version 2 chatgpt

This commit is contained in:
2025-09-07 08:18:31 +02:00
parent 0a79e491f3
commit 79b1db5180
2 changed files with 58 additions and 9 deletions

View File

@@ -2,6 +2,7 @@ package pmolog
import (
"container/ring"
"context"
"encoding/json"
"fmt"
"net/http"
@@ -103,7 +104,7 @@ func sseHandler(w http.ResponseWriter, r *http.Request) {
}
}
// ---------- HTML ----------
// ---------- HTML Dashboard ----------
var indexHTML = `<!DOCTYPE html>
<html>
@@ -112,31 +113,54 @@ var indexHTML = `<!DOCTYPE html>
<title>🚀 Real-Time Logs</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
<style>
body { background:#0d1117; color:#e6edf3; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,sans-serif; margin:0; padding:20px; }
h1 { color:#58a6ff; border-bottom:1px solid #30363d; padding-bottom:10px; }
#logs { height:70vh; overflow-y:auto; background:#161b22; border:1px solid #30363d; border-radius:8px; padding:15px; }
body { background:#0d1117; color:#e6edf3; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,sans-serif; margin:0; }
header { display:flex; align-items:center; justify-content:space-between; padding:10px 20px; background:#161b22; border-bottom:1px solid #30363d; }
h1 { margin:0; font-size:20px; color:#58a6ff; }
#controls { display:flex; gap:15px; align-items:center; }
#logs { height:75vh; overflow-y:auto; background:#161b22; border:1px solid #30363d; border-radius:8px; padding:15px; margin:15px; }
.log { margin:6px 0; padding:6px 10px; border-left:4px solid; border-radius:6px; }
.log.error { border-color:#f85149; background:rgba(248,81,73,0.1); }
.log.warning { border-color:#d29922; background:rgba(210,153,34,0.1); }
.log.info { border-color:#58a6ff; background:rgba(56,139,253,0.1); }
.log.debug { border-color:#8957e5; background:rgba(137,87,229,0.1); }
.time { color:#7d8590; font-size:12px; margin-right:10px; }
input[type="checkbox"] { margin-right:4px; }
#search { padding:4px 8px; border-radius:4px; border:none; }
button { background:#238636; color:white; border:none; padding:6px 12px; border-radius:4px; cursor:pointer; }
button:hover { background:#2ea043; }
</style>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
</head>
<body>
<h1>📝 Logs en temps réel</h1>
<header>
<h1>📝 Logs en temps réel</h1>
<div id="controls">
<label><input type="checkbox" value="error" checked>❌ Error</label>
<label><input type="checkbox" value="warning" checked>⚠️ Warning</label>
<label><input type="checkbox" value="info" checked> Info</label>
<label><input type="checkbox" value="debug" checked>🐛 Debug</label>
<input id="search" type="text" placeholder="Search...">
<label><input type="checkbox" id="autoscroll" checked> Auto-scroll</label>
<button id="clear">Clear</button>
</div>
</header>
<div id="logs"></div>
<script>
const logs=document.getElementById('logs');
const es=new EventSource('/log-sse');
const maxLogs=500;
const filters={error:true,warning:true,info:true,debug:true};
let searchTerm="";
let autoScroll=true;
marked.setOptions({ breaks:true, highlight: (code,lang)=>hljs.highlightAuto(code).value });
es.addEventListener('message', e=>{
const d=JSON.parse(e.data);
if(!filters[d.level]) return;
if(searchTerm && !d.content.toLowerCase().includes(searchTerm)) return;
const line=document.createElement('div');
line.className='log '+d.level;
@@ -151,9 +175,19 @@ var indexHTML = `<!DOCTYPE html>
logs.appendChild(line);
if(logs.children.length>maxLogs) logs.removeChild(logs.firstChild);
logs.scrollTop=logs.scrollHeight;
if(autoScroll) logs.scrollTop=logs.scrollHeight;
});
// controls
document.querySelectorAll('input[type=checkbox][value]').forEach(cb=>{
cb.addEventListener('change',()=>{ filters[cb.value]=cb.checked; });
});
document.getElementById('search').addEventListener('input',e=>{
searchTerm=e.target.value.toLowerCase();
});
document.getElementById('clear').addEventListener('click',()=>{ logs.innerHTML=""; });
document.getElementById('autoscroll').addEventListener('change',e=>{ autoScroll=e.target.checked; });
es.onerror=e=>console.error("SSE error",e);
</script>
</body>
@@ -166,10 +200,25 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, indexHTML)
}
func LoggerWeb(mux *http.ServeMux) {
// LoggerWeb installe les routes et arrête le broker quand ctx est annulé.
func LoggerWeb(ctx context.Context, mux *http.ServeMux) {
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true, FullTimestamp: true})
logrus.AddHook(SSELogHook{})
mux.HandleFunc("/log", indexHandler)
mux.HandleFunc("/log-sse", sseHandler)
// goroutine d'arrêt
go func() {
<-ctx.Done()
broker.mu.Lock()
for ch := range broker.clients {
close(ch)
delete(broker.clients, ch)
}
broker.mu.Unlock()
logrus.Info("Web logger stopped")
}()
logrus.Info("Web logger connected")
}

View File

@@ -78,8 +78,6 @@ func (s *Server) Start() error {
s.mu.RLock()
pmolog.LoggerWeb(mux)
mux.HandleFunc("/", s.ServeDebugIndex)
s.httpSrv = &http.Server{
@@ -125,6 +123,8 @@ func (s *Server) Run(ctx context.Context) error {
return fmt.Errorf("❌ failed to start server: %w", err)
}
pmolog.LoggerWeb(ctx, s.httpSrv.Handler.(*http.ServeMux))
s.sspd = ssdp.NewSSDPServer()
if err := s.sspd.Start(ctx); err != nil {
return fmt.Errorf("❌ failed to start SSDP server: %w", err)