Skip to content

Commit f80e5ce

Browse files
authored
Merge pull request #2857 from calebschoepp/telemetry-fixes
Telemetry fixes
2 parents 57a5b88 + 7ee2579 commit f80e5ce

File tree

8 files changed

+50
-19
lines changed

8 files changed

+50
-19
lines changed

crates/factor-key-value/src/host.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl key_value::HostStore for KeyValueDispatch {
8585
.await)
8686
}
8787

88-
#[instrument(name = "spin_key_value.get", skip(self, store), err(level = Level::INFO), fields(otel.kind = "client"))]
88+
#[instrument(name = "spin_key_value.get", skip(self, store, key), err(level = Level::INFO), fields(otel.kind = "client"))]
8989
async fn get(
9090
&mut self,
9191
store: Resource<key_value::Store>,
@@ -95,7 +95,7 @@ impl key_value::HostStore for KeyValueDispatch {
9595
Ok(store.get(&key).await)
9696
}
9797

98-
#[instrument(name = "spin_key_value.set", skip(self, store, value), err(level = Level::INFO), fields(otel.kind = "client"))]
98+
#[instrument(name = "spin_key_value.set", skip(self, store, key, value), err(level = Level::INFO), fields(otel.kind = "client"))]
9999
async fn set(
100100
&mut self,
101101
store: Resource<key_value::Store>,
@@ -106,7 +106,7 @@ impl key_value::HostStore for KeyValueDispatch {
106106
Ok(store.set(&key, &value).await)
107107
}
108108

109-
#[instrument(name = "spin_key_value.delete", skip(self, store), err(level = Level::INFO), fields(otel.kind = "client"))]
109+
#[instrument(name = "spin_key_value.delete", skip(self, store, key), err(level = Level::INFO), fields(otel.kind = "client"))]
110110
async fn delete(
111111
&mut self,
112112
store: Resource<key_value::Store>,
@@ -116,7 +116,7 @@ impl key_value::HostStore for KeyValueDispatch {
116116
Ok(store.delete(&key).await)
117117
}
118118

119-
#[instrument(name = "spin_key_value.exists", skip(self, store), err(level = Level::INFO), fields(otel.kind = "client"))]
119+
#[instrument(name = "spin_key_value.exists", skip(self, store, key), err(level = Level::INFO), fields(otel.kind = "client"))]
120120
async fn exists(
121121
&mut self,
122122
store: Resource<key_value::Store>,

crates/factor-outbound-mysql/src/host.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use spin_world::v1::mysql as v1;
55
use spin_world::v2::mysql::{self as v2, Connection};
66
use spin_world::v2::rdbms_types as v2_types;
77
use spin_world::v2::rdbms_types::ParameterValue;
8+
use tracing::field::Empty;
89
use tracing::{instrument, Level};
910

1011
use crate::client::Client;
@@ -38,8 +39,10 @@ impl<C: Client> v2::Host for InstanceState<C> {}
3839

3940
#[async_trait]
4041
impl<C: Client> v2::HostConnection for InstanceState<C> {
41-
#[instrument(name = "spin_outbound_mysql.open_connection", skip(self), err(level = Level::INFO), fields(otel.kind = "client", db.system = "mysql"))]
42+
#[instrument(name = "spin_outbound_mysql.open", skip(self, address), err(level = Level::INFO), fields(otel.kind = "client", db.system = "mysql", db.address = Empty, server.port = Empty, db.namespace = Empty))]
4243
async fn open(&mut self, address: String) -> Result<Resource<Connection>, v2::Error> {
44+
spin_factor_outbound_networking::record_address_fields(&address);
45+
4346
if !self
4447
.is_address_allowed(&address)
4548
.await
@@ -52,7 +55,7 @@ impl<C: Client> v2::HostConnection for InstanceState<C> {
5255
self.open_connection(&address).await
5356
}
5457

55-
#[instrument(name = "spin_outbound_mysql.execute", skip(self, connection), err(level = Level::INFO), fields(otel.kind = "client", db.system = "mysql", otel.name = statement))]
58+
#[instrument(name = "spin_outbound_mysql.execute", skip(self, connection, params), err(level = Level::INFO), fields(otel.kind = "client", db.system = "mysql", otel.name = statement))]
5659
async fn execute(
5760
&mut self,
5861
connection: Resource<Connection>,
@@ -66,7 +69,7 @@ impl<C: Client> v2::HostConnection for InstanceState<C> {
6669
.await?)
6770
}
6871

69-
#[instrument(name = "spin_outbound_mysql.query", skip(self, connection), err(level = Level::INFO), fields(otel.kind = "client", db.system = "mysql", otel.name = statement))]
72+
#[instrument(name = "spin_outbound_mysql.query", skip(self, connection, params), err(level = Level::INFO), fields(otel.kind = "client", db.system = "mysql", otel.name = statement))]
7073
async fn query(
7174
&mut self,
7275
connection: Resource<Connection>,

crates/factor-outbound-networking/src/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub use config::{
2020
};
2121

2222
pub use runtime_config::ComponentTlsConfigs;
23+
use url::Url;
2324

2425
pub type SharedFutureResult<T> = Shared<BoxFuture<'static, Result<Arc<T>, Arc<anyhow::Error>>>>;
2526

@@ -247,3 +248,22 @@ impl<F: Fn(&str, &str) + Send + Sync> DisallowedHostHandler for F {
247248
self(scheme, authority);
248249
}
249250
}
251+
252+
/// Records the address host, port, and database as fields on the current tracing span.
253+
///
254+
/// This should only be called from within a function that has been instrumented with a span.
255+
///
256+
/// The following fields must be pre-declared as empty on the span or they will not show up.
257+
/// ```
258+
/// use tracing::field::Empty;
259+
/// #[tracing::instrument(fields(db.address = Empty, server.port = Empty, db.namespace = Empty))]
260+
/// fn open() {}
261+
/// ```
262+
pub fn record_address_fields(address: &str) {
263+
if let Ok(url) = Url::parse(address) {
264+
let span = tracing::Span::current();
265+
span.record("db.address", url.host_str().unwrap_or_default());
266+
span.record("server.port", url.port().unwrap_or_default());
267+
span.record("db.namespace", url.path().trim_start_matches('/'));
268+
}
269+
}

crates/factor-outbound-pg/src/host.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use spin_world::v1::rdbms_types as v1_types;
55
use spin_world::v2::postgres::{self as v2, Connection};
66
use spin_world::v2::rdbms_types;
77
use spin_world::v2::rdbms_types::{ParameterValue, RowSet};
8+
use tracing::field::Empty;
89
use tracing::instrument;
910
use tracing::Level;
1011

@@ -63,8 +64,10 @@ impl<C: Send + Sync + Client> v2::Host for InstanceState<C> {}
6364

6465
#[async_trait]
6566
impl<C: Send + Sync + Client> v2::HostConnection for InstanceState<C> {
66-
#[instrument(name = "spin_outbound_pg.open_connection", skip(self), err(level = Level::INFO), fields(otel.kind = "client", db.system = "postgresql"))]
67+
#[instrument(name = "spin_outbound_pg.open", skip(self, address), err(level = Level::INFO), fields(otel.kind = "client", db.system = "postgresql", db.address = Empty, server.port = Empty, db.namespace = Empty))]
6768
async fn open(&mut self, address: String) -> Result<Resource<Connection>, v2::Error> {
69+
spin_factor_outbound_networking::record_address_fields(&address);
70+
6871
if !self
6972
.is_address_allowed(&address)
7073
.await
@@ -77,7 +80,7 @@ impl<C: Send + Sync + Client> v2::HostConnection for InstanceState<C> {
7780
self.open_connection(&address).await
7881
}
7982

80-
#[instrument(name = "spin_outbound_pg.execute", skip(self, connection), err(level = Level::INFO), fields(otel.kind = "client", db.system = "postgresql", otel.name = statement))]
83+
#[instrument(name = "spin_outbound_pg.execute", skip(self, connection, params), err(level = Level::INFO), fields(otel.kind = "client", db.system = "postgresql", otel.name = statement))]
8184
async fn execute(
8285
&mut self,
8386
connection: Resource<Connection>,
@@ -91,7 +94,7 @@ impl<C: Send + Sync + Client> v2::HostConnection for InstanceState<C> {
9194
.await?)
9295
}
9396

94-
#[instrument(name = "spin_outbound_pg.query", skip(self, connection), err(level = Level::INFO), fields(otel.kind = "client", db.system = "postgresql", otel.name = statement))]
97+
#[instrument(name = "spin_outbound_pg.query", skip(self, connection, params), err(level = Level::INFO), fields(otel.kind = "client", db.system = "postgresql", otel.name = statement))]
9598
async fn query(
9699
&mut self,
97100
connection: Resource<Connection>,

crates/factor-outbound-redis/src/host.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use spin_world::v1::{redis as v1, redis_types};
66
use spin_world::v2::redis::{
77
self as v2, Connection as RedisConnection, Error, RedisParameter, RedisResult,
88
};
9+
use tracing::field::Empty;
910
use tracing::{instrument, Level};
1011

1112
pub struct InstanceState {
@@ -53,8 +54,10 @@ impl v2::Host for crate::InstanceState {
5354

5455
#[async_trait]
5556
impl v2::HostConnection for crate::InstanceState {
56-
#[instrument(name = "spin_outbound_redis.open_connection", skip(self), err(level = Level::INFO), fields(otel.kind = "client", db.system = "redis"))]
57+
#[instrument(name = "spin_outbound_redis.open_connection", skip(self, address), err(level = Level::INFO), fields(otel.kind = "client", db.system = "redis", db.address = Empty, server.port = Empty, db.namespace = Empty))]
5758
async fn open(&mut self, address: String) -> Result<Resource<RedisConnection>, Error> {
59+
spin_factor_outbound_networking::record_address_fields(&address);
60+
5861
if !self
5962
.is_address_allowed(&address)
6063
.await

crates/factor-sqlite/src/host.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl v2::HostConnection for InstanceState {
8383
.map(Resource::new_own)
8484
}
8585

86-
#[instrument(name = "spin_sqlite.execute", skip(self, connection), err(level = Level::INFO), fields(otel.kind = "client", db.system = "sqlite", otel.name = query, sqlite.backend = Empty))]
86+
#[instrument(name = "spin_sqlite.execute", skip(self, connection, parameters), err(level = Level::INFO), fields(otel.kind = "client", db.system = "sqlite", otel.name = query, sqlite.backend = Empty))]
8787
async fn execute(
8888
&mut self,
8989
connection: Resource<v2::Connection>,

crates/telemetry/src/metrics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::time::Duration;
22

33
use anyhow::{bail, Result};
4+
use opentelemetry::global;
45
use opentelemetry_otlp::MetricsExporterBuilder;
56
use opentelemetry_sdk::{
67
metrics::{
@@ -57,6 +58,8 @@ pub(crate) fn otel_metrics_layer<S: Subscriber + for<'span> LookupSpan<'span>>(
5758
.with_resource(resource)
5859
.build();
5960

61+
global::set_meter_provider(meter_provider.clone());
62+
6063
Ok(MetricsLayer::new(meter_provider))
6164
}
6265

crates/telemetry/src/traces.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::time::Duration;
22

33
use anyhow::bail;
4-
use opentelemetry::trace::TracerProvider;
4+
use opentelemetry::{global, trace::TracerProvider};
55
use opentelemetry_otlp::SpanExporterBuilder;
66
use opentelemetry_sdk::{
77
resource::{EnvResourceDetector, TelemetryResourceDetector},
@@ -34,22 +34,21 @@ pub(crate) fn otel_tracing_layer<S: Subscriber + for<'span> LookupSpan<'span>>(
3434
],
3535
);
3636

37-
// This will configure the exporter based on the OTEL_EXPORTER_* environment variables. We
38-
// currently default to using the HTTP exporter but in the future we could select off of the
39-
// combination of OTEL_EXPORTER_OTLP_PROTOCOL and OTEL_EXPORTER_OTLP_TRACES_PROTOCOL to
40-
// determine whether we should use http/protobuf or grpc.
41-
let exporter: SpanExporterBuilder = match OtlpProtocol::traces_protocol_from_env() {
37+
// This will configure the exporter based on the OTEL_EXPORTER_* environment variables.
38+
let exporter_builder: SpanExporterBuilder = match OtlpProtocol::traces_protocol_from_env() {
4239
OtlpProtocol::Grpc => opentelemetry_otlp::new_exporter().tonic().into(),
4340
OtlpProtocol::HttpProtobuf => opentelemetry_otlp::new_exporter().http().into(),
4441
OtlpProtocol::HttpJson => bail!("http/json OTLP protocol is not supported"),
4542
};
4643

4744
let tracer_provider = opentelemetry_otlp::new_pipeline()
4845
.tracing()
49-
.with_exporter(exporter)
46+
.with_exporter(exporter_builder)
5047
.with_trace_config(opentelemetry_sdk::trace::Config::default().with_resource(resource))
5148
.install_batch(opentelemetry_sdk::runtime::Tokio)?;
5249

50+
global::set_tracer_provider(tracer_provider.clone());
51+
5352
let env_filter = match EnvFilter::try_from_env("SPIN_OTEL_TRACING_LEVEL") {
5453
Ok(filter) => filter,
5554
// If it isn't set or it fails to parse default to info

0 commit comments

Comments
 (0)