1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024-2026 Dragonscale Team
//! OpenTelemetry tracing-subscriber layer for `uni-db`.
//!
//! Per proposal §12.1.1, plugin spans should propagate alongside the
//! host's `tracing` events so a query trace shows up as one continuous
//! span tree in Jaeger / Tempo / Datadog. This module exposes a single
//! initialization helper that constructs a [`tracing_subscriber::Registry`]
//! with the [`tracing-opentelemetry`](https://docs.rs/tracing-opentelemetry)
//! layer wrapping the standard `fmt` layer.
//!
//! ## Why a helper, not auto-install?
//!
//! Embedders frequently bring their own `tracing` subscriber (server
//! frameworks like axum/tower-http, test harnesses, Python bindings).
//! Auto-installing a global subscriber from `Uni::open` would conflict
//! with those setups and produce the runtime panic
//! "a global default trace dispatcher has already been set". The
//! conservative shape: ship the helper, let embedders opt in.
//!
//! Inside the host, the [`uni_plugin::observability::record_invocation`]
//! function emits `tracing::debug!` events tagged with `kind` / `qname` /
//! plugin id. With the OTel layer installed those events become OTLP
//! spans automatically.
//!
//! ## Usage
//!
//! ```no_run
//! use uni_plugin_host::observability::OtelConfig;
//!
//! let cfg = OtelConfig {
//! service_name: "my-app".into(),
//! otlp_endpoint: "http://localhost:4317".into(),
//! };
//! let _guard = uni_plugin_host::observability::init_otel_subscriber(cfg)
//! .expect("OTel subscriber must initialize once");
//! // ... use Uni normally; events become OTLP spans.
//! ```
// Rust guideline compliant
use Error as StdError;
use TracerProvider as _;
use WithExportConfig;
use Resource;
use SdkTracerProvider;
use SubscriberExt;
use SubscriberInitExt;
/// Configuration for the OTel tracing subscriber.
///
/// Construct directly with literal fields; no builder is needed at this
/// shape.
/// Initialize a `tracing-subscriber::Registry` with an OTel layer
/// pointing at the OTLP endpoint described by `cfg`.
///
/// Returns a [`OtelGuard`] whose `Drop` impl shuts the tracer provider
/// down cleanly. Calls
/// [`tracing_subscriber::util::SubscriberInitExt::try_init`] under the
/// hood — passing the global default subscriber lock through to
/// `tracing-subscriber` semantics.
///
/// # Errors
///
/// Returns an error if the tracer provider cannot be constructed
/// (bad endpoint, missing TLS material) or if a global subscriber has
/// already been installed.
/// RAII guard that flushes and shuts down the OTel tracer provider on
/// drop. Keep the returned value alive for the lifetime of the
/// process; dropping it tears down the OTel pipeline.
// ── FU-3: trace context extraction + outbound HTTP injection ──────
/// W3C `traceparent` header value extracted from the current
/// `tracing` span, formatted as `00-<trace_id>-<span_id>-<flags>`.
///
/// Returns `None` when no `tracing-opentelemetry` layer is installed
/// (the current span has no associated `SpanContext`). Used by
/// outbound HTTP request paths to propagate the trace across a
/// process boundary — e.g., when a plugin invokes `http-get-with-trace`
/// via the host-net WIT import.
/// Perform an HTTP GET against `url` with the current span's
/// `traceparent` header injected (FU-3).
///
/// Used by the host's outbound-HTTP request path (and by the
/// `examples/otel_demo` binary) to demonstrate end-to-end trace
/// propagation: `Session::query → plugin span → outbound HTTP`. The
/// receiving server sees a `traceparent` header whose `trace_id`
/// matches the outer query span.
///
/// # Errors
///
/// Returns an error string on any HTTP transport / status failure.
pub async