-
Notifications
You must be signed in to change notification settings - Fork 265
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(telemetry): Add support for OTel metrics
Signed-off-by: Caleb Schoepp <caleb.schoepp@fermyon.com>
- Loading branch information
1 parent
33afee8
commit 06af58e
Showing
10 changed files
with
241 additions
and
66 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,118 @@ | ||
use std::time::Duration; | ||
|
||
use anyhow::{bail, Result}; | ||
use opentelemetry_otlp::MetricsExporterBuilder; | ||
use opentelemetry_sdk::{ | ||
metrics::{ | ||
reader::{DefaultAggregationSelector, DefaultTemporalitySelector}, | ||
PeriodicReader, SdkMeterProvider, | ||
}, | ||
resource::{EnvResourceDetector, TelemetryResourceDetector}, | ||
runtime, Resource, | ||
}; | ||
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer}; | ||
use tracing_subscriber::{filter::Filtered, layer::Layered, EnvFilter, Registry}; | ||
|
||
use crate::{detector::SpinResourceDetector, env::OtlpProtocol}; | ||
|
||
/// Constructs a layer for the tracing subscriber that sends metrics to an OTEL collector. | ||
/// | ||
/// It pulls OTEL configuration from the environment based on the variables defined | ||
/// [here](https://opentelemetry.io/docs/specs/otel/protocol/exporter/) and | ||
/// [here](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration). | ||
pub(crate) fn otel_metrics_layer(spin_version: String) -> Result<CustomMetricsLayer> { | ||
let resource = Resource::from_detectors( | ||
Duration::from_secs(5), | ||
vec![ | ||
// Set service.name from env OTEL_SERVICE_NAME > env OTEL_RESOURCE_ATTRIBUTES > spin | ||
// Set service.version from Spin metadata | ||
Box::new(SpinResourceDetector::new(spin_version)), | ||
// Sets fields from env OTEL_RESOURCE_ATTRIBUTES | ||
Box::new(EnvResourceDetector::new()), | ||
// Sets telemetry.sdk{name, language, version} | ||
Box::new(TelemetryResourceDetector), | ||
], | ||
); | ||
|
||
// This will configure the exporter based on the OTEL_EXPORTER_* environment variables. We | ||
// currently default to using the HTTP exporter but in the future we could select off of the | ||
// combination of OTEL_EXPORTER_OTLP_PROTOCOL and OTEL_EXPORTER_OTLP_TRACES_PROTOCOL to | ||
// determine whether we should use http/protobuf or grpc. | ||
let exporter_builder: MetricsExporterBuilder = match OtlpProtocol::metrics_protocol_from_env() { | ||
OtlpProtocol::Grpc => opentelemetry_otlp::new_exporter().tonic().into(), | ||
OtlpProtocol::HttpProtobuf => opentelemetry_otlp::new_exporter().http().into(), | ||
OtlpProtocol::HttpJson => bail!("http/json OTLP protocol is not supported"), | ||
}; | ||
let exporter = exporter_builder.build_metrics_exporter( | ||
Box::new(DefaultTemporalitySelector::new()), | ||
Box::new(DefaultAggregationSelector::new()), | ||
)?; | ||
|
||
let reader = PeriodicReader::builder(exporter, runtime::Tokio).build(); | ||
let meter_provider = SdkMeterProvider::builder() | ||
.with_reader(reader) | ||
.with_resource(resource) | ||
.build(); | ||
|
||
Ok(MetricsLayer::new(meter_provider)) | ||
} | ||
|
||
#[macro_export] | ||
/// Records an increment to the named counter with the given attributes. | ||
/// | ||
/// The increment may only be an i64 or f64. You must not mix types for the same metric. | ||
/// | ||
/// ```no_run | ||
/// counter!(spin.metric_name = 1, metric_attribute = "value"); | ||
/// ``` | ||
macro_rules! counter { | ||
($metric:ident $(. $suffixes:ident)* = $metric_value:expr $(, $attrs:ident=$values:expr)*) => { | ||
tracing::trace!(counter.$metric $(. $suffixes)* = $metric_value $(, $attrs=$values)*); | ||
} | ||
} | ||
|
||
#[macro_export] | ||
/// Adds an additional value to the distribution of the named histogram with the given attributes. | ||
/// | ||
/// The increment may only be an i64 or f64. You must not mix types for the same metric. | ||
/// | ||
/// ```no_run | ||
/// histogram!(spin.metric_name = 1.5, metric_attribute = "value"); | ||
/// ``` | ||
macro_rules! histogram { | ||
($metric:ident $(. $suffixes:ident)* = $metric_value:expr $(, $attrs:ident=$values:expr)*) => { | ||
tracing::trace!(histogram.$metric $(. $suffixes)* = $metric_value $(, $attrs=$values)*); | ||
} | ||
} | ||
|
||
#[macro_export] | ||
/// Records an increment to the named monotonic counter with the given attributes. | ||
/// | ||
/// The increment may only be a positive i64 or f64. You must not mix types for the same metric. | ||
/// | ||
/// ```no_run | ||
/// monotonic_counter!(spin.metric_name = 1, metric_attribute = "value"); | ||
/// ``` | ||
macro_rules! monotonic_counter { | ||
($metric:ident $(. $suffixes:ident)* = $metric_value:expr $(, $attrs:ident=$values:expr)*) => { | ||
tracing::trace!(monotonic_counter.$metric $(. $suffixes)* = $metric_value $(, $attrs=$values)*); | ||
} | ||
} | ||
|
||
pub use counter; | ||
pub use histogram; | ||
pub use monotonic_counter; | ||
|
||
/// This really large type alias is require to make the registry.with() pattern happy. | ||
type CustomMetricsLayer = MetricsLayer< | ||
Layered< | ||
Option< | ||
Filtered< | ||
OpenTelemetryLayer<Registry, opentelemetry_sdk::trace::Tracer>, | ||
EnvFilter, | ||
Registry, | ||
>, | ||
>, | ||
Registry, | ||
>, | ||
>; |
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
Oops, something went wrong.