Repository navigation
stratify 1.0.0: absorb loggingkit as stratify::logging, add init() - #6
Merged
Merged
Conversation
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One crate, two namespaces.
stratify::configis the configuration half,stratify::logging(featurelogging) is a non-blocking tracing facade, andstratify::initstands 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::configand 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.