Skip to content

Commit

Permalink
Merge pull request #2463 from calebschoepp/grpc-otel
Browse files Browse the repository at this point in the history
feat(telemetry): Make telemetry support http/protobuf protocol in addition to grpc protocol
  • Loading branch information
calebschoepp authored Apr 19, 2024
2 parents 63972c2 + 0992503 commit 19c3017
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 30 deletions.
85 changes: 85 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/telemetry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ http0 = { version = "0.2.9", package = "http" }
http1 = { version = "1.0.0", package = "http" }
opentelemetry = { version = "0.22.0", features = [ "metrics", "trace"] }
opentelemetry_sdk = { version = "0.22.1", features = ["rt-tokio"] }
opentelemetry-otlp = { version = "0.15.0", default_features=false, features = ["http-proto", "trace", "http", "reqwest-client", "metrics"] }
opentelemetry-otlp = { version = "0.15.0", default_features=false, features = ["http-proto", "trace", "http", "reqwest-client", "metrics", "grpc-tonic"] }
opentelemetry-semantic-conventions = "0.14.0"
tracing = { version = "0.1.37", features = ["log"] }
tracing-appender = "0.2.2"
Expand Down
48 changes: 48 additions & 0 deletions crates/telemetry/src/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// Returns a boolean indicating if the OTEL layer should be enabled.
///
/// It is considered enabled if any of the following environment variables are set and not empty:
/// - `OTEL_EXPORTER_OTLP_ENDPOINT`
/// - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`
/// - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`
///
/// Note that this is overridden if OTEL_SDK_DISABLED is set and not empty.
pub(crate) fn otel_enabled() -> bool {
const ENABLING_VARS: &[&str] = &[
"OTEL_EXPORTER_OTLP_ENDPOINT",
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
];
ENABLING_VARS
.iter()
.any(|key| std::env::var_os(key).is_some_and(|val| !val.is_empty()))
}

/// Returns a boolean indicating if the OTEL SDK should be disabled for all signals.
///
/// It is considered disabled if the environment variable `OTEL_SDK_DISABLED` is set and not empty.
pub(crate) fn otel_sdk_disabled() -> bool {
std::env::var_os("OTEL_SDK_DISABLED").is_some_and(|val| !val.is_empty())
}

/// The protocol to use for OTLP exporter.
pub(crate) enum OtlpProtocol {
Grpc,
HttpProtobuf,
HttpJson,
}

impl OtlpProtocol {
/// Returns the protocol to be used for exporting traces as defined by the environment.
pub(crate) fn traces_protocol_from_env() -> Self {
let trace_protocol = std::env::var("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL");
let general_protocol = std::env::var("OTEL_EXPORTER_OTLP_PROTOCOL");
let protocol = trace_protocol.unwrap_or(general_protocol.unwrap_or_default());

match protocol.as_str() {
"grpc" => Self::Grpc,
"http/protobuf" => Self::HttpProtobuf,
"http/json" => Self::HttpJson,
_ => Self::HttpProtobuf,
}
}
}
29 changes: 3 additions & 26 deletions crates/telemetry/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::io::IsTerminal;

use env::otel_enabled;
use env::otel_sdk_disabled;
use opentelemetry_sdk::propagation::TraceContextPropagator;
use tracing_subscriber::{fmt, prelude::*, registry, EnvFilter, Layer};

pub mod detector;
mod env;
mod propagation;
mod traces;

Expand Down Expand Up @@ -48,32 +51,6 @@ pub fn init(spin_version: String) -> anyhow::Result<ShutdownGuard> {
Ok(ShutdownGuard)
}

/// Returns a boolean indicating if the OTEL layer should be enabled.
///
/// It is considered enabled if any of the following environment variables are set and not empty:
/// - `OTEL_EXPORTER_OTLP_ENDPOINT`
/// - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`
/// - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`
///
/// Note that this is overridden if OTEL_SDK_DISABLED is set and not empty.
fn otel_enabled() -> bool {
const ENABLING_VARS: &[&str] = &[
"OTEL_EXPORTER_OTLP_ENDPOINT",
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
];
ENABLING_VARS
.iter()
.any(|key| std::env::var_os(key).is_some_and(|val| !val.is_empty()))
}

/// Returns a boolean indicating if the OTEL SDK should be disabled for all signals.
///
/// It is considered disabled if the environment variable `OTEL_SDK_DISABLED` is set and not empty.
fn otel_sdk_disabled() -> bool {
std::env::var_os("OTEL_SDK_DISABLED").is_some_and(|val| !val.is_empty())
}

fn otel_error_handler(err: opentelemetry::global::Error) {
static FIRST_OTEL_ERROR: std::sync::Once = std::sync::Once::new();
FIRST_OTEL_ERROR.call_once(|| {
Expand Down
16 changes: 13 additions & 3 deletions crates/telemetry/src/traces.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::time::Duration;

use opentelemetry_otlp::WithExportConfig;
use anyhow::bail;
use opentelemetry_otlp::{SpanExporterBuilder, WithExportConfig};
use opentelemetry_otlp::{OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT};
use opentelemetry_sdk::{
resource::{EnvResourceDetector, TelemetryResourceDetector},
Expand All @@ -11,6 +12,7 @@ use tracing_opentelemetry::OpenTelemetryLayer;
use tracing_subscriber::{EnvFilter, Layer, Registry};

use crate::detector::SpinResourceDetector;
use crate::env::OtlpProtocol;

/// Constructs a layer for the tracing subscriber that sends spans to an OTEL collector.
///
Expand Down Expand Up @@ -39,9 +41,17 @@ pub(crate) fn otel_tracing_layer(
// 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 mut exporter = opentelemetry_otlp::new_exporter().http();
let mut exporter: SpanExporterBuilder = match OtlpProtocol::traces_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"),
};
if let Some(endpoint) = fix_endpoint_bug() {
exporter = exporter.with_endpoint(endpoint);
match exporter {
SpanExporterBuilder::Tonic(inner) => exporter = inner.with_endpoint(endpoint).into(),
SpanExporterBuilder::Http(inner) => exporter = inner.with_endpoint(endpoint).into(),
_ => {}
}
}

let tracer = opentelemetry_otlp::new_pipeline()
Expand Down
Loading

0 comments on commit 19c3017

Please sign in to comment.