Skip to content

Commit 7a42764

Browse files
feat(logging): tracing diagnostics with --log-format/--log-level (#51) (#110)
Add tracing + tracing-subscriber. Global --log-format=pretty|json and --log-level flags (precedence --log-level > RUST_LOG > info). The subscriber writes to stderr so the stdout data contract is never contaminated: JSON reports, the version string, the octad table, and the status/gc/validate report bodies stay on stdout verbatim. Only genuine diagnostics (schema parsing, file-write progress, "checking drift", "created manifest") become tracing events. JSON log schema documented in docs/logging.adoc + docs/logging.schema.json. New acceptance suite tests/logging_test.rs (6 tests): stdout purity, JSON-line schema validity, level filtering, RUST_LOG precedence. Closes #51. Co-authored-by: hyperpolymath <hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 642e1e1 commit 7a42764

7 files changed

Lines changed: 439 additions & 11 deletions

File tree

Cargo.lock

Lines changed: 150 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@ thiserror = "2"
2222
chrono = { version = "0.4", features = ["serde"] }
2323
sha2 = "0.10"
2424
rusqlite = { version = "0.32", features = ["bundled", "hooks"] }
25+
tracing = "0.1"
26+
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
2527

2628
[build-dependencies]
2729
chrono = "0.4"
2830

2931
[dev-dependencies]
3032
tempfile = "3"
3133
proptest = "1"
34+
serde_json = "1"

docs/logging.adoc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
= VeriSimiser diagnostic logging
3+
:revdate: 2026-05-17
4+
5+
VeriSimiser separates two output streams:
6+
7+
stdout (data)::
8+
The answer to the command: JSON reports (`status --json`, `gc --json`,
9+
`validate --json`, `doctor --json`, `version --json`), the human-readable
10+
`status` / `gc` / `validate` report bodies, the `octad` table, and the
11+
`version` string. This contract is stable and machine-parseable; logging
12+
configuration never alters it.
13+
14+
stderr (diagnostics)::
15+
Progress and status messages emitted via `tracing` (e.g. "parsing
16+
schema", "generated sidecar schema", "checking temporal drift",
17+
"created manifest"). Safe to discard; never parse stdout-bound data
18+
out of this stream.
19+
20+
== Flags
21+
22+
`--log-format=pretty|json`:: diagnostic rendering. Default `pretty`
23+
(human-readable, coloured). `json` emits one JSON object per line.
24+
`--log-level=trace|debug|info|warn|error`:: minimum level. Precedence:
25+
`--log-level` > `RUST_LOG` > `info`. `RUST_LOG` accepts the full
26+
`tracing-subscriber` `EnvFilter` syntax (e.g. `RUST_LOG=verisimiser=debug`).
27+
28+
Both flags are global: they may appear before or after the subcommand.
29+
30+
== JSON log schema
31+
32+
With `--log-format=json`, each diagnostic line is a JSON object produced by
33+
`tracing-subscriber`'s JSON formatter. A machine-readable JSON Schema is at
34+
`docs/logging.schema.json`. Shape:
35+
36+
[source,json]
37+
----
38+
{
39+
"timestamp": "2026-05-17T12:34:56.789012Z",
40+
"level": "INFO",
41+
"target": "verisimiser",
42+
"fields": { "message": "generated sidecar schema",
43+
"path": ".verisim/sidecar_schema.sql" },
44+
"spans": []
45+
}
46+
----
47+
48+
`timestamp` (RFC 3339), `level` (`TRACE|DEBUG|INFO|WARN|ERROR`), `target`
49+
(emitting module), and `fields` (always contains `message`; structured
50+
key/values such as `path`, `schema`, `threshold`, `tables` are added per
51+
event) are always present. `spans` is present when emitted inside a span.
52+
Stable contract: consumers may rely on `timestamp`, `level`, `target`, and
53+
`fields.message`.

docs/logging.schema.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://github.com/hyperpolymath/verisimiser/docs/logging.schema.json",
4+
"title": "VeriSimiser JSON diagnostic log line",
5+
"description": "One line of `--log-format=json` output (stderr). stdout data output is NOT covered by this schema.",
6+
"type": "object",
7+
"required": ["timestamp", "level", "target", "fields"],
8+
"properties": {
9+
"timestamp": {
10+
"type": "string",
11+
"format": "date-time",
12+
"description": "RFC 3339 / ISO 8601 event time."
13+
},
14+
"level": {
15+
"type": "string",
16+
"enum": ["TRACE", "DEBUG", "INFO", "WARN", "ERROR"]
17+
},
18+
"target": {
19+
"type": "string",
20+
"description": "Emitting module path, e.g. \"verisimiser\"."
21+
},
22+
"fields": {
23+
"type": "object",
24+
"required": ["message"],
25+
"properties": {
26+
"message": { "type": "string" }
27+
},
28+
"additionalProperties": true,
29+
"description": "Always carries `message`; structured key/values (path, schema, threshold, tables, …) are added per event."
30+
},
31+
"spans": {
32+
"type": "array",
33+
"items": { "type": "object" }
34+
}
35+
},
36+
"additionalProperties": true
37+
}

0 commit comments

Comments
 (0)