Skip to content

Commit

Permalink
Add tests for tracing appender (#1415)
Browse files Browse the repository at this point in the history
  • Loading branch information
cijothomas authored Nov 30, 2023
1 parent cd23ec2 commit 8b838fc
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 1 deletion.
1 change: 1 addition & 0 deletions opentelemetry-appender-tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ opentelemetry-stdout = { path = "../opentelemetry-stdout", features = ["logs"] }
[features]
logs_level_enabled = ["opentelemetry/logs_level_enabled", "opentelemetry_sdk/logs_level_enabled"]
default = ["logs_level_enabled"]
testing = ["opentelemetry_sdk/testing"]
142 changes: 142 additions & 0 deletions opentelemetry-appender-tracing/src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,145 @@ const fn severity_of_level(level: &Level) -> Severity {
Level::ERROR => Severity::Error,
}
}

#[cfg(test)]
mod tests {
use crate::layer;
use opentelemetry::logs::Severity;
use opentelemetry::trace::TracerProvider as _;
use opentelemetry::trace::{TraceContextExt, TraceFlags, Tracer};
use opentelemetry::{logs::AnyValue, Key};
use opentelemetry_sdk::logs::LoggerProvider;
use opentelemetry_sdk::testing::logs::InMemoryLogsExporter;
use opentelemetry_sdk::trace::{config, Sampler, TracerProvider};
use tracing::error;
use tracing_subscriber::layer::SubscriberExt;

// cargo test --features=testing
#[test]
fn tracing_appender_standalone() {
// Arrange
let exporter: InMemoryLogsExporter = InMemoryLogsExporter::default();
let logger_provider = LoggerProvider::builder()
.with_simple_exporter(exporter.clone())
.build();

let layer = layer::OpenTelemetryTracingBridge::new(&logger_provider);
let subscriber = tracing_subscriber::registry().with(layer);

// avoiding setting tracing subscriber as global as that does not
// play well with unit tests.
let _guard = tracing::subscriber::set_default(subscriber);

// Act
error!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "[email protected]");
logger_provider.force_flush();

// Assert TODO: move to helper methods
let exported_logs = exporter
.get_emitted_logs()
.expect("Logs are expected to be exported.");
assert_eq!(exported_logs.len(), 1);
let log = exported_logs
.get(0)
.expect("Atleast one log is expected to be present.");

// Validate common fields
assert_eq!(log.instrumentation.name, "opentelemetry-appender-tracing");
assert_eq!(log.record.severity_number, Some(Severity::Error));

// Validate trace context is none.
assert!(log.record.trace_context.is_none());

// Validate attributes
let attributes: Vec<(Key, AnyValue)> = log
.record
.attributes
.clone()
.expect("Attributes are expected");
assert_eq!(attributes.len(), 4);
assert!(attributes.contains(&(Key::new("name"), "my-event-name".into())));
assert!(attributes.contains(&(Key::new("event_id"), 20.into())));
assert!(attributes.contains(&(Key::new("user_name"), "otel".into())));
assert!(attributes.contains(&(Key::new("user_email"), "[email protected]".into())));
}

#[test]
fn tracing_appender_inside_tracing_context() {
// Arrange
let exporter: InMemoryLogsExporter = InMemoryLogsExporter::default();
let logger_provider = LoggerProvider::builder()
.with_simple_exporter(exporter.clone())
.build();

let layer = layer::OpenTelemetryTracingBridge::new(&logger_provider);
let subscriber = tracing_subscriber::registry().with(layer);

// avoiding setting tracing subscriber as global as that does not
// play well with unit tests.
let _guard = tracing::subscriber::set_default(subscriber);

// setup tracing as well.
let tracer_provider = TracerProvider::builder()
.with_config(config().with_sampler(Sampler::AlwaysOn))
.build();
let tracer = tracer_provider.tracer("test-tracer");

// Act
let (trace_id_expected, span_id_expected) = tracer.in_span("test-span", |cx| {
let trace_id = cx.span().span_context().trace_id();
let span_id = cx.span().span_context().span_id();

// logging is done inside span context.
error!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "[email protected]");
(trace_id, span_id)
});

logger_provider.force_flush();

// Assert TODO: move to helper methods
let exported_logs = exporter
.get_emitted_logs()
.expect("Logs are expected to be exported.");
assert_eq!(exported_logs.len(), 1);
let log = exported_logs
.get(0)
.expect("Atleast one log is expected to be present.");

// validate common fields.
assert_eq!(log.instrumentation.name, "opentelemetry-appender-tracing");
assert_eq!(log.record.severity_number, Some(Severity::Error));

// validate trace context.
assert!(log.record.trace_context.is_some());
assert_eq!(
log.record.trace_context.as_ref().unwrap().trace_id,
trace_id_expected
);
assert_eq!(
log.record.trace_context.as_ref().unwrap().span_id,
span_id_expected
);
assert_eq!(
log.record
.trace_context
.as_ref()
.unwrap()
.trace_flags
.unwrap(),
TraceFlags::SAMPLED
);

// validate attributes.
let attributes: Vec<(Key, AnyValue)> = log
.record
.attributes
.clone()
.expect("Attributes are expected");
assert_eq!(attributes.len(), 4);
assert!(attributes.contains(&(Key::new("name"), "my-event-name".into())));
assert!(attributes.contains(&(Key::new("event_id"), 20.into())));
assert!(attributes.contains(&(Key::new("user_name"), "otel".into())));
assert!(attributes.contains(&(Key::new("user_email"), "[email protected]".into())));
}
}
2 changes: 1 addition & 1 deletion opentelemetry/src/logs/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl From<&SpanContext> for TraceContext {
}

/// Value types for representing arbitrary values in a log record.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum AnyValue {
/// An integer value
Int(i64),
Expand Down

0 comments on commit 8b838fc

Please sign in to comment.