Skip to content

stratify 1.0.0: absorb loggingkit as stratify::logging, add init() - #6

Merged
LogicOcean merged 4 commits into
mainfrom
unify-logging
Aug 21, 2026
Merged

LogicOcean merged 4 commits into
mainfrom
unify-logging

Conversation

@LogicOcean

Copy link
Copy Markdown
Owner

One crate, two namespaces. stratify::config is the configuration half, stratify::logging (feature logging) is a non-blocking tracing facade, and stratify::init stands both up in one call. A config-only build compiles none of the logging stack, and CI fails if the default dependency tree ever contains a logging dependency.

Breaking: the config API moves from the crate root into stratify::config and the types shed their prefixes (ConfigBuilder -> config::Builder, etc.). Full details in the CHANGELOG's 1.0.0 entry.

Already published to crates.io as 1.0.0; this PR brings main up to the released source.

David Saroka added 4 commits August 21, 2026 16:05
One crate, two namespaces. `stratify::config` is the configuration half,
`stratify::logging` is a non-blocking tracing facade behind the
`logging` feature, and `stratify::init` reads configuration, builds
logging from its `[logging]` block, and installs the subscriber in one
call. A config-only build compiles none of the logging stack, and CI now
fails if the default dependency tree ever contains tracing-subscriber,
tracing-appender or any opentelemetry crate, because that guarantee is
what the one-crate design rests on.

Breaking: the config API moves from the crate root into
`stratify::config`, and the types shed prefixes the module now carries:
ConfigBuilder -> config::Builder, ConfigError -> config::Error,
ConfigStore -> config::Store. The same rename applies to the logging
half (LogError -> logging::Error, LoggingHandle -> logging::Handle),
whose LoggingKit namespace struct dissolves into module functions.

The logging half arrives without its git history, deliberately, and
without its legacy pre-facade API (LogBuilder, LogStore, the sink
module, and the chrono dependency only they used). Its TOML parsing is
gone too: logging is described by `logging::settings::Settings`, a serde
schema read from a config Store, so parsing and precedence exist in one
place. `Builder::init` now returns the Handle it stores.

Settings tests go through a real store built from a temp file rather
than a parser the logging half no longer owns, and the error type keeps
loggingkit's exact display strings, which the moved tests pin.

Verified: 549 tests across the default/logging/all-features matrix, 48
suites, 0 failures; clippy clean on all three with -D warnings; cargo
doc clean; cargo deny advisories/bans/sources/licenses ok; the five
runnable examples run; qualia 97/100 (A).
The version says the API is frozen, so the release audits exactly that
surface and fixes what must not be frozen by accident:

- `Handle.reload_tx` was public with no consumer. A field nobody uses is
  an accident, and 1.0 turns accidents into contracts. Now private;
  `reload_filter` remains the supported route.

- `Handle::shutdown` did not exist. `flush` drains the queues but leaves
  the Application Insights exporter's batch loop running, so a clean
  process exit had no correct final call. `shutdown(self)` flushes, then
  closes both providers; it consumes the handle because records after it
  never reach the exporter, and a live-looking handle past that point
  would lie.

- `init` had no end-to-end test. The flagship function now has one, in
  its own integration binary because installing the global subscriber
  happens once per process: a real config file through a real store,
  the subscriber installed, the install line and an app record asserted
  in the file sink, and the config half answering from the same file.

- The declared MSRV (1.88.0) was never compiled in CI, which is a
  promise that drifts. A dedicated job now runs cargo check with all
  features on 1.88.0; verified locally on that toolchain first.

Verified: 551 tests across the default/logging/all-features matrix, 0
failures; clippy clean on all three sets with -D warnings; cargo doc
clean; MSRV check clean; cargo publish --dry-run packages successfully;
qualia 97/100 (A).
…ult refs

The four adoption gaps from the 1.0 audit.

Settings parity. "Described rather than coded" covered eight of the
builder's blocks and was silent about the rest. The `[logging]` schema
now expresses all of it: per-sink filters, redact, capture_panics,
global_fields, syslog, and app_insights. The app_insights block names
the key the connection string is found under rather than holding the
value, so the file stays safe to commit; an explicit block whose secret
the store cannot answer is a startup error, not a silently absent
exporter. `Settings::to_builder` is fallible now, because a bad level,
an unknown facility, or a block needing a feature that is not compiled
in must fail loudly naming the key — and it refuses an app_insights
block outright, directing the caller to `from_store`/`apply`, which can
resolve it.

Trace sampling. The tracer exported every span, which at production
traffic is an Application Insights bill growing linearly with load.
`AppInsightsConfig::with_sample_rate` (and `sample_rate` in the block)
bounds it: parent-based, so a trace is kept or dropped whole rather
than arriving with holes. Log records are not sampled; per-sink filters
are the tool for those.

RUST_LOG through the store. The builder's fallback reads the process
environment, which a `.env` loaded as a source never touches, so a
RUST_LOG written there silently lost to a shell export — the exact
inversion the `.env` precedence promises. With no explicit level, init
now reads `rust_log` from the store, strictly: a typo is a startup
error naming the key.

Key Vault references. An App Configuration key can hold a reference to
a Key Vault secret — the common enterprise setup — and the source
handed back the JSON envelope as if it were the value.
`with_key_vault_resolution()` resolves references with the same
credential against the vault data plane. Off by default, because
resolution widens the source's reach from one store to every vault the
references name; with it off, encountering a reference is an error
naming the key.

Also re-exports EnvFilter (callers needed tracing-subscriber as a
direct dependency just to name a parameter type) and decomposes
init_with and base_builder after the additions pushed both past a
cyclomatic complexity worth keeping.

Verified: 270 tests all-features (64 default / 80 azure / 236 logging),
0 failures; clippy -D warnings clean on all four feature sets; docs
clean; MSRV 1.88.0 clean; cargo deny ok; default tree still carries no
logging dependencies; qualia 96/100 (A).
The double-check pass, probing what the previous commit added rather
than restating it. Three findings, all fixed:

The connection_string_key missed its own most likely spelling. The
natural thing to write in the block is the environment variable's name
as the environment shows it — uppercase — while the env source stores
keys lowercased, so the obvious configuration failed on first use. The
lookup now tries the key as written, then lowercased, and a regression
test pins the uppercase path.

The sample-rate clamp propagated NaN. `f64::clamp` passes NaN through,
and a NaN ratio is not a rate the OTel sampler defines behaviour for.
Non-finite now means 1.0.

Options and Bootstrap lacked #[non_exhaustive]. Both have public fields
and are 1.0 surface, so adding any future field — an env prefix
variant, a metrics handle — would have been a breaking change forever.
Construction already goes through new()/init, so nothing downstream
loses anything.

Verified: 271 tests all-features (64/80/236 across default/azure/
logging), 0 failures; clippy -D warnings clean on all four feature
sets; docs, MSRV and the no-logging-deps tree check clean; qualia
96/100 (A).
@LogicOcean
LogicOcean enabled auto-merge (squash) August 21, 2026 16:44
@LogicOcean
LogicOcean merged commit 37e3a10 into main Aug 21, 2026
3 checks passed
@LogicOcean
LogicOcean deleted the unify-logging branch August 21, 2026 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant