Skip to content

Commit 12b3161

Browse files
authored
Expose more Sentry configuration (#4352)
2 parents fa69cdc + eb0cb94 commit 12b3161

File tree

4 files changed

+118
-9
lines changed

4 files changed

+118
-9
lines changed

crates/cli/src/main.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,18 @@ async fn try_main() -> anyhow::Result<ExitCode> {
109109
// Load the base configuration files
110110
let figment = opts.figment();
111111

112-
// Telemetry config could fail to load, but that's probably OK, since the whole
113-
// config will be loaded afterwards, and crash if there is a problem.
114-
// Falling back to default.
115-
let telemetry_config = TelemetryConfig::extract(&figment).unwrap_or_default();
112+
let telemetry_config =
113+
TelemetryConfig::extract(&figment).context("Failed to load telemetry config")?;
116114

117115
// Setup Sentry
118116
let sentry = sentry::init((
119117
telemetry_config.sentry.dsn.as_deref(),
120118
sentry::ClientOptions {
121119
transport: Some(Arc::new(SentryTransportFactory::new())),
122-
traces_sample_rate: 1.0,
120+
environment: telemetry_config.sentry.environment.clone().map(Into::into),
121+
release: Some(VERSION.into()),
122+
sample_rate: telemetry_config.sentry.sample_rate.unwrap_or(1.0),
123+
traces_sample_rate: telemetry_config.sentry.traces_sample_rate.unwrap_or(0.0),
123124
auto_session_tracking: true,
124125
session_mode: sentry::SessionMode::Request,
125126
..Default::default()

crates/cli/src/telemetry.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ fn stdout_tracer_provider() -> SdkTracerProvider {
102102
.build()
103103
}
104104

105-
fn otlp_tracer_provider(endpoint: Option<&Url>) -> anyhow::Result<SdkTracerProvider> {
105+
fn otlp_tracer_provider(
106+
endpoint: Option<&Url>,
107+
sample_rate: f64,
108+
) -> anyhow::Result<SdkTracerProvider> {
106109
let mut exporter = opentelemetry_otlp::SpanExporter::builder()
107110
.with_http()
108111
.with_http_client(mas_http::reqwest_client());
@@ -119,17 +122,18 @@ fn otlp_tracer_provider(endpoint: Option<&Url>) -> anyhow::Result<SdkTracerProvi
119122
let tracer_provider = SdkTracerProvider::builder()
120123
.with_span_processor(batch_processor)
121124
.with_resource(resource())
122-
.with_sampler(Sampler::AlwaysOn)
125+
.with_sampler(Sampler::TraceIdRatioBased(sample_rate))
123126
.build();
124127

125128
Ok(tracer_provider)
126129
}
127130

128131
fn init_tracer(config: &TracingConfig) -> anyhow::Result<()> {
132+
let sample_rate = config.sample_rate.unwrap_or(1.0);
129133
let tracer_provider = match config.exporter {
130134
TracingExporterKind::None => return Ok(()),
131135
TracingExporterKind::Stdout => stdout_tracer_provider(),
132-
TracingExporterKind::Otlp => otlp_tracer_provider(config.endpoint.as_ref())?,
136+
TracingExporterKind::Otlp => otlp_tracer_provider(config.endpoint.as_ref(), sample_rate)?,
133137
};
134138
TRACER_PROVIDER
135139
.set(tracer_provider.clone())

crates/config/src/sections/telemetry.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
// Please see LICENSE in the repository root for full details.
66

77
use schemars::JsonSchema;
8-
use serde::{Deserialize, Serialize};
8+
use serde::{Deserialize, Serialize, de::Error as _};
99
use serde_with::skip_serializing_none;
1010
use url::Url;
1111

1212
use super::ConfigurationSection;
1313

14+
fn sample_rate_example() -> f64 {
15+
0.5
16+
}
17+
1418
/// Propagation format for incoming and outgoing requests
1519
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1620
#[serde(rename_all = "lowercase")]
@@ -61,6 +65,13 @@ pub struct TracingConfig {
6165
/// List of propagation formats to use for incoming and outgoing requests
6266
#[serde(default)]
6367
pub propagators: Vec<Propagator>,
68+
69+
/// Sample rate for traces
70+
///
71+
/// Defaults to `1.0` if not set.
72+
#[serde(skip_serializing_if = "Option::is_none")]
73+
#[schemars(example = "sample_rate_example", range(min = 0.0, max = 1.0))]
74+
pub sample_rate: Option<f64>,
6475
}
6576

6677
impl TracingConfig {
@@ -116,13 +127,38 @@ fn sentry_dsn_example() -> &'static str {
116127
"https://public@host:port/1"
117128
}
118129

130+
fn sentry_environment_example() -> &'static str {
131+
"production"
132+
}
133+
119134
/// Configuration related to the Sentry integration
120135
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
121136
pub struct SentryConfig {
122137
/// Sentry DSN
123138
#[schemars(url, example = "sentry_dsn_example")]
124139
#[serde(skip_serializing_if = "Option::is_none")]
125140
pub dsn: Option<String>,
141+
142+
/// Environment to use when sending events to Sentry
143+
///
144+
/// Defaults to `production` if not set.
145+
#[schemars(example = "sentry_environment_example")]
146+
#[serde(skip_serializing_if = "Option::is_none")]
147+
pub environment: Option<String>,
148+
149+
/// Sample rate for event submissions
150+
///
151+
/// Defaults to `1.0` if not set.
152+
#[serde(skip_serializing_if = "Option::is_none")]
153+
#[schemars(example = "sample_rate_example", range(min = 0.0, max = 1.0))]
154+
pub sample_rate: Option<f32>,
155+
156+
/// Sample rate for tracing transactions
157+
///
158+
/// Defaults to `0.0` if not set.
159+
#[serde(skip_serializing_if = "Option::is_none")]
160+
#[schemars(example = "sample_rate_example", range(min = 0.0, max = 1.0))]
161+
pub traces_sample_rate: Option<f32>,
126162
}
127163

128164
impl SentryConfig {
@@ -157,4 +193,35 @@ impl TelemetryConfig {
157193

158194
impl ConfigurationSection for TelemetryConfig {
159195
const PATH: Option<&'static str> = Some("telemetry");
196+
197+
fn validate(&self, _figment: &figment::Figment) -> Result<(), figment::Error> {
198+
if let Some(sample_rate) = self.sentry.sample_rate {
199+
if !(0.0..=1.0).contains(&sample_rate) {
200+
return Err(figment::error::Error::custom(
201+
"Sentry sample rate must be between 0.0 and 1.0",
202+
)
203+
.with_path("sentry.sample_rate"));
204+
}
205+
}
206+
207+
if let Some(sample_rate) = self.sentry.traces_sample_rate {
208+
if !(0.0..=1.0).contains(&sample_rate) {
209+
return Err(figment::error::Error::custom(
210+
"Sentry sample rate must be between 0.0 and 1.0",
211+
)
212+
.with_path("sentry.traces_sample_rate"));
213+
}
214+
}
215+
216+
if let Some(sample_rate) = self.tracing.sample_rate {
217+
if !(0.0..=1.0).contains(&sample_rate) {
218+
return Err(figment::error::Error::custom(
219+
"Tracing sample rate must be between 0.0 and 1.0",
220+
)
221+
.with_path("tracing.sample_rate"));
222+
}
223+
}
224+
225+
Ok(())
226+
}
160227
}

docs/config.schema.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,16 @@
12131213
"items": {
12141214
"$ref": "#/definitions/Propagator"
12151215
}
1216+
},
1217+
"sample_rate": {
1218+
"description": "Sample rate for traces\n\nDefaults to `1.0` if not set.",
1219+
"examples": [
1220+
0.5
1221+
],
1222+
"type": "number",
1223+
"format": "double",
1224+
"maximum": 1.0,
1225+
"minimum": 0.0
12161226
}
12171227
}
12181228
},
@@ -1333,6 +1343,33 @@
13331343
],
13341344
"type": "string",
13351345
"format": "uri"
1346+
},
1347+
"environment": {
1348+
"description": "Environment to use when sending events to Sentry\n\nDefaults to `production` if not set.",
1349+
"examples": [
1350+
"production"
1351+
],
1352+
"type": "string"
1353+
},
1354+
"sample_rate": {
1355+
"description": "Sample rate for event submissions\n\nDefaults to `1.0` if not set.",
1356+
"examples": [
1357+
0.5
1358+
],
1359+
"type": "number",
1360+
"format": "float",
1361+
"maximum": 1.0,
1362+
"minimum": 0.0
1363+
},
1364+
"traces_sample_rate": {
1365+
"description": "Sample rate for tracing transactions\n\nDefaults to `0.0` if not set.",
1366+
"examples": [
1367+
0.5
1368+
],
1369+
"type": "number",
1370+
"format": "float",
1371+
"maximum": 1.0,
1372+
"minimum": 0.0
13361373
}
13371374
}
13381375
},

0 commit comments

Comments
 (0)