From a5b74facc051bf26b23244aabc84516f6c187038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric?= Date: Mon, 5 Oct 2026 12:50:11 +0200 Subject: [PATCH] Source badge at the start of every log line Each row now starts with a fixed-width badge naming its source, one color per source: SYSLOG, DOCKER, KERNEL (dmesg), HOST (/var/log), AUDIT, FILE and LS. The AUDIT/FILE/LS badges move there from before the app name; those sources keep their colored edge and tint. Co-Authored-By: Claude Opus 5.5 (1M context) --- README.fr.md | 8 ++++++-- README.md | 7 +++++-- web/app.js | 23 +++++++++++++---------- web/index.html | 1 + web/style.css | 43 +++++++++++++++++++++++++++++++------------ 5 files changed, 56 insertions(+), 26 deletions(-) diff --git a/README.fr.md b/README.fr.md index acf4f24..72dbb84 100644 --- a/README.fr.md +++ b/README.fr.md @@ -92,6 +92,10 @@ une base propre. Les badges de sévérité `err`/`crit` et `warning` reprennent les couleurs des tags `error` et `warning`. +Chaque ligne commence par un badge de largeur fixe qui indique sa source, avec une couleur par +source : **SYSLOG**, **DOCKER**, **KERNEL** (dmesg), **HOST** (fichiers de `/var/log`), **AUDIT**, +**FILE** et **LS** (logs de LogStream lui-même). + Raccourcis : `/` place le curseur dans la recherche, `Esc` la vide. Un clic sur une ligne affiche tous ses champs. @@ -278,7 +282,7 @@ source est **désactivée par défaut** : activez-la dans **Réglages > Sources ne peut pas être résolu), `exe`, `res` (`success` / `failed`, d'après `res=` ou `success=`) et `key` (clé de la règle). La sévérité est `warning` en cas d'échec, `info` sinon ; facility `authpriv` ; source `audit`. Dans la liste, les lignes d'audit ont un liseré gauche violet, - un fond légèrement teinté et un badge **AUDIT** devant l'app ; le filtre **Source** permet de + un fond légèrement teinté et le badge de source **AUDIT** ; le filtre **Source** permet de les afficher seules. - **Noms** : `user` vient du format enrichi (`log_format = ENRICHED`, le défaut des versions récentes d'auditd), sinon du `/etc/passwd` de l'hôte s'il est monté en `/host/etc/passwd`. @@ -338,7 +342,7 @@ conteneur, un **format** (*Automatique* par défaut), un **hôte** facultatif (p qui portent le nom d'un champ de LogStream (`host`, `app`…) sont renommés `field_host`, `field_app`… - **Affichage** : source `file`, le chemin dans `log_file`. Dans la liste, ces lignes ont un - liseré gauche vert, une légère teinte et un badge **FILE** avant l'app ; le filtre **Source** + liseré gauche vert, une légère teinte et le badge de source **FILE** ; le filtre **Source** les affiche seules. - À l'activation d'un fichier, les lignes de la dernière heure déjà présentes sont lues d'abord (`FILES_BACKFILL`, `0` = seulement les nouvelles lignes ; les lignes sans horodatage sont alors diff --git a/README.md b/README.md index 4402c18..8788f67 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,9 @@ versions before this change are indexed by their message timestamp; purge them f Settings to start clean. Severity badges `err`/`crit` and `warning` use the colors of the `error` and `warning` tags. +Each row starts with a fixed-width badge naming its source, one color per source: **SYSLOG**, +**DOCKER**, **KERNEL** (dmesg), **HOST** (files of `/var/log`), **AUDIT**, **FILE** and **LS** +(LogStream's own logs). Shortcuts: `/` focuses the search box, `Esc` clears it. Clicking a row shows all its fields. @@ -254,7 +257,7 @@ also be changed (saved in `/data/audit.json`; `AUDIT_LOG` sets the default path) `auid` (login user ID), `user` (its name, or the uid when it cannot be resolved), `exe`, `res` (`success` / `failed`, from `res=` or `success=`) and `key` (rule key). Severity is `warning` when the result is a failure, `info` otherwise; facility `authpriv`; source `audit`. In the - list, audit lines have a violet left edge, a light tint and an **AUDIT** badge before the app; + list, audit lines have a violet left edge, a light tint and the **AUDIT** source badge; the **Source** filter shows them alone. - **Names**: `user` comes from the enriched format (`log_format = ENRICHED`, the default of recent auditd versions), else from the host's `/etc/passwd` when it is mounted as @@ -310,7 +313,7 @@ optional **host** (default: `/host/etc/hostname`, else `localhost`) and a switch not fit the chosen format is kept as plain text. Fields named like LogStream's own ones (`host`, `app`…) are renamed `field_host`, `field_app`… - **Display**: source `file`, the path in `log_file`. In the list these lines have a green left - edge, a light tint and a **FILE** badge before the app; the **Source** filter shows them alone. + edge, a light tint and the **FILE** source badge; the **Source** filter shows them alone. - When a file is turned on, the lines of the last hour already in it are read first (`FILES_BACKFILL`, `0` = only new lines; lines without a timestamp are then left out). The start of that hour is found by bisection on the dates of the lines, so a large file that holds diff --git a/web/app.js b/web/app.js index f25a815..abce485 100644 --- a/web/app.js +++ b/web/app.js @@ -109,7 +109,7 @@ const I18N = { file_not_found: 'No file at this path: mount it in the container (see docker-compose.yml) and check the path.', file_permission: 'Permission denied: the file must be readable by UID 10001 or the adm group (see the README). ', file_read: 'Cannot read the file: ', - filesHelp: 'Follows the log file of another program, mounted read-only in the container (e.g. /var/log/traefik:/logs/traefik:ro, then /logs/traefik/access.log here). Once the path is filled in, the file is checked and its format detected from its last lines (JSON lines, logfmt, access logs of nginx, Apache or Traefik, else plain text); choose a format to force it, or a regular expression whose named groups time, level, msg, host and app fill these fields, the other groups giving extra fields. Each line gives an entry (badge FILE, app = the name); indented lines are added to the previous entry; for access logs 5xx are errors and 4xx warnings. When turned on, the last hour of dated lines is read first (FILES_BACKFILL); rotations are followed and reading resumes where it stopped.', + filesHelp: 'Follows the log file of another program, mounted read-only in the container (e.g. /var/log/traefik:/logs/traefik:ro, then /logs/traefik/access.log here). Once the path is filled in, the file is checked and its format detected from its last lines (JSON lines, logfmt, access logs of nginx, Apache or Traefik, else plain text); choose a format to force it, or a regular expression whose named groups time, level, msg, host and app fill these fields, the other groups giving extra fields. Each line gives an entry (badge FILE at the start of the line, app = the name); indented lines are added to the previous entry; for access logs 5xx are errors and 4xx warnings. When turned on, the last hour of dated lines is read first (FILES_BACKFILL); rotations are followed and reading resumes where it stopped.', auditTitle: 'Linux audit (auditd)', auditEnabled: 'Collect the audit events of this machine', auditPath: 'File', @@ -228,7 +228,7 @@ const I18N = { hCappedTitle: 'The chosen division would exceed 300 intervals over this range: it has been enlarged.', hUnzoom: '× Back to stream', unitDay: 'd', toTop: 'Back to top', - colRcv: 'Received', colMt: 'Message time', colSev: 'Severity', colHost: 'Host', colApp: 'App', colCodes: 'Pattern', colMsg: 'Message', + colSrc: 'Source', colRcv: 'Received', colMt: 'Message time', colSev: 'Severity', colHost: 'Host', colApp: 'App', colCodes: 'Pattern', colMsg: 'Message', codesTitle: 'Codes of the color tags found in the message', tagCodeTitle: 'Code shown on the log lines this tag matches', colGrip: 'Drag to resize, double-click for the automatic width', @@ -341,7 +341,7 @@ const I18N = { file_not_found: 'Aucun fichier à ce chemin : montez-le dans le conteneur (voir docker-compose.yml) et vérifiez le chemin.', file_permission: 'Accès refusé : le fichier doit être lisible par l\'UID 10001 ou le groupe adm (voir le README). ', file_read: 'Lecture du fichier impossible : ', - filesHelp: 'Suit le fichier de logs d\'un autre programme, monté en lecture seule dans le conteneur (par ex. /var/log/traefik:/logs/traefik:ro, puis /logs/traefik/access.log ici). Une fois le chemin saisi, le fichier est vérifié et son format détecté à partir de ses dernières lignes (JSON lines, logfmt, journaux d\'accès de nginx, Apache ou Traefik, sinon texte brut) ; choisissez un format pour le forcer, ou une expression régulière dont les groupes nommés time, level, msg, host et app remplissent ces champs, les autres groupes donnant des champs supplémentaires. Chaque ligne donne une entrée (badge FILE, app = le nom) ; les lignes indentées sont rattachées à l\'entrée précédente ; pour les journaux d\'accès, 5xx en erreur et 4xx en warning. À l\'activation, la dernière heure de lignes datées est lue d\'abord (FILES_BACKFILL) ; les rotations sont suivies et la lecture reprend où elle s\'était arrêtée.', + filesHelp: 'Suit le fichier de logs d\'un autre programme, monté en lecture seule dans le conteneur (par ex. /var/log/traefik:/logs/traefik:ro, puis /logs/traefik/access.log ici). Une fois le chemin saisi, le fichier est vérifié et son format détecté à partir de ses dernières lignes (JSON lines, logfmt, journaux d\'accès de nginx, Apache ou Traefik, sinon texte brut) ; choisissez un format pour le forcer, ou une expression régulière dont les groupes nommés time, level, msg, host et app remplissent ces champs, les autres groupes donnant des champs supplémentaires. Chaque ligne donne une entrée (badge FILE en début de ligne, app = le nom) ; les lignes indentées sont rattachées à l\'entrée précédente ; pour les journaux d\'accès, 5xx en erreur et 4xx en warning. À l\'activation, la dernière heure de lignes datées est lue d\'abord (FILES_BACKFILL) ; les rotations sont suivies et la lecture reprend où elle s\'était arrêtée.', auditTitle: 'Audit Linux (auditd)', auditEnabled: 'Collecter les événements d\'audit de cette machine', auditPath: 'Fichier', @@ -460,7 +460,7 @@ const I18N = { hCappedTitle: 'La division choisie dépasserait 300 intervalles sur cette plage : elle a été élargie.', hUnzoom: '× Revenir au flux', unitDay: 'j', toTop: 'Revenir en haut', - colRcv: 'Réception', colMt: 'Heure message', colSev: 'Sévérité', colHost: 'Hôte', colApp: 'App', colCodes: 'Motif de recherche', colMsg: 'Message', + colSrc: 'Source', colRcv: 'Réception', colMt: 'Heure message', colSev: 'Sévérité', colHost: 'Hôte', colApp: 'App', colCodes: 'Motif de recherche', colMsg: 'Message', codesTitle: 'Codes des tags de couleur trouvés dans le message', tagCodeTitle: 'Code affiché sur les lignes de log où ce tag est trouvé', colGrip: 'Glisser pour redimensionner, double-clic pour la largeur automatique', @@ -985,15 +985,18 @@ function fmtTime(s) { return `${day} ${p.h}:${p.m}:${p.s}.${p.ms}`; } -// Sources with their own look in the list: a colored edge and a badge -// before the app name (the severity badge stays the same). -const SRC_BADGE = { audit: 'AUDIT', logstream: 'LS', file: 'FILE' }; +// Every row starts with a badge naming its source, one color per source +// (--src- in style.css). Audit events, log files and LogStream's own +// logs also get a colored edge and a light tint (the severity badge stays the same). +const SRC_BADGE = { syslog: 'SYSLOG', docker: 'DOCKER', kernel: 'KERNEL', host: 'HOST', audit: 'AUDIT', file: 'FILE', logstream: 'LS' }; +const srcOf = (r) => (SRC_BADGE[r.source_type] ? r.source_type : 'syslog'); // older entries have no source_type function rowHTML(r, isNew) { const sev = r.severity || ''; const cls = SEV_CLASS[sev] || 'info'; - const badge = SRC_BADGE[r.source_type]; - return `
` + const src = srcOf(r); + return `
` + + `${SRC_BADGE[src]}` + `` + `` + `${esc(sev || '—')}` @@ -1001,7 +1004,7 @@ function rowHTML(r, isNew) { ? `${esc(r.host_name || r.host)}` : '') + (r.app - ? `${r.source_type === 'docker' ? DOCKER_ICON : ''}${badge ? `${badge}` : ''}${esc(r.app)}` + ? `${r.source_type === 'docker' ? DOCKER_ICON : ''}${esc(r.app)}` : '') + `${codesHTML(r._msg)}` + `
${msgHTML(r)}
` diff --git a/web/index.html b/web/index.html index ba8d302..d6a765b 100644 --- a/web/index.html +++ b/web/index.html @@ -140,6 +140,7 @@