Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
init4 bin-base
Common functionality for binaries produced by the init4 project. This crate provides:
- Environment parsing utilities
- Standard
tracingsetup withotlpsupport - Standard server for Prometheus
metrics - Standard environment variables to configure these features
Note: This crate is intended as a base for all binaries in the init4 project. It is not intended for outside consumption.
Installation
[]
= "0.18"
Quick Start
use init4;
Build the crate docs with cargo doc --open for more details.
init4 Tracing Best Practices
Carefully Consider Level
Event and span level should correspond to the significance of the event as follows:
| Level | Usage | Examples |
|---|---|---|
TRACE |
Low-level, detailed debugging info. Use rarely. | HTTP request body, every network packet |
DEBUG |
Low-level lifecycle info useful for debugging. Use sparingly. | Single DB query result, single function call result |
INFO |
Normal operation lifecycle info. Default level for most events. | Request processing start, DB connection established |
WARN |
Potential problems that don't prevent operation. | Request took longer than expected, ignored parse error |
ERROR |
Problems that prevent correct operation. | DB connection failed, required file not found |
By default, the OTLP exporter captures DEBUG and higher. Configure with OTEL_LEVEL env var.
The log formatter logs at INFO level. Configure with RUST_LOG env var.
// ❌ Avoid
warn!;
// ✅ Instead
info!;
Import from bin-base
Re-export all necessary crates from init4-bin-base rather than adding them to your Cargo.toml:
// ❌ Avoid
use info;
// ✅ Instead
use info;
Spans
Spans represent the duration of a unit of work. They should be:
- Time-limited — at most a few seconds
- Work-associated — tied to a specific action
- Informative — have useful data, not over-verbose
Inheritance
Spans inherit the currently-entered span as their parent. Avoid spurious span relationships:
// ❌ Avoid — accidental parent-child relationship
let span = info_span!.entered;
let my_closure = ;
do_work;
// ✅ Instead — closure span created before outer span
let my_closure = ;
let span = info_span!.entered;
do_work;
Avoid Over-Verbose Spans
When instrumenting methods, skip self and add only needed fields:
// ❌ Avoid — self will be Debug-printed (verbose)
async
// ✅ Instead — skip self, add specific fields
async
For multiple arguments, skip all and add back what you need:
// ❌ Avoid
async
// ✅ Instead
async
Instrument Futures, Not JoinHandles
// ❌ Avoid — span won't propagate to the future
spawn.instrument;
// ✅ Instead
spawn;
Instrument Work, Not Tasks
Avoid adding spans to long-running tasks. Create spans in the internal loop instead:
// ❌ Avoid — span open for entire task lifetime
let span = info_span!;
spawn;
// ✅ Instead — span per iteration
spawn;
Root Spans
Root spans are top-level spans in a trace. Ensure they correspond to a SINGLE UNIT OF WORK:
// ❌ Avoid — nested work units under one span
let span = info_span!;
for item in my_vec
// ✅ Instead — each work unit is a root span
let work_loop = info_span!.entered;
for item in my_vec
With #[instrument]:
// ✅ Create root span
async
Be Careful with instrument(err)
Using #[instrument(err)] emits errors at EACH span level. Only root spans should have instrument(err):
// ❌ Avoid — error emitted multiple times
async
async
// ✅ Instead — only root span has err
async
async
To track error bubbling, record additional info:
async
Managing Events
Events represent state at a single point in time. They should be:
- Informative — useful data, not over-verbose
- Descriptive — clear, concise messages
- Lifecycle-aware — record lifecycle of a unit of work
- Non-repetitive — fire ONCE in a span's lifetime
Avoid String Interpolation
Events are structured data. String interpolation loses type information:
// ❌ Avoid
info!;
// ✅ Instead
info!;
Lifecycle Events
Events should capture significant lifecycle steps, not every step:
// ❌ Avoid — using events for start/end
info!;
let parsed = parse_input;
info!;
// ✅ Instead — use spans
let span = info_span!.entered;
let parsed = parse_input;
drop;
// ✅ Even better — use #[instrument]
DRY: Don't Repeat Yourself (at INFO and DEBUG)
If firing the same event many times, you're violating span rules or verbosity rules:
// ❌ Avoid — same event many times
for i in my_vec
// ✅ Instead — trace per item, info for summary
for i in my_vec
info!;
License
This project is licensed under the MIT License.