From cf889d7004f954c76a01a2914746d353ab28d593 Mon Sep 17 00:00:00 2001 From: Torstein Tauno Svendsen Date: Sun, 6 Sep 2026 23:29:49 +0200 Subject: [PATCH 1/2] The docs read against the graph diff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release doc pass over timbersh-v0.8.0..main, which is timbergraph and the `graph` statement, plus the one defect reading them found. - The refusal for samples that already carry a `host` label named an undefined variable, so raising it raised a NameError from inside the shell instead. Tested, and the test fails without the fix. - A `.B` request mid-line in timbersh(1) put the literal `.B "graph M from SRC extracting NAME"` in the rendered page. - `--width`/`--height` had neither help text nor a man entry. - The grammar `\?` prints — which timbersh(1) calls the authority — knew `png` but not `svg` or `using`. - Recommends: timberfs (>= 0.32.0), for `extracting`: it runs `timberfs tally --try` here and resolves a name against the packaged extractor directory. --- .github/workflows/timbersh.yml | 14 ++++++++------ packaging/timbergraph.1 | 5 +++++ packaging/timbersh.1 | 4 +++- tests/timbersh/test-timbersh | 15 +++++++++++++++ tools/README.md | 4 ++++ tools/timbergraph.py | 3 ++- tools/timbersh | 7 ++++--- 7 files changed, 41 insertions(+), 11 deletions(-) diff --git a/.github/workflows/timbersh.yml b/.github/workflows/timbersh.yml index 43eca0b..162c93c 100644 --- a/.github/workflows/timbersh.yml +++ b/.github/workflows/timbersh.yml @@ -77,11 +77,13 @@ jobs: # works; `--no-install-recommends` is the workstation that only # ever talks to other machines. # - # The version belongs there too, and only as a hint: the viewer is - # nothing but seeks and the bounded `from_chunk` one landed in - # 0.26.0. What a dpkg constraint cannot reach is the case that - # matters anyway — a REMOTE target, about which it says nothing — - # so the runtime diagnosis is the real guard. + # The version belongs there too, and only as a hint: `graph ... + # extracting` runs `timberfs tally --try` HERE and resolves an + # extractor name against the directory the timberfs package ships, + # both of which landed in 0.32.0. What a dpkg constraint cannot + # reach is the case that matters anyway — a REMOTE target, about + # which it says nothing — so the runtime diagnosis is the real + # guard. - name: Build the .deb run: | V=$(tr -d '[:space:]' < tools/VERSION) @@ -95,7 +97,7 @@ jobs: Priority: optional Architecture: all Depends: python3, zstd - Recommends: timberfs (>= 0.26.0) + Recommends: timberfs (>= 0.32.0) Suggests: gnuplot Maintainer: Torstein Tauno Svendsen Homepage: https://github.com/torstei/timberfs diff --git a/packaging/timbergraph.1 b/packaging/timbergraph.1 index c9a2e4a..586440e 100644 --- a/packaging/timbergraph.1 +++ b/packaging/timbergraph.1 @@ -150,6 +150,11 @@ Draw somewhere other than the terminal. .B \-\-window needs a display and gnuplot's qt or x11 terminal. .TP +.BI \-\-width " N" ", " \-\-height " N" +The plot's size \(em CHARACTERS on the terminal, where it defaults to the +terminal's own, and PIXELS everywhere else (1000x500, or 900x500 for +.BR \-\-window ). +.TP .BI \-\-tsv " FILE" ", " \-\-gnuplot " FILE" The table behind the picture, and the script that drew it with its data inline so it re-runs alone diff --git a/packaging/timbersh.1 b/packaging/timbersh.1 index 6d86bd6..d93b983 100644 --- a/packaging/timbersh.1 +++ b/packaging/timbersh.1 @@ -429,7 +429,9 @@ read and a plot of what came back, with no response kind of its own. ⚠ The HOST is a label like any other: a fleet answer that merged two of them would be two series a reader takes for one, so .B "by host" -keeps them apart and leaving it out sums them on purpose. .B "graph M from SRC extracting NAME" +keeps them apart and leaving it out sums them on purpose. +.PP +.B "graph M from SRC extracting NAME" makes the numbers HERE, from a store that has NO TALLY at all \(em for trying an extractor against real data before provisioning anything. ⚠ It moves the RAW LOG, tens of megabytes an hour per host against kilobytes diff --git a/tests/timbersh/test-timbersh b/tests/timbersh/test-timbersh index f4e2b68..335d912 100755 --- a/tests/timbersh/test-timbersh +++ b/tests/timbersh/test-timbersh @@ -457,6 +457,21 @@ def a_graph_makes_the_fleet_a_dimension_rather_than_merging_it(): s.cleanup() +@test +def a_graph_refuses_a_host_label_it_would_have_to_write_over(): + """The shell adds `host` itself, so a metric that already carries one + would be two meanings in one label. The refusal has to survive being + RAISED — it names the metric, and naming the wrong variable turns the + diagnosis into a NameError from inside the shell.""" + labelled = "2026-09-06T13:37:00.000Z 60s heap host=one last=100\n" + s = Session({h: {"stores": [store("t", ID_A)], "loglines": labelled} + for h in ("a", "b")}, hosts=["a", "b"]).run( + "graph heap from [class=tally];") + assert "already carry" in s.out, s.out + assert "graph heap from" in s.out, s.out + s.cleanup() + + @test def a_graph_refuses_a_cumulative_ladder_rather_than_multiplying_it(): """`le` series are cumulative, so stacking them multiplies the count diff --git a/tools/README.md b/tools/README.md index 1174380..0e11622 100644 --- a/tools/README.md +++ b/tools/README.md @@ -597,6 +597,10 @@ Several metrics go on one graph, comma-separated — which is how two stores answer at once, since `[class=tally]` covers both and the metric name is what tells them apart. +`using ` names the extractor document the numbers came from, which is +where the **unit** is written down; it is `timbergraph --using` below, with the +same lookup. `svg 'FILE'` draws where `png 'FILE'` does. + ### `extracting` — metrics from a store that has no tally ``` diff --git a/tools/timbergraph.py b/tools/timbergraph.py index 72f3ee9..7bcec63 100644 --- a/tools/timbergraph.py +++ b/tools/timbergraph.py @@ -812,7 +812,8 @@ def main(argv=None): ap.add_argument("--svg", metavar="FILE") ap.add_argument("--window", action="store_true", help="an interactive window; needs a display and gnuplot-qt") - ap.add_argument("--width", type=int) + ap.add_argument("--width", type=int, + help="characters on the terminal, pixels in an image") ap.add_argument("--height", type=int) ap.add_argument("--tsv", metavar="FILE", help="the table behind the picture") diff --git a/tools/timbersh b/tools/timbersh index 71e118c..60b5892 100755 --- a/tools/timbersh +++ b/tools/timbersh @@ -197,7 +197,7 @@ HELP = """ select from [where ...] [limit N [chunks]] [into view]; tail from [where ...]; graph [, ...] from [by LABEL] [where ...] - [quantile Q] [rate] [png 'FILE']; + [quantile Q] [rate] [using ] [png 'FILE'|svg 'FILE']; graph against from [...]; graph from extracting where ... ; @@ -1676,7 +1676,8 @@ class Shell: if at is None or at < 2 or at + 1 >= len(toks): raise ValueError( "graph [, ...] from [by