wasmcloud_provider_sdk/otel.rs
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
/// Instrument a given [`provider_sdk::Context`], injecting current `tracing`-generated metadata
/// if one isn't present.
///
/// This functionality is exposed as a macro since the context for trace injection
/// should be at the *call site* of this macro (ex. inside some method annotated with `#[instrument]`)
///
/// This macro requires `provider_sdk` and `wasmcloud_tracing` to be imported
#[macro_export]
macro_rules! propagate_trace_for_ctx {
($ctx:ident) => {{
use $crate::wasmcloud_tracing::context::{attach_span_context, TraceContextInjector};
let trace_ctx = match $ctx {
Some(ref ctx) if !ctx.tracing.is_empty() => ctx
.tracing
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect::<Vec<(String, String)>>(),
_ => TraceContextInjector::default_with_span()
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect(),
};
attach_span_context(&trace_ctx);
}};
}
/// Initialize observability for a given provider with host-supplied data, via [`tracing`].
///
/// This functionality exists as a macro due to the requirement that `tracing` be initialized
/// from *binary* code, rather than library code.
///
/// This macro loads host data and uses the provider-sdk to build a [`tracing_core::Dispatch`] and
/// relevant guards/internal structures to configure it with information relevant to the host
///
/// This macro introduces the following variables into scope:
/// - `__observability__guard`
///
/// # Arguments
/// * `provider_name` - An expression that evaluates to a `&str` which is the name of your provider
/// * `maybe_flamegraphs_path` - An expression that evaluates to a `Option<impl AsRef<Path>>` for flamegraph path
#[macro_export]
macro_rules! initialize_observability {
($provider_name:expr, $maybe_flamegraphs_path:expr) => {
let __observability_guard = {
use $crate::anyhow::Context as _;
use $crate::tracing_subscriber::util::SubscriberInitExt as _;
let $crate::HostData {
config,
otel_config,
structured_logging,
log_level,
..
} = $crate::provider::load_host_data().context("failed to load host data")?;
// Update OTEL configuration with overrides if provided via config to the provider
let mut otel_config = otel_config.clone();
for (k, v) in config.iter() {
match k.to_uppercase().as_str() {
"OTEL_EXPORTER_OTLP_ENDPOINT" => {
otel_config.observability_endpoint = Some(v.clone())
}
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" => {
otel_config.traces_endpoint = Some(v.clone())
}
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" => {
otel_config.metrics_endpoint = Some(v.clone())
}
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT" => {
otel_config.logs_endpoint = Some(v.clone())
}
"OTEL_TRACES_SAMPLER" => {
otel_config.traces_sampler = Some(v.clone())
}
"OTEL_TRACES_SAMPLER_ARG" => {
otel_config.traces_sampler_arg = Some(v.clone())
}
"OTEL_BSP_MAX_CONCURRENT_EXPORTS" => {
let parsed = match v.parse::<usize>() {
Ok(v) => v,
Err(_) => {
eprintln!(
"Failed to parse OTEL_BSP_MAX_CONCURRENT_EXPORTS as usize, using previously set value or default"
);
continue
}
};
otel_config.concurrent_exports = Some(parsed)
}
"OTEL_BSP_MAX_QUEUE_SIZE" => {
let parsed = match v.parse::<usize>() {
Ok(v) => v,
Err(_) => {
eprintln!(
"Failed to parse OTEL_BSP_MAX_QUEUE_SIZE as usize, using previously set value or default"
);
continue
}
};
otel_config.max_batch_queue_size = Some(parsed)
}
_ => {}
}
}
// Init logging
//
// NOTE: this *must* be done on the provider binary side, to avoid
// colliding with the in-process observability setup that happens in the host.
let (dispatch, _guard) = $crate::wasmcloud_tracing::configure_observability(
$provider_name,
&otel_config,
*structured_logging,
$maybe_flamegraphs_path,
log_level.as_ref(),
Some(&otel_config.trace_level),
)
.context("failed to configure observability")?;
dispatch
.try_init()
.context("failed to initialize observability")?;
_guard
};
};
}