iet-telemetry-otel
Initializes tracing, metrics, and logs exporters explicitly at process start.
iet-telemetry-otelimplementationOpenTelemetry telemetryHow to use it
iet-telemetry-otel initializes OpenTelemetry once for the process and installs the tracing subscriber used across the framework. Call OpenTelemetry::init at startup, emit spans, logs, and metrics through iet_telemetry_otel::tracing, then shutdown().await after the application has drained.
// examples/htmx-starter/servers/web/src/main.rs
let telemetry = init?;
info!;
let result = run.await; // serve, migrate, seed...
let shutdown = telemetry.shutdown.await;
result?;
shutdown?;
config_from_envsnapshots onlyFW_TELEMETRY_*andOTEL_EXPORTER_OTLP_ENDPOINT; logs go to OTLP or JSON stdout, never both. An explicit config works too:TelemetryConfig { endpoint, ..TelemetryConfig::profile(Profile::Debug) }.initmust be called once (a second call fails withtelemetry.already_initialized);tracingevents on thefw::telemetry::metricstarget become counters, gauges, and histograms.shutdowndrains exporters off the async executor with a timeout; export outcome counters are exposed astrace_exports,log_exports, andmetric_exports.
How it works
OpenTelemetry::init builds one provider per signal — SdkTracerProvider, SdkMeterProvider, and SdkLoggerProvider — each feeding an OTLP/HTTP exporter through its batch or periodic processor, then installs a tracing_subscriber registry with the trace, metric, and log layers via a single try_init. shutdown moves the blocking SDK flush off the async executor in spawn_blocking and bounds it with a timeout.
flowchart LR A["OpenTelemetry::init"] --> B["SdkTracerProvider"] A --> C["SdkMeterProvider"] A --> D["SdkLoggerProvider"] B --> E["BatchSpanProcessor"] C --> F["PeriodicReader"] D --> G["BatchLogProcessor"] E --> H["OTLP http exporter"] F --> H G --> H A --> I["tracing_subscriber registry"] I -->|"try_init once"| J["global subscriber"] A --> K["shutdown"] K --> L["spawn_blocking flush"]
What it implements
- Concrete mechanism; see the public API below.
What's inside
Modules
src/cardinality.rssrc/diagnostics.rssrc/lib.rssrc/resources.rssrc/testing.rssrc/testing/sdk.rs
Public API
(root)
pub fn config_from_env() -> AppResult<TelemetryConfig>— Explicit snapshot of only telemetry-related environment values.- struct
OpenTelemetry pub fn init(config: TelemetryConfig) -> AppResult<Self>— Uses OTLP/HTTP protobuf on dedicated exporter threads. Call once at startup. Logs go to OTLP or JSON stdout, not both. No global meter provider is needed.pub fn meter(&self, name: &'static str) -> opentelemetry::metrics::Meterpub fn duration_view( config: iet_telemetry::HistogramConfig, ) -> impl Fn(&opentelemetry_sdk::metrics::Instrument) -> Option<opentelemetry_sdk::metrics::Stream>— Shared by production and test providers. Quantiles are computed downstream, never averaged across instances. All framework duration observations are seconds.
cardinality
pub fn new(limit: usize) -> Self
diagnostics
- struct
ExportStats - struct
ExportSnapshot pub fn snapshot(&self) -> ExportSnapshot- struct
Observed
testing
- struct
CapturedRecord - struct
Snapshot pub fn assert_span_exists(&self, name: &str)pub fn assert_no_dropped_records(&self)- struct
TestTelemetry pub fn new(capacity: usize) -> Selfpub fn dispatch(&self) -> tracing::Dispatchpub fn snapshot(&self) -> Snapshot
testing::sdk
- struct
TestProviders— Owns isolated SDK providers and a scoped subscriber for all three signals. Keep this alive until application tasks and response bodies have completed. pub fn new(capacity: usize) -> Selfpub fn with_histogram(capacity: usize, histogram: iet_telemetry::HistogramConfig) -> Selfpub fn dispatch(&self) -> tracing::Dispatchpub fn meter(&self, name: &'static str) -> opentelemetry::metrics::Meterpub fn flush(&self) -> OTelSdkResultpub fn shutdown(&self) -> OTelSdkResult- struct
Capture pub fn new(capacity: usize) -> Selfpub fn take(&self) -> Vec<T>pub fn dropped(&self) -> u64pub fn bounded(capacity: usize, max_points: usize, max_debug_bytes: usize) -> Self— Reject an entire oversized export before taking ownership. Debug-byte budget also bounds histogram arrays and exemplars, not just attributes.
Impl map
Visit for Identity<H>Filter<S> for CardinalityClone for Capture<T>SpanExporter for Capture<SpanData>LogExporter for Capture<SdkLogRecord>PushMetricExporter for Capture<ResourceMetrics>std::fmt::Write for LimitedTextVisit for FieldsLayer<S> for TestTelemetry
Depends on
iet-configiet-coreiet-telemetry(features: recording)
External crates: async-trait, opentelemetry, opentelemetry-appender-tracing, opentelemetry-otlp, opentelemetry_sdk, rustix, tokio, tracing, tracing-opentelemetry, tracing-subscriber
Used by
- No other framework crate depends on it directly.
In this repository
examples/htmx-starter
Source: crates/features/iet-telemetry-otel