|
| 1 | +use opentelemetry::logs::LogRecord; |
| 2 | +use opentelemetry_semantic_conventions as semcov; |
| 3 | +use std::error::Error; |
| 4 | + |
| 5 | +#[derive(Debug)] |
| 6 | +struct ErrorAsExceptionLogProcessor; |
| 7 | + |
| 8 | +impl opentelemetry_sdk::logs::LogProcessor for ErrorAsExceptionLogProcessor { |
| 9 | + fn emit( |
| 10 | + &self, |
| 11 | + data: &mut opentelemetry_sdk::logs::SdkLogRecord, |
| 12 | + _instrumentation: &opentelemetry::InstrumentationScope, |
| 13 | + ) { |
| 14 | + if let Some(severity) = data.severity_number() { |
| 15 | + if severity >= opentelemetry::logs::Severity::Error { |
| 16 | + // TODO: Check if exception attributes are already present |
| 17 | + data.add_attribute(semcov::attribute::EXCEPTION_TYPE, "error"); |
| 18 | + if let Some(body) = data.body() { |
| 19 | + data.add_attribute( |
| 20 | + semcov::attribute::EXCEPTION_MESSAGE, |
| 21 | + any_value_to_string(body), |
| 22 | + ); |
| 23 | + } |
| 24 | + } |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + fn force_flush(&self) -> opentelemetry_sdk::error::OTelSdkResult { |
| 29 | + Ok(()) |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +fn any_value_to_string(v: &opentelemetry::logs::AnyValue) -> String { |
| 34 | + match v { |
| 35 | + opentelemetry::logs::AnyValue::String(v) => v.to_string(), |
| 36 | + _ => format!("{:?}", v).into(), |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +fn main() -> Result<(), Box<dyn Error + Send + Sync>> { |
| 41 | + let client = reqwest::blocking::Client::new(); |
| 42 | + |
| 43 | + let exporter = opentelemetry_application_insights::Exporter::new_from_env(client)?; |
| 44 | + |
| 45 | + let logger_provider = opentelemetry_sdk::logs::SdkLoggerProvider::builder() |
| 46 | + .with_log_processor(ErrorAsExceptionLogProcessor) |
| 47 | + .with_batch_exporter(exporter) |
| 48 | + .build(); |
| 49 | + let otel_log_appender = |
| 50 | + opentelemetry_appender_log::OpenTelemetryLogBridge::new(&logger_provider); |
| 51 | + log::set_boxed_logger(Box::new(otel_log_appender))?; |
| 52 | + log::set_max_level(log::Level::Info.to_level_filter()); |
| 53 | + |
| 54 | + // Log via `log` crate. |
| 55 | + let fruit = "apple"; |
| 56 | + let price = 2.99; |
| 57 | + let colors = ("red", "green"); |
| 58 | + log::info!(fruit, price, colors:sval; "info! {fruit} is {price}"); |
| 59 | + log::warn!("warn!"); |
| 60 | + log::error!("error!"); |
| 61 | + |
| 62 | + // Force export before exit. |
| 63 | + logger_provider.shutdown()?; |
| 64 | + |
| 65 | + Ok(()) |
| 66 | +} |
0 commit comments