-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add opentelemetry-otlp integration example
- Loading branch information
Showing
2 changed files
with
167 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
use opentelemetry::{global, runtime, Key, KeyValue}; | ||
use opentelemetry_otlp::TonicExporterBuilder; | ||
use opentelemetry_sdk::{ | ||
metrics::{ | ||
reader::{DefaultAggregationSelector, DefaultTemporalitySelector}, | ||
Aggregation, Instrument, MeterProvider, PeriodicReader, Stream, | ||
}, | ||
trace::{BatchConfig, RandomIdGenerator, Sampler, Tracer}, | ||
Resource, | ||
}; | ||
use opentelemetry_semantic_conventions::{ | ||
resource::{DEPLOYMENT_ENVIRONMENT, SERVICE_NAME, SERVICE_VERSION}, | ||
SCHEMA_URL, | ||
}; | ||
use tracing_core::Level; | ||
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer}; | ||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; | ||
|
||
// Create a Resource that captures information about the entity for which telemetry is recorded. | ||
fn resource() -> Resource { | ||
Resource::from_schema_url( | ||
[ | ||
KeyValue::new(SERVICE_NAME, env!("CARGO_PKG_NAME")), | ||
KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")), | ||
KeyValue::new(DEPLOYMENT_ENVIRONMENT, "develop"), | ||
], | ||
SCHEMA_URL, | ||
) | ||
} | ||
|
||
// Construct MeterProvider for MetricsLayer | ||
fn init_meter_provider() -> MeterProvider { | ||
// Currently we could not access MeterProviderBuilder from opentelemetry_otlp | ||
// However to customize View we need MeterBuilder, so manually construct. | ||
let exporter = opentelemetry_otlp::MetricsExporter::new( | ||
TonicExporterBuilder::default(), | ||
Box::new(DefaultTemporalitySelector::new()), | ||
Box::new(DefaultAggregationSelector::new()), | ||
) | ||
.unwrap(); | ||
|
||
let reader = PeriodicReader::builder(exporter, runtime::Tokio) | ||
.with_interval(std::time::Duration::from_secs(30)) | ||
.build(); | ||
|
||
// For debugging in development | ||
let stdout_reader = PeriodicReader::builder( | ||
opentelemetry_stdout::MetricsExporter::default(), | ||
runtime::Tokio, | ||
) | ||
.build(); | ||
|
||
// Rename foo metrics to foo_named and drop key_2 attribute | ||
let view_foo = |instrument: &Instrument| -> Option<Stream> { | ||
if instrument.name == "foo" { | ||
Some( | ||
Stream::new() | ||
.name("foo_named") | ||
.allowed_attribute_keys([Key::from("key_1")]), | ||
) | ||
} else { | ||
None | ||
} | ||
}; | ||
|
||
// Set Custom histogram boundaries for baz metrics | ||
let view_baz = |instrument: &Instrument| -> Option<Stream> { | ||
if instrument.name == "baz" { | ||
Some( | ||
Stream::new() | ||
.name("baz") | ||
.aggregation(Aggregation::ExplicitBucketHistogram { | ||
boundaries: vec![0.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0], | ||
record_min_max: true, | ||
}), | ||
) | ||
} else { | ||
None | ||
} | ||
}; | ||
|
||
let meter_provider = MeterProvider::builder() | ||
.with_resource(resource()) | ||
.with_reader(reader) | ||
.with_reader(stdout_reader) | ||
.with_view(view_foo) | ||
.with_view(view_baz) | ||
.build(); | ||
|
||
global::set_meter_provider(meter_provider.clone()); | ||
|
||
meter_provider | ||
} | ||
|
||
// Construct Tracer for OpenTelemetryLayer | ||
fn init_tracer() -> Tracer { | ||
opentelemetry_otlp::new_pipeline() | ||
.tracing() | ||
.with_trace_config( | ||
opentelemetry_sdk::trace::Config::default() | ||
// Customize sampling strategy | ||
.with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased( | ||
1.0, | ||
)))) | ||
// If export trace to AWS X-Ray, you can use XrayIdGenerator | ||
.with_id_generator(RandomIdGenerator::default()) | ||
.with_resource(resource()), | ||
) | ||
.with_batch_config(BatchConfig::default()) | ||
.with_exporter(opentelemetry_otlp::new_exporter().tonic()) | ||
.install_batch(runtime::Tokio) | ||
.unwrap() | ||
} | ||
|
||
// Initialize tracing-subscriber and return OtelGuard for opentelemetry-related termination processing | ||
fn init_tracing_subscriber() -> OtelGuard { | ||
let meter_provider = init_meter_provider(); | ||
|
||
tracing_subscriber::registry() | ||
.with(tracing_subscriber::filter::LevelFilter::from_level( | ||
Level::INFO, | ||
)) | ||
.with(tracing_subscriber::fmt::layer()) | ||
.with(MetricsLayer::new(meter_provider.clone())) | ||
.with(OpenTelemetryLayer::new(init_tracer())) | ||
.init(); | ||
|
||
OtelGuard { meter_provider } | ||
} | ||
|
||
struct OtelGuard { | ||
meter_provider: MeterProvider, | ||
} | ||
|
||
impl Drop for OtelGuard { | ||
fn drop(&mut self) { | ||
if let Err(err) = self.meter_provider.shutdown() { | ||
eprintln!("{err:?}"); | ||
} | ||
opentelemetry::global::shutdown_tracer_provider(); | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let _guard = init_tracing_subscriber(); | ||
|
||
foo().await; | ||
} | ||
|
||
#[tracing::instrument] | ||
async fn foo() { | ||
tracing::info!( | ||
monotonic_counter.foo = 1_u64, | ||
key_1 = "bar", | ||
key_2 = 10, | ||
"handle foo", | ||
); | ||
|
||
tracing::info!(histogram.baz = 10, "histogram example",); | ||
} |