diff --git a/README.md b/README.md index fd3674e..5f21082 100644 --- a/README.md +++ b/README.md @@ -423,5 +423,6 @@ If pages are missing publicly: `sudo /home/hernani/koopa-caddy/apply-monitoring- ## Version on monitoring pages (v1.3+ / sticky bar) -The sticky bar shows the suite **tag** (e.g. `v1.4.1`) and links to that tag on Forgejo. -Planned **v1.4.0**: fuller L10n (fr-CH for FrancPaysan, de-CH for hacktivism/Taler CH). +The sticky bar shows the suite **tag** (e.g. `v1.11.0`) and links to that tag on Forgejo. + +**v1.11.0:** Click the sticky **error** or **warning** count to filter the console log to only those lines (other log lines hide; sticky bar, stats, and top overviews stay). Same via `#filter-error` / `#filter-warn` (or `#first-error` / `#first-warn`). Click again or **Show all** to clear. diff --git a/VERSION b/VERSION index d90bb28..1cac385 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.11 +1.11.0 diff --git a/VERSIONS.md b/VERSIONS.md index 5140f11..9ee308c 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -17,6 +17,7 @@ Git tags: `vMAJOR.FEATURE.FIX` (e.g. `v1.8.0`). File `VERSION` omits the `v` pre | Tag | Date (UTC) | Notes | |-----|------------|--------| +| **v1.11.0** | 2026-07-19 | **Feature:** sticky **error/warn filter** — click counts to show only error or only warn log lines; sticky bar + overviews stay; `#filter-error` / `#filter-warn` (+ `#first-*` still works). | | **v1.10.11** | 2026-07-19 | **Bugfix:** surface/aptdeploy wrappers **force** MON_HOSTS+PHASES+MONPAGES_INVENTORY (env cannot expand job to bank/exchange); wrap more mon knobs. | | **v1.10.10** | 2026-07-19 | **Bugfix:** monpages bare code 21 is WARN again by default (slash form remains ERROR); bare redir still needs live Caddy `redir *` — set MONPAGES_BARE_STRICT=1 to enforce. | | **v1.10.9** | 2026-07-19 | **Bugfix:** stats policy INFO no longer says bare “ERROR” (false #first-error on www.stats-01); extract_errors only from `┌ ERROR` badges. | diff --git a/site-gen/caddy-monitoring-handles.snippet b/site-gen/caddy-monitoring-handles.snippet index f0b1a3a..47b6725 100644 --- a/site-gen/caddy-monitoring-handles.snippet +++ b/site-gen/caddy-monitoring-handles.snippet @@ -1,23 +1,27 @@ # Host Caddy (root service). Place BEFORE catch-all reverse_proxy in each site block. # -# CRITICAL (v1.7.2): root must be the *host directory* (…/monitoring-sites/{host}), -# and the matcher must be a path *prefix* (`/monitoring*`), so that URI -# /monitoring/index.html maps to {root}/monitoring/index.html. +# CRITICAL: bare paths (no trailing slash) must redirect to slash, or the request +# falls through to merchant/bank/exchange API → Taler JSON code 21. # -# WRONG (causes empty HTTP 404 from Caddy file_server): -# handle /monitoring/ { -# root * …/monitoring-sites/{host}/monitoring -# file_server -# } -# → looks for …/monitoring/monitoring/index.html +# CORRECT (site-level named matcher — preferred): +# @mon_bare path /monitoring /monitoring_err \ +# /taler-monitoring-surface /taler-monitoring-surface_err \ +# /taler-monitoring-aptdeploy /taler-monitoring-aptdeploy_err +# redir @mon_bare {path}/ 302 # -# CRITICAL (v1.9.2): bare-path redir inside handle MUST use matcher `*`: +# ALSO OK inside handle (matcher must be `*`): # handle /taler-monitoring-surface { # redir * /taler-monitoring-surface/ 302 # } -# WRONG: `redir /taler-monitoring-surface/ 302` is parsed as -# matcher=/taler-monitoring-surface/ to="302" → Location: 302, merchant code 21 -# (same footgun for /monitoring, aptdeploy, mail, mattermost bare paths). +# +# WRONG (Caddy footgun — causes merchant code 21 on bare URLs): +# redir /taler-monitoring-surface/ 302 +# → parsed as matcher=/taler-monitoring-surface/ to="302" +# → Location: 302, or no-op then fallthrough to reverse_proxy +# +# root must be the *host directory* (…/monitoring-sites/{host}), and the +# file_server matcher a path *prefix* (`/monitoring*`), so +# /monitoring/index.html maps to {root}/monitoring/index.html. # # Disk layout: # /var/www/monitoring-sites/{host}/monitoring/index.html @@ -25,49 +29,44 @@ # # Live apply on koopa (absolute path — ~ as root is /root): # sudo /home/hernani/koopa-caddy/apply-monitoring-live.sh +# Runtime-only (no sudo; hernani admin API): +# curl -g -X POST http://[::1]:2019/load -H 'Content-Type: text/caddyfile' \ +# --data-binary @/home/hernani/koopa-caddy/Caddyfile # --- only inside taler.hacktivism.ch { ... } --- - handle /taler-monitoring-surface { - redir * /taler-monitoring-surface/ 302 + @mon_bare path /monitoring /monitoring_err \ + /taler-monitoring-surface /taler-monitoring-surface_err \ + /taler-monitoring-aptdeploy /taler-monitoring-aptdeploy_err \ + /taler-monitoring-mail /taler-monitoring-mail_err \ + /taler-monitoring-mattermost /taler-monitoring-mattermost_err + redir @mon_bare {path}/ 302 + + handle /taler-monitoring-surface_err* { + root * /var/www/monitoring-sites/taler.hacktivism.ch + file_server } handle /taler-monitoring-surface* { root * /var/www/monitoring-sites/taler.hacktivism.ch file_server } - handle /taler-monitoring-surface_err { - redir * /taler-monitoring-surface_err/ 302 - } - handle /taler-monitoring-surface_err* { + handle /taler-monitoring-aptdeploy_err* { root * /var/www/monitoring-sites/taler.hacktivism.ch file_server } - handle /taler-monitoring-aptdeploy { - redir * /taler-monitoring-aptdeploy/ 302 - } handle /taler-monitoring-aptdeploy* { root * /var/www/monitoring-sites/taler.hacktivism.ch file_server } - handle /taler-monitoring-aptdeploy_err { - redir * /taler-monitoring-aptdeploy_err/ 302 - } - handle /taler-monitoring-aptdeploy_err* { - root * /var/www/monitoring-sites/taler.hacktivism.ch - file_server - } # --- bank + exchange + taler (each site block; set root host dir) --- - handle /monitoring { - redir * /monitoring/ 302 + @mon_bare path /monitoring /monitoring_err + redir @mon_bare {path}/ 302 + + handle /monitoring_err* { + root * /var/www/monitoring-sites/{host} + file_server } handle /monitoring* { root * /var/www/monitoring-sites/{host} file_server } - handle /monitoring_err { - redir * /monitoring_err/ 302 - } - handle /monitoring_err* { - root * /var/www/monitoring-sites/{host} - file_server - } diff --git a/site-gen/console_to_html.py b/site-gen/console_to_html.py index ba936ca..3428b34 100755 --- a/site-gen/console_to_html.py +++ b/site-gen/console_to_html.py @@ -31,6 +31,12 @@ def ui(lang: str, key: str, **kwargs) -> str: "warn_many": "{n} warnings", "jump_first_error": "Jump to first error", "jump_first_warn": "Jump to first warning", + "filter_errors": "Filter: show all errors (hide other log lines)", + "filter_warns": "Filter: show all warnings (hide other log lines)", + "filter_clear": "Clear filter · show all lines", + "filter_active_err": "Filter: errors only", + "filter_active_warn": "Filter: warnings only", + "filter_show_all": "Show all", "generated": "generated", "version": "version", @@ -94,7 +100,7 @@ def ui(lang: str, key: str, **kwargs) -> str: "mail_i1": "Outside-in phase mail: MX, SMTP/IMAP ports and handshakes, SPF/DMARC", "mail_i2": "Mail hosts: firefly.gnunet.org (taler.net/gnunet.org) and anastasis.taler-systems.com", "mail_i3": "Reported on taler-monitoring-surface HTML (no separate /taler-monitoring-mail* page)", - "footer": "Console-style render of taler-monitoring output. Sticky bar: green = clean · yellow = warnings · red = errors. Commit pins the exact tree used for this run.", + "footer": "Console-style render of taler-monitoring output. Sticky bar: green = clean · yellow = warnings · red = errors. Click error/warning counts to filter the log (other lines hidden; sticky + overviews stay). Commit pins the exact tree used for this run.", "redirect_fail": "has failures.", "redirect_see": "See {link} for the full console log, error index, and sticky status bar.", "ago_s": "{n}s ago", @@ -113,6 +119,12 @@ def ui(lang: str, key: str, **kwargs) -> str: "warn_many": "{n} avertissements", "jump_first_error": "Aller à la première erreur", "jump_first_warn": "Aller au premier avertissement", + "filter_errors": "Filtrer : toutes les erreurs (masquer le reste du journal)", + "filter_warns": "Filtrer : tous les avertissements (masquer le reste du journal)", + "filter_clear": "Effacer le filtre · tout afficher", + "filter_active_err": "Filtre : erreurs seulement", + "filter_active_warn": "Filtre : avertissements seulement", + "filter_show_all": "Tout afficher", "generated": "généré", "version": "version", @@ -176,7 +188,7 @@ def ui(lang: str, key: str, **kwargs) -> str: "mail_i1": "Phase outside-in mail : MX, ports SMTP/IMAP et handshakes, SPF/DMARC", "mail_i2": "Hôtes mail : firefly.gnunet.org (taler.net/gnunet.org) et anastasis.taler-systems.com", "mail_i3": "Rapporté dans le HTML taler-monitoring-surface (pas de page /taler-monitoring-mail*)", -"footer": "Rendu console de taler-monitoring. Barre collante : vert = OK · jaune = avertissements · rouge = erreurs. Le commit fixe l'arbre exact de cette exécution.", + "footer": "Rendu console de taler-monitoring. Barre collante : vert = OK · jaune = avertissements · rouge = erreurs. Cliquer sur les compteurs erreur/avertissement filtre le journal (le reste est masqué ; barre et vues d'ensemble restent). Le commit fixe l'arbre exact de cette exécution.", "redirect_fail": "a des échecs.", "redirect_see": "Voir {link} pour le journal console complet, l'index d'erreurs et la barre de statut.", "ago_s": "il y a {n}s", @@ -701,26 +713,50 @@ def sticky_bar_html( else: status_txt = ui(lang, "ok") - if first_err_href and n_err: + # Click error/warn stats → filter console to matching lines only (v1.11.0). + # Hash #filter-error / #filter-warn; #first-error / #first-warn also activate filter. + if n_err: err_lbl = ui(lang, "error_one", n=n_err) if n_err == 1 else ui(lang, "error_many", n=n_err) + err_href = first_err_href or "#filter-error" + # Prefer filter hash; keep first-error as secondary scroll target via JS err_stat = ( - f'{html.escape(err_lbl)}' + f'{html.escape(err_lbl)}' ) else: err_lbl = ui(lang, "error_many", n=n_err) err_stat = f'{html.escape(err_lbl)}' - if first_warn_href and n_warn: + if n_warn: warn_lbl = ui(lang, "warn_one", n=n_warn) if n_warn == 1 else ui(lang, "warn_many", n=n_warn) + warn_href = first_warn_href or "#filter-warn" warn_stat = ( - f'{html.escape(warn_lbl)}' + f'{html.escape(warn_lbl)}' ) else: warn_lbl = ui(lang, "warn_many", n=n_warn) warn_stat = f'{html.escape(warn_lbl)}' + filter_chip = ( + f'' + f'' + f'' + f"" + ) + # data attributes for JS i18n + filter_i18n = ( + f'data-i18n-filter-err="{html.escape(ui(lang, "filter_active_err"))}" ' + f'data-i18n-filter-warn="{html.escape(ui(lang, "filter_active_warn"))}" ' + f'data-i18n-filter-clear="{html.escape(ui(lang, "filter_clear"))}"' + ) + other = "" if link_other: other = ( @@ -758,7 +794,7 @@ def sticky_bar_html( return f"""