iii-observability
v0.12.0OpenTelemetry-based traces, metrics, logs, alerts, and sampling.
exact versions are immutable; binary and bundle artifacts are digest-pinned.
skill doc
Read and locally set OpenTelemetry baggage
how-toWhen to use
The three functions inspect the OpenTelemetry baggage attached to the current trace context — string-keyed values that propagate alongside spans for cross-cutting concerns (tenant id, request id, A/B variant, feature flags). All three are read-side or local-only: there is no engine function that writes baggage so the next inbound request sees it.
| Question | Use this |
|---|---|
| Read one baggage key | engine::baggage::get |
| Read every baggage key | engine::baggage::get_all |
| Set a value for the current call's downstream code | engine::baggage::set (see warning below) |
Warning —
baggage::setdoes not propagate. OpenTelemetry baggage is immutable; the engine constructs a new context with the value but cannot push it back to the caller's invocation. The function exists for verification and debugging. Real baggage propagation must happen at the SDK / invocation level by attaching baggage headers to the next outbound call. The function returns anotefield reminding the caller of this.
Reach for get / get_all when:
- A handler needs the tenant/user/request id the upstream caller stamped onto baggage.
- You're debugging trace correlation and want to verify baggage is flowing.
Use a function-input field instead of baggage::set when you actually need to pass a value to a downstream call — baggage is for opaque cross-cutting context, not for inter-function arguments.
engine::baggage::get
Inputs
{
"key": "tenant_id" // required. The baggage key to read.
}Outputs
{
"value": "tenant-7" // The string value, or null when the key isn't present in the current baggage.
}engine::baggage::get_all
Inputs
{}get_all takes no fields.
Outputs
{
"baggage": {
"tenant_id": "tenant-7",
"request_id": "req-abc-123"
}
}The response is an object map of every baggage key/value in the current context. Empty baggage returns { "baggage": {} }.
engine::baggage::set
Inputs
{
"key": "feature_variant", // required. Baggage key.
"value": "experiment-A" // required. String value to set.
}Outputs
{
"success": true,
"note": "Baggage set in new context. For propagation, use SDK-level baggage headers."
}The note field is the engine's reminder that this set is local-only. The new context exists for the duration of the call but is not handed back to the caller's tracing pipeline. Verify, debug, or test with this function — do not rely on it for runtime context propagation.
Worked example
Read the tenant_id baggage key the upstream caller stamped onto the trace context:
{ "key": "tenant_id" }The typical pattern is get/get_all for inspection. A handler reads tenant_id from baggage, branches on it, and proceeds; for tracing visibility this means the value was stamped by an upstream caller (HTTP middleware, SDK auto-instrumentation, etc.). set is only useful in tests or when verifying the OTel pipeline is wired up correctly.
For runnable scaffolds and the SDK-level pattern for actually propagating baggage, see the observability worker source and SDK examples in the iii main repo.
Related
iii-observabilityworker config — sampling and trace-context configuration governs whether baggage flows through to your handler. The relevant knobs aresampling_ratio(global trace ratio) and the advancedsampling:block (default,parent_based,rules: [{operation, rate}],rate_limit: { max_traces_per_second }); set periii-config.yaml.engine::traces::tree— when investigating a trace,attributeson each span often duplicate baggage values, useful as a cross-check.