Seeing what a node did meant ssh through a jump host, to a machine whose address nobody remembers, to read a journal only root may open. When an engine install failed on a new node today, the reason was one line — and it was four steps away from the page that said the install had failed. Each node's row on the cluster page now links to its logs: the agent's own, and every engine running there, chosen from the list the node itself sends. The page can follow, refreshing every five seconds, and is on both the admin listener and /admin. `llmgw ctl logs NODE [--source SHARD] [-n N]` reads the same. They travel over the stream the agent already holds, so they need nothing the control plane does not already have: a request goes down, the lines come back, and a reply that does not come in ten seconds is an agent too old to answer. The agent keeps its last 2000 lines in memory as well as writing them wherever it did before; the engines' last few hundred lines were already kept and sent only when one crashed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
32 lines
1.6 KiB
HTML
32 lines
1.6 KiB
HTML
{{define "node_logs"}}<!doctype html>
|
|
<html lang="en"><head>
|
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
{{if .Follow}}<meta http-equiv="refresh" content="5">{{end}}
|
|
<title>llmgw — {{.Node}} logs</title><link rel="stylesheet" href="/_static/base.css">
|
|
</head><body><div class="wrap">
|
|
<header>
|
|
<h1>{{.Node}}</h1>
|
|
<p class="sub">{{if eq .Source "agent"}}the agent's log{{else}}output of engine <code>{{.Source}}</code>{{end}} · last {{.Count}} lines</p>
|
|
<nav><a href="{{.Back}}">cluster</a></nav>
|
|
</header>
|
|
|
|
<p>
|
|
{{- $d := . -}}
|
|
{{range .Sources}}<a href="{{$d.Base}}?source={{.}}&lines={{$d.Count}}{{if $d.Follow}}&follow=1{{end}}"{{if eq . $d.Source}} aria-current="page"><strong>{{.}}</strong>{{else}}>{{.}}{{end}}</a> {{end}}
|
|
</p>
|
|
<p class="note">
|
|
{{range .Counts}}<a href="{{$d.Base}}?source={{$d.Source}}&lines={{.}}{{if $d.Follow}}&follow=1{{end}}">{{.}}</a> {{end}}lines ·
|
|
{{if .Follow}}<a href="{{.Base}}?source={{.Source}}&lines={{.Count}}">stop following</a>{{else}}<a href="{{.Base}}?source={{.Source}}&lines={{.Count}}&follow=1">follow</a> (refresh every 5s){{end}}
|
|
</p>
|
|
|
|
{{if .Error}}<p class="bad">{{.Error}}</p>{{end}}
|
|
{{if .Lines}}<pre id="log">{{range .Lines}}{{.}}
|
|
{{end}}</pre>
|
|
{{/* Newest at the bottom, like a terminal, and scrolled there: the line
|
|
worth reading is almost always the last one. */}}
|
|
<script>window.scrollTo(0, document.body.scrollHeight);</script>
|
|
{{else if not .Error}}<p class="empty">Nothing logged yet.</p>{{end}}
|
|
|
|
<footer class="note">llmgw {{.Version}} · {{.Now}}</footer>
|
|
</div></body></html>{{end}}
|