Skip to content

Commit 5376867

Browse files
authored
feat(common): generic otel config (#2086)
* feat(common): generic otel config * nit(runtime): better warn log when otel enabled
1 parent 247e9c6 commit 5376867

File tree

3 files changed

+87
-5
lines changed

3 files changed

+87
-5
lines changed

common/src/models/telemetry.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub struct TelemetryConfigResponse {
2828
datadog: Option<TelemetrySinkStatus>,
2929
grafana_cloud: Option<TelemetrySinkStatus>,
3030
logfire: Option<TelemetrySinkStatus>,
31+
generic: Option<TelemetrySinkStatus>,
3132
}
3233

3334
impl From<Vec<TelemetrySinkConfig>> for TelemetryConfigResponse {
@@ -48,6 +49,9 @@ impl From<Vec<TelemetrySinkConfig>> for TelemetryConfigResponse {
4849
TelemetrySinkConfig::Logfire(_) => {
4950
instance.logfire = Some(TelemetrySinkStatus { enabled: true })
5051
}
52+
TelemetrySinkConfig::GenericOtel(_) => {
53+
instance.generic = Some(TelemetrySinkStatus { enabled: true })
54+
}
5155
TelemetrySinkConfig::Debug(_) => {}
5256
}
5357
}
@@ -95,6 +99,9 @@ pub enum TelemetrySinkConfig {
9599
/// [Logfire](https://logfire.pydantic.dev/docs/how-to-guides/alternative-clients/)
96100
Logfire(LogfireConfig),
97101

102+
/// Generic config for Otel sinks that only need a host and Bearer token
103+
GenericOtel(GenericOtelConfig),
104+
98105
/// Internal Debugging
99106
#[doc(hidden)]
100107
#[typeshare(skip)]
@@ -204,6 +211,33 @@ impl Default for LogfireConfig {
204211
}
205212
}
206213

214+
#[derive(Eq, Clone, PartialEq, Serialize, Deserialize)]
215+
#[cfg_attr(feature = "integration-tests", derive(Debug))]
216+
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
217+
#[typeshare::typeshare]
218+
pub struct GenericOtelConfig {
219+
pub endpoint: String,
220+
pub bearer_token: String,
221+
pub grpc: bool,
222+
pub logs: bool,
223+
pub traces: bool,
224+
pub metrics: bool,
225+
}
226+
227+
#[cfg(any(test, feature = "integration-tests"))]
228+
impl Default for GenericOtelConfig {
229+
fn default() -> Self {
230+
Self {
231+
endpoint: "https://host.host/".into(),
232+
bearer_token: "bearer".into(),
233+
grpc: true,
234+
logs: true,
235+
traces: true,
236+
metrics: true,
237+
}
238+
}
239+
}
240+
207241
#[cfg(feature = "integration-tests")]
208242
impl From<BetterstackConfig> for TelemetrySinkConfig {
209243
fn from(value: BetterstackConfig) -> Self {
@@ -232,6 +266,13 @@ impl From<LogfireConfig> for TelemetrySinkConfig {
232266
}
233267
}
234268

269+
#[cfg(feature = "integration-tests")]
270+
impl From<GenericOtelConfig> for TelemetrySinkConfig {
271+
fn from(value: GenericOtelConfig) -> Self {
272+
TelemetrySinkConfig::GenericOtel(value)
273+
}
274+
}
275+
235276
#[cfg(feature = "integration-tests")]
236277
impl std::str::FromStr for TelemetrySinkConfig {
237278
type Err = serde_json::Error;
@@ -273,6 +314,15 @@ impl std::str::FromStr for TelemetrySinkConfig {
273314
"cannot deserialize config as valid Logfire configuration",
274315
)
275316
}))
317+
.or(serde_json::from_str::<GenericOtelConfig>(config)
318+
.map(Self::from)
319+
.inspect_err(|error| {
320+
tracing::debug!(
321+
%config,
322+
%error,
323+
"cannot deserialize config as valid Generic configuration",
324+
)
325+
}))
276326
.map_err(|_| {
277327
<serde_json::Error as serde::de::Error>::custom(format!(
278328
"configuration does not match any known external telemetry sink: {}",
@@ -309,6 +359,13 @@ mod tests {
309359
assert_eq!("logfire", sink.as_ref());
310360
assert_eq!("project::telemetry::logfire::config", sink.as_db_type());
311361
}
362+
sink @ TelemetrySinkConfig::GenericOtel(_) => {
363+
assert_eq!("generic_otel", sink.as_ref());
364+
assert_eq!(
365+
"project::telemetry::generic_otel::config",
366+
sink.as_db_type()
367+
);
368+
}
312369
sink @ TelemetrySinkConfig::Debug(_) => {
313370
assert_eq!("debug", sink.as_ref());
314371
assert_eq!("project::telemetry::debug::config", sink.as_db_type());
@@ -346,6 +403,13 @@ mod tests {
346403
serde_json::to_string(&discriminant).unwrap()
347404
);
348405
}
406+
discriminant @ TelemetrySinkConfigDiscriminants::GenericOtel => {
407+
assert_eq!("generic_otel", discriminant.as_ref());
408+
assert_eq!(
409+
r#""generic_otel""#,
410+
serde_json::to_string(&discriminant).unwrap()
411+
);
412+
}
349413
discriminant @ TelemetrySinkConfigDiscriminants::Debug => {
350414
assert_eq!("debug", discriminant.as_ref());
351415
assert_eq!(r#""debug""#, serde_json::to_string(&discriminant).unwrap());

common/types.ts

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/src/start.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,19 @@ pub async fn start(
5858
}),
5959
)
6060
.init();
61+
tracing::warn!(
62+
"Default tracing subscriber initialized (https://docs.shuttle.dev/docs/logs)"
63+
);
6164
}
6265

6366
#[cfg(feature = "setup-otel-exporter")]
64-
let _guard = crate::telemetry::init_tracing_subscriber(crate_name, package_version);
65-
66-
#[cfg(any(feature = "setup-tracing", feature = "setup-otel-exporter"))]
67-
tracing::warn!("Default tracing subscriber initialized (https://docs.shuttle.dev/docs/logs)");
67+
let _guard = {
68+
let guard = crate::telemetry::init_tracing_subscriber(crate_name, package_version);
69+
tracing::warn!(
70+
"Default tracing subscriber with otel exporter initialized (https://docs.shuttle.dev/docs/telemetry)"
71+
);
72+
guard
73+
};
6874

6975
rt::start(loader, runner).await
7076
}

0 commit comments

Comments
 (0)