Log files: one file per entry, format detection

- a path is one file (wildcards refused for now); the name defaults to
  the file name
- format "auto" (the default): detected from the last 50 lines of the
  file, the structured format followed by at least 80 % of them (Traefik
  access JSON, JSON lines, CLF, logfmt), else plain text; done again when
  the format changes, shown in the status ("Format detected: …"); any
  other format forces it
- POST /api/files/detect {path}: found / permission / empty, detected
  format and last line, shown under the row as soon as the path is typed
  (POST so that read-only accounts cannot read files through it)
- README (EN/FR) updated

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
cedricandClaude Opus 5.5 committed 2026-10-05 10:33:26 +02:00
1 parent 087d9e7b30
commit dcb09e619e
8 files changed
+488 -284

No files matched your search

+16 -1
View File
@@ -59,6 +59,7 @@ func (a *API) Routes(mux *http.ServeMux) {
mux.HandleFunc("PUT /api/audit", a.auditConfigure)
mux.HandleFunc("GET /api/files", a.filesStatus)
mux.HandleFunc("PUT /api/files", a.filesConfigure)
mux.HandleFunc("POST /api/files/detect", a.filesDetect)
mux.HandleFunc("GET /api/selflog", a.selfLogStatus)
mux.HandleFunc("PUT /api/selflog", a.selfLogConfigure)
}
@@ -88,7 +89,7 @@ func (a *API) filesStatus(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, a.files.Status())
}
// PUT /api/files {"sources": [{"id", "name", "path", "format", "regex", "host", "enabled"}]}
// PUT /api/files {"sources": [{"id", "name", "path", "format" (auto or a format), "regex", "host", "enabled"}]}
// (no id: a new file).
func (a *API) filesConfigure(w http.ResponseWriter, r *http.Request) {
var cfg filesConfig
@@ -104,6 +105,20 @@ func (a *API) filesConfigure(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, a.files.Status())
}
// POST /api/files/detect {"path": "/logs/traefik/access.log"}: whether the file
// can be read, its detected format and its last line (Settings > Sources). A
// POST, so that read-only accounts cannot read files through it.
func (a *API) filesDetect(w http.ResponseWriter, r *http.Request) {
var req struct {
Path string `json:"path"`
}
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 4096)).Decode(&req); err != nil {
writeErr(w, http.StatusBadRequest, err)
return
}
writeJSON(w, http.StatusOK, DetectFile(req.Path))
}
// GET /api/selflog: state of the LogStream internal logs (Settings > Sources).
func (a *API) selfLogStatus(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, a.selfLog.Status())