diff --git a/webapp/src/components/Docs.tsx b/webapp/src/components/Docs.tsx index 656a250..c12b610 100644 --- a/webapp/src/components/Docs.tsx +++ b/webapp/src/components/Docs.tsx @@ -62,6 +62,14 @@ const SECTIONS: DocSection[] = [ copy of the active one, and its "×" button deletes the active profile. Switching profiles hot-swaps the running engine's declared params/metrics immediately, with no restart.
+Worked example
+
+ Piping a webserver's access log — {'tail -f access.log | ottyl'} — into a profile named{' '}
+ webserver: create the profile from the settings menu, declare params/metrics against it (see
+ the Parameters, Metrics, and Dashboards sections below), then next time you run
+ the same command, switch to webserver and everything you declared is already there —
+ no re-declaring params or rebuilding dashboards.
+
The filter string is evaluated on the server. A parse error shows as inline text under the filter bar.
+Worked examples
+{'regex("timeout") and timestamp>-15m'}
+ requests metric has a value-role{' '}
+ duration param declared: {'requests[duration]>200'}
+ requests metric with a path label param —
+ note that [param] comparisons only work against a declared metric's labels, not a
+ bare param declared on its own, and values are unquoted (no surrounding "..."):{' '}
+ {'requests[path]==/checkout and regex("5[0-9]{2}")'}
+ {'timestamp<2024-06-15T12:00:00Z'}
+ requests[duration]>100), declare it as a param on a metric instead — see the Metrics
section below.
+ Worked example
+
+ Given lines like {'request path=/checkout method=GET duration=182'}, declaring a param named{' '}
+ duration with regex {String.raw`duration=(?P, capture group{' '}
+ duration, and type number makes duration show up as a column in the
+ log table for every line that matched, and comparable in the filter bar once it's also declared as part of
+ a metric (see Filtering above — bare params aren't queryable by name on their own, only metric
+ labels/values are).
+
Worked example
+
+ To count requests per path and track their latency from lines like{' '}
+ {'request path=/checkout method=GET duration=182'}, declare a metric named{' '}
+ requests with message-match regex{' '}
+ {String.raw`request path=(?P{' '}
+ and two params: path (capture group path, kind string, role{' '}
+ label) and duration (capture group duration, kind{' '}
+ number, role value — at most one param can be value). Selecting{' '}
+ requests in the panel then shows one row per distinct path with its occurrence
+ count and a trend sparkline. The same declaration also unlocks{' '}
+ {'histogram(requests[50])'} (duration distribution in 50ms-wide buckets) and{' '}
+ gauge(requests) (each path's most recent duration) as dashboard panel queries.
+
+ A param of kind duration marked value is a special case: rather than parsing the
+ capture group as a number, its value is derived automatically as the elapsed time since the previous
+ matching event with the same labels — useful for measuring the gap between repeated events (e.g. time
+ between retries) without the log line itself reporting a duration.
+
https://ntfy.sh). Configure the sink and send a test notification from the Settings
panel — the Alerts panel only defines rule conditions.
+ Worked example: build a "requests" dashboard
+
+ Assuming a requests metric declared as in the Metrics example above (a path{' '}
+ label and a duration value param), a useful dashboard is three panels:
+
requests — one line per path,
+ showing every request occurrence over time.
+ gauge(requests) — each path's
+ most recent request duration side by side, a quick "who's slow right now" snapshot.
+ {'requests{path="/checkout"}'}{' '}
+ — label matchers filter a query down to one series; here, just the checkout path's share of its own
+ occurrences over the range (mostly useful once more matchers are added to compare paths against each
+ other).
+
+ Other query shapes worth knowing: {'sum(requests)'} collapses every path into one combined
+ count-over-time series, and {'rate(requests[5m])'} gives each path's occurrences-per-second
+ over a trailing 5-minute window — both work with any of the three chart types, since chart type is just how
+ the returned series get drawn, not part of the query itself. Add a panel, type a query, and it previews
+ live; a malformed query (e.g. mismatched braces, or histogram() missing its{' '}
+ [width]) shows its error inline in the panel instead of breaking the dashboard — a syntactically
+ valid query for a metric that doesn't exist just renders "No data in range."
+
Worked example
+
+ Ingesting a very chatty process and only care about the last hour of activity: set{' '}
+ max logs in memory to something like 50000 so older lines are dropped as new ones
+ arrive rather than growing memory use unbounded for the life of the process. Leave it blank to keep
+ everything ingested — the default, and fine for shorter-lived commands.
+