Skip to content

Commit 5bee630

Browse files
authored
add support for inferring token from region (#36)
1 parent 367c983 commit 5bee630

File tree

5 files changed

+69
-23
lines changed

5 files changed

+69
-23
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ thiserror = "2"
3333
serde = { version = "1", features = ["derive"], optional = true }
3434
nu-ansi-term = "0.50.1"
3535
chrono = "0.4.39"
36+
regex = "1.11.1"
3637

3738
[dev-dependencies]
3839
async-trait = "0.1.88"

examples/basic.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ static BASIC_COUNTER: LazyLock<Counter<u64>> = LazyLock::new(|| {
1212
});
1313

1414
fn main() -> Result<(), Box<dyn std::error::Error>> {
15-
let shutdown_handler = logfire::configure().install_panic_handler().finish()?;
15+
let shutdown_handler = logfire::configure()
16+
.install_panic_handler()
17+
.with_console(None)
18+
.finish()?;
1619

1720
logfire::info!("Hello, world!");
1821

src/config.rs

+39-12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use opentelemetry_sdk::{
1212
metrics::reader::MetricReader,
1313
trace::{IdGenerator, SpanProcessor},
1414
};
15+
use regex::Regex;
1516

1617
use crate::ConfigureError;
1718

@@ -168,9 +169,10 @@ impl std::fmt::Debug for Target {
168169
}
169170

170171
/// Options primarily used for testing by Logfire developers.
172+
#[derive(Default)]
171173
pub struct AdvancedOptions {
172174
/// Root URL for the Logfire API.
173-
pub(crate) base_url: String,
175+
pub(crate) base_url: Option<String>,
174176
/// Generator for trace and span IDs.
175177
pub(crate) id_generator: Option<BoxedIdGenerator>,
176178
/// Resource to override default resource detection.
@@ -186,21 +188,11 @@ pub struct AdvancedOptions {
186188
// pub log_record_processors: Vec<Box<dyn LogRecordProcessor>>,
187189
}
188190

189-
impl Default for AdvancedOptions {
190-
fn default() -> Self {
191-
AdvancedOptions {
192-
base_url: "https://logfire-api.pydantic.dev".to_string(),
193-
id_generator: None,
194-
resource: None,
195-
}
196-
}
197-
}
198-
199191
impl AdvancedOptions {
200192
/// Set the base URL for the Logfire API.
201193
#[must_use]
202194
pub fn with_base_url<T: AsRef<str>>(mut self, base_url: T) -> Self {
203-
self.base_url = base_url.as_ref().into();
195+
self.base_url = Some(base_url.as_ref().into());
204196
self
205197
}
206198

@@ -222,6 +214,41 @@ impl AdvancedOptions {
222214
}
223215
}
224216

217+
struct RegionData {
218+
base_url: &'static str,
219+
#[expect(dead_code)] // not used for the moment
220+
gcp_region: &'static str,
221+
}
222+
223+
const US_REGION: RegionData = RegionData {
224+
base_url: "https://logfire-us.pydantic.dev",
225+
gcp_region: "us-east4",
226+
};
227+
228+
const EU_REGION: RegionData = RegionData {
229+
base_url: "https://logfire-eu.pydantic.dev",
230+
gcp_region: "europe-west4",
231+
};
232+
233+
/// Get the base API URL from the token's region.
234+
pub(crate) fn get_base_url_from_token(token: &str) -> &'static str {
235+
let pydantic_logfire_token_pattern = Regex::new(
236+
r"^(?P<safe_part>pylf_v(?P<version>[0-9]+)_(?P<region>[a-z]+)_)(?P<token>[a-zA-Z0-9]+)$",
237+
)
238+
.expect("token regex is known to be valid");
239+
240+
#[expect(clippy::wildcard_in_or_patterns, reason = "being explicit about us")]
241+
match pydantic_logfire_token_pattern
242+
.captures(token)
243+
.and_then(|captures| captures.name("region"))
244+
.map(|region| region.as_str())
245+
{
246+
Some("eu") => EU_REGION.base_url,
247+
// fallback to US region if the token / region is not recognized
248+
Some("us") | _ => US_REGION.base_url,
249+
}
250+
}
251+
225252
/// Configuration of metrics.
226253
///
227254
/// This only has one option for now, but it's a place to add more related options in the future.

src/lib.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ use std::sync::{Arc, Once};
103103
use std::{backtrace::Backtrace, env::VarError, sync::OnceLock, time::Duration};
104104

105105
use bridges::tracing::LogfireTracingPendingSpanNotSentLayer;
106+
use config::get_base_url_from_token;
106107
use opentelemetry::trace::TracerProvider;
107108
use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider};
108109
use opentelemetry_sdk::trace::{
@@ -501,17 +502,29 @@ impl LogfireConfigBuilder {
501502

502503
let mut http_headers: Option<HashMap<String, String>> = None;
503504

504-
if send_to_logfire {
505+
let logfire_base_url = if send_to_logfire {
505506
let Some(token) = token else {
506507
return Err(ConfigureError::TokenRequired);
507508
};
509+
508510
http_headers
509511
.get_or_insert_default()
510512
.insert("Authorization".to_string(), format!("Bearer {token}"));
511513

514+
Some(
515+
advanced_options
516+
.base_url
517+
.as_deref()
518+
.unwrap_or_else(|| get_base_url_from_token(&token)),
519+
)
520+
} else {
521+
None
522+
};
523+
524+
if let Some(logfire_base_url) = logfire_base_url {
512525
tracer_provider_builder = tracer_provider_builder.with_span_processor(
513526
BatchSpanProcessor::builder(exporters::span_exporter(
514-
&advanced_options.base_url,
527+
logfire_base_url,
515528
http_headers.clone(),
516529
)?)
517530
.with_batch_config(
@@ -570,14 +583,16 @@ impl LogfireConfigBuilder {
570583

571584
let mut meter_provider_builder = SdkMeterProvider::builder();
572585

573-
if send_to_logfire && self.enable_metrics {
574-
let metric_reader = PeriodicReader::builder(exporters::metric_exporter(
575-
&advanced_options.base_url,
576-
http_headers,
577-
)?)
578-
.build();
586+
if let Some(logfire_base_url) = logfire_base_url {
587+
if self.enable_metrics {
588+
let metric_reader = PeriodicReader::builder(exporters::metric_exporter(
589+
logfire_base_url,
590+
http_headers,
591+
)?)
592+
.build();
579593

580-
meter_provider_builder = meter_provider_builder.with_reader(metric_reader);
594+
meter_provider_builder = meter_provider_builder.with_reader(metric_reader);
595+
}
581596
};
582597

583598
if let Some(metrics) = self.metrics.filter(|_| self.enable_metrics) {

tests/test_basic_exports.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ fn test_basic_span() {
10321032
"code.lineno",
10331033
),
10341034
value: I64(
1035-
675,
1035+
690,
10361036
),
10371037
},
10381038
KeyValue {

0 commit comments

Comments
 (0)