Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,716 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::config::storage::Storage;
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use hyper::HeaderMap;
|
||||
use opentelemetry::{InstrumentationScope, KeyValue};
|
||||
use opentelemetry_otlp::{
|
||||
LogExporter, MetricExporter, SpanExporter, WithExportConfig, WithHttpConfig,
|
||||
};
|
||||
use opentelemetry_sdk::{Resource, metrics::Temporality};
|
||||
use opentelemetry_semantic_conventions::resource::SERVICE_VERSION;
|
||||
use registry::schema::{
|
||||
enums::{EventPolicy, LogRotateFrequency},
|
||||
prelude::ObjectType,
|
||||
structs::{self, EventTracingLevel, MetricsPrometheus, Tracer, WebHook},
|
||||
};
|
||||
use std::{collections::HashMap, str::FromStr, sync::Arc, time::Duration};
|
||||
use store::registry::bootstrap::Bootstrap;
|
||||
use trc::{EventType, Level, MetricType, TelemetryEvent, ipc::subscriber::Interests};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TelemetrySubscriber {
|
||||
pub id: String,
|
||||
pub interests: Interests,
|
||||
pub typ: TelemetrySubscriberType,
|
||||
pub lossy: bool,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug)]
|
||||
pub enum TelemetrySubscriberType {
|
||||
ConsoleTracer(ConsoleTracer),
|
||||
LogTracer(LogTracer),
|
||||
OtelTracer(OtelTracer),
|
||||
Webhook(WebhookTracer),
|
||||
#[cfg(unix)]
|
||||
JournalTracer(crate::telemetry::tracers::journald::Subscriber),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OtelTracer {
|
||||
pub span_exporter: SpanExporter,
|
||||
pub span_exporter_enable: bool,
|
||||
pub log_exporter: LogExporter,
|
||||
pub log_exporter_enable: bool,
|
||||
pub throttle: Duration,
|
||||
}
|
||||
|
||||
pub struct OtelMetrics {
|
||||
pub resource: Resource,
|
||||
pub instrumentation: InstrumentationScope,
|
||||
pub exporter: MetricExporter,
|
||||
pub interval: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConsoleTracer {
|
||||
pub ansi: bool,
|
||||
pub multiline: bool,
|
||||
pub buffered: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LogTracer {
|
||||
pub path: String,
|
||||
pub prefix: String,
|
||||
pub rotate: RotationStrategy,
|
||||
pub ansi: bool,
|
||||
pub multiline: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WebhookTracer {
|
||||
pub url: String,
|
||||
pub key: String,
|
||||
pub timeout: Duration,
|
||||
pub throttle: Duration,
|
||||
pub discard_after: Duration,
|
||||
pub tls_allow_invalid_certs: bool,
|
||||
pub headers: HeaderMap,
|
||||
pub client: reqwest::Client,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RotationStrategy {
|
||||
Daily,
|
||||
Hourly,
|
||||
Minutely,
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Telemetry {
|
||||
pub tracers: Tracers,
|
||||
pub metrics: Interests,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tracers {
|
||||
pub interests: Interests,
|
||||
pub levels: AHashMap<EventType, Level>,
|
||||
pub subscribers: Vec<TelemetrySubscriber>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Metrics {
|
||||
pub prometheus: Option<PrometheusMetrics>,
|
||||
pub otel: Option<Arc<OtelMetrics>>,
|
||||
pub log_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PrometheusMetrics {
|
||||
pub auth: Option<String>,
|
||||
}
|
||||
|
||||
impl Telemetry {
|
||||
pub async fn parse(bp: &mut Bootstrap, storage: &Storage) -> Self {
|
||||
let mut telemetry = Telemetry {
|
||||
tracers: Tracers::parse(bp, storage).await,
|
||||
metrics: Interests::default(),
|
||||
};
|
||||
|
||||
// Parse metrics
|
||||
let metrics = bp.setting_infallible::<structs::Metrics>().await;
|
||||
apply_metrics(metrics.metrics, metrics.metrics_policy, |metric_type| {
|
||||
let event_id = metric_type.event_id();
|
||||
if event_id != usize::MAX {
|
||||
telemetry.metrics.set(event_id);
|
||||
}
|
||||
});
|
||||
|
||||
telemetry
|
||||
}
|
||||
}
|
||||
|
||||
impl Tracers {
|
||||
pub async fn parse(bp: &mut Bootstrap, storage: &Storage) -> Self {
|
||||
let mut custom_levels = AHashMap::new();
|
||||
let mut tracers: Vec<TelemetrySubscriber> = Vec::new();
|
||||
let mut global_interests = Interests::default();
|
||||
|
||||
if !bp.registry.is_recovery_mode() {
|
||||
// Parse custom logging levels
|
||||
for level in bp.list_infallible::<EventTracingLevel>().await {
|
||||
custom_levels.insert(level.object.event, level.object.level.into());
|
||||
}
|
||||
|
||||
// Parse tracers
|
||||
for tracer in bp.list_infallible::<Tracer>().await {
|
||||
let id = tracer.id;
|
||||
let tracer = tracer.object;
|
||||
let level;
|
||||
let lossy;
|
||||
let events;
|
||||
let events_policy;
|
||||
let enable;
|
||||
|
||||
let typ = match tracer {
|
||||
Tracer::Log(tracer) if tracer.enable => {
|
||||
level = Level::from(tracer.level);
|
||||
lossy = tracer.lossy;
|
||||
events = tracer.events;
|
||||
events_policy = tracer.events_policy;
|
||||
enable = tracer.enable;
|
||||
|
||||
TelemetrySubscriberType::LogTracer(LogTracer {
|
||||
path: tracer.path,
|
||||
prefix: tracer.prefix,
|
||||
rotate: match tracer.rotate {
|
||||
LogRotateFrequency::Daily => RotationStrategy::Daily,
|
||||
LogRotateFrequency::Hourly => RotationStrategy::Hourly,
|
||||
LogRotateFrequency::Minutely => RotationStrategy::Minutely,
|
||||
LogRotateFrequency::Never => RotationStrategy::Never,
|
||||
},
|
||||
ansi: tracer.ansi,
|
||||
multiline: tracer.multiline,
|
||||
})
|
||||
}
|
||||
Tracer::Stdout(tracer) if tracer.enable => {
|
||||
level = Level::from(tracer.level);
|
||||
lossy = tracer.lossy;
|
||||
events = tracer.events;
|
||||
events_policy = tracer.events_policy;
|
||||
enable = tracer.enable;
|
||||
|
||||
if !tracers
|
||||
.iter()
|
||||
.any(|t| matches!(t.typ, TelemetrySubscriberType::ConsoleTracer(_)))
|
||||
{
|
||||
TelemetrySubscriberType::ConsoleTracer(ConsoleTracer {
|
||||
ansi: tracer.ansi,
|
||||
multiline: tracer.multiline,
|
||||
buffered: tracer.buffered,
|
||||
})
|
||||
} else {
|
||||
bp.build_error(id, "Only one console tracer is allowed");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Tracer::Journal(tracer) if tracer.enable => {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
level = Level::from(tracer.level);
|
||||
lossy = tracer.lossy;
|
||||
events = tracer.events;
|
||||
events_policy = tracer.events_policy;
|
||||
enable = tracer.enable;
|
||||
|
||||
if !tracers
|
||||
.iter()
|
||||
.any(|t| matches!(t.typ, TelemetrySubscriberType::JournalTracer(_)))
|
||||
{
|
||||
match crate::telemetry::tracers::journald::Subscriber::new() {
|
||||
Ok(subscriber) => {
|
||||
TelemetrySubscriberType::JournalTracer(subscriber)
|
||||
}
|
||||
Err(e) => {
|
||||
bp.build_error(
|
||||
id,
|
||||
format!("Failed to create journald subscriber: {e}"),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bp.build_error(id, "Only one journal tracer is allowed");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
bp.build_error(id, "Journald is only available on Unix systems.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Tracer::OtelHttp(tracer) if tracer.enable => {
|
||||
level = Level::from(tracer.level);
|
||||
lossy = tracer.lossy;
|
||||
events = tracer.events;
|
||||
events_policy = tracer.events_policy;
|
||||
enable = tracer.enable;
|
||||
|
||||
let headers = match tracer
|
||||
.http_auth
|
||||
.build_headers(tracer.http_headers, None)
|
||||
.await
|
||||
{
|
||||
Ok(headers) => headers
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| {
|
||||
k.and_then(|k| {
|
||||
Some((k.to_string(), v.to_str().ok()?.to_string()))
|
||||
})
|
||||
})
|
||||
.collect::<HashMap<String, String>>(),
|
||||
Err(err) => {
|
||||
bp.build_error(
|
||||
id,
|
||||
format!("Failed to build OpenTelemetry HTTP headers: {err}"),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut span_exporter = SpanExporter::builder()
|
||||
.with_http()
|
||||
.with_endpoint(tracer.endpoint.clone())
|
||||
.with_timeout(tracer.timeout.into_inner());
|
||||
let mut log_exporter = LogExporter::builder()
|
||||
.with_http()
|
||||
.with_endpoint(tracer.endpoint)
|
||||
.with_timeout(tracer.timeout.into_inner());
|
||||
if !headers.is_empty() {
|
||||
span_exporter = span_exporter.with_headers(headers.clone());
|
||||
log_exporter = log_exporter.with_headers(headers);
|
||||
}
|
||||
|
||||
match (span_exporter.build(), log_exporter.build()) {
|
||||
(Ok(span_exporter), Ok(log_exporter)) => {
|
||||
TelemetrySubscriberType::OtelTracer(OtelTracer {
|
||||
span_exporter,
|
||||
log_exporter,
|
||||
throttle: tracer.throttle.into_inner(),
|
||||
span_exporter_enable: tracer.enable_span_exporter,
|
||||
log_exporter_enable: tracer.enable_log_exporter,
|
||||
})
|
||||
}
|
||||
(Err(err), _) => {
|
||||
bp.build_error(
|
||||
id,
|
||||
format!("Failed to build OpenTelemetry span exporter: {err}"),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
(_, Err(err)) => {
|
||||
bp.build_error(
|
||||
id,
|
||||
format!("Failed to build OpenTelemetry log exporter: {err}"),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Tracer::OtelGrpc(tracer) if tracer.enable => {
|
||||
level = Level::from(tracer.level);
|
||||
lossy = tracer.lossy;
|
||||
events = tracer.events;
|
||||
events_policy = tracer.events_policy;
|
||||
enable = tracer.enable;
|
||||
|
||||
let mut span_exporter = SpanExporter::builder()
|
||||
.with_tonic()
|
||||
.with_protocol(opentelemetry_otlp::Protocol::Grpc)
|
||||
.with_timeout(tracer.timeout.into_inner());
|
||||
let mut log_exporter = LogExporter::builder()
|
||||
.with_tonic()
|
||||
.with_protocol(opentelemetry_otlp::Protocol::Grpc)
|
||||
.with_timeout(tracer.timeout.into_inner());
|
||||
if let Some(endpoint) = tracer.endpoint {
|
||||
span_exporter = span_exporter.with_endpoint(endpoint.clone());
|
||||
log_exporter = log_exporter.with_endpoint(endpoint);
|
||||
}
|
||||
|
||||
match (span_exporter.build(), log_exporter.build()) {
|
||||
(Ok(span_exporter), Ok(log_exporter)) => {
|
||||
TelemetrySubscriberType::OtelTracer(OtelTracer {
|
||||
span_exporter,
|
||||
log_exporter,
|
||||
throttle: tracer.throttle.into_inner(),
|
||||
span_exporter_enable: tracer.enable_span_exporter,
|
||||
log_exporter_enable: tracer.enable_log_exporter,
|
||||
})
|
||||
}
|
||||
(Err(err), _) => {
|
||||
bp.build_error(
|
||||
id,
|
||||
format!("Failed to build OpenTelemetry span exporter: {err}"),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
(_, Err(err)) => {
|
||||
bp.build_error(
|
||||
id,
|
||||
format!("Failed to build OpenTelemetry log exporter: {err}"),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if !enable {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create tracer
|
||||
let mut tracer = TelemetrySubscriber {
|
||||
id: format!("t_{}", id.id()),
|
||||
interests: Default::default(),
|
||||
lossy,
|
||||
typ,
|
||||
};
|
||||
|
||||
// Parse disabled events
|
||||
let exclude_event = match &tracer.typ {
|
||||
TelemetrySubscriberType::ConsoleTracer(_) => None,
|
||||
TelemetrySubscriberType::LogTracer(_) => {
|
||||
EventType::Telemetry(TelemetryEvent::LogError).into()
|
||||
}
|
||||
TelemetrySubscriberType::OtelTracer(_) => {
|
||||
EventType::Telemetry(TelemetryEvent::OtelExporterError).into()
|
||||
}
|
||||
TelemetrySubscriberType::Webhook(_) => {
|
||||
EventType::Telemetry(TelemetryEvent::WebhookError).into()
|
||||
}
|
||||
#[cfg(unix)]
|
||||
TelemetrySubscriberType::JournalTracer(_) => {
|
||||
EventType::Telemetry(TelemetryEvent::JournalError).into()
|
||||
}
|
||||
};
|
||||
|
||||
// Parse disabled events
|
||||
apply_events(events, events_policy, |event_type| {
|
||||
if exclude_event != Some(event_type) {
|
||||
let event_level = custom_levels
|
||||
.get(&event_type)
|
||||
.copied()
|
||||
.unwrap_or(event_type.level());
|
||||
if level.is_contained(event_level) {
|
||||
tracer.interests.set(event_type);
|
||||
global_interests.set(event_type);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if !tracer.interests.is_empty() {
|
||||
tracers.push(tracer);
|
||||
} else {
|
||||
bp.build_warning(id, "No events enabled for tracer");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse webhooks
|
||||
for hook in bp.list_infallible::<WebHook>().await {
|
||||
let id = hook.id;
|
||||
let hook = hook.object;
|
||||
|
||||
if !hook.enable {
|
||||
continue;
|
||||
}
|
||||
|
||||
let headers = match hook
|
||||
.http_auth
|
||||
.build_headers(hook.http_headers, "application/json".into())
|
||||
.await
|
||||
{
|
||||
Ok(headers) => headers,
|
||||
Err(err) => {
|
||||
bp.build_error(id, format!("Unable to build HTTP headers: {}", err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Build tracer
|
||||
let mut tracer = TelemetrySubscriber {
|
||||
id: format!("w_{}", id.id()),
|
||||
interests: Default::default(),
|
||||
lossy: hook.lossy,
|
||||
typ: TelemetrySubscriberType::Webhook(WebhookTracer {
|
||||
url: hook.url,
|
||||
timeout: hook.timeout.into_inner(),
|
||||
tls_allow_invalid_certs: hook.allow_invalid_certs,
|
||||
client: utils::http::http_client_builder(hook.allow_invalid_certs)
|
||||
.build()
|
||||
.unwrap_or_default(),
|
||||
headers,
|
||||
key: hook
|
||||
.signature_key
|
||||
.secret()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
bp.build_error(
|
||||
id,
|
||||
format!("Unable to retrieve signature key: {}", err),
|
||||
);
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default()
|
||||
.into_owned(),
|
||||
throttle: hook.throttle.into_inner(),
|
||||
discard_after: hook.discard_after.into_inner(),
|
||||
}),
|
||||
};
|
||||
|
||||
// Parse webhook events
|
||||
apply_events(hook.events, hook.events_policy, |event_type| {
|
||||
if event_type != EventType::Telemetry(TelemetryEvent::WebhookError) {
|
||||
tracer.interests.set(event_type);
|
||||
global_interests.set(event_type);
|
||||
}
|
||||
});
|
||||
|
||||
if !tracer.interests.is_empty() {
|
||||
tracers.push(tracer);
|
||||
} else {
|
||||
bp.build_error(id, "No events enabled for webhook");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dev_mode")]
|
||||
if let Ok(level) = std::env::var("LOG") {
|
||||
let level = Level::from_str(&level).expect("Invalid LOG level");
|
||||
for event_type in EventType::variants() {
|
||||
let event_level = custom_levels
|
||||
.get(event_type)
|
||||
.copied()
|
||||
.unwrap_or(event_type.level());
|
||||
if level.is_contained(event_level) {
|
||||
global_interests.set(event_type.to_id() as usize);
|
||||
}
|
||||
}
|
||||
|
||||
tracers.push(TelemetrySubscriber {
|
||||
id: "default".to_string(),
|
||||
interests: global_interests.clone(),
|
||||
typ: TelemetrySubscriberType::ConsoleTracer(ConsoleTracer {
|
||||
ansi: true,
|
||||
multiline: false,
|
||||
buffered: true,
|
||||
}),
|
||||
lossy: false,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Add default tracer if none were found
|
||||
let level = std::env::var("STALWART_RECOVERY_MODE_LOG_LEVEL")
|
||||
.ok()
|
||||
.and_then(|level| Level::from_str(&level).ok())
|
||||
.unwrap_or(Level::Info);
|
||||
for event_type in EventType::variants() {
|
||||
let event_level = custom_levels
|
||||
.get(event_type)
|
||||
.copied()
|
||||
.unwrap_or(event_type.level());
|
||||
if level.is_contained(event_level) {
|
||||
global_interests.set(event_type.to_id() as usize);
|
||||
}
|
||||
}
|
||||
|
||||
tracers.push(TelemetrySubscriber {
|
||||
id: "recover-log".to_string(),
|
||||
interests: global_interests.clone(),
|
||||
typ: TelemetrySubscriberType::ConsoleTracer(ConsoleTracer {
|
||||
ansi: true,
|
||||
multiline: false,
|
||||
buffered: true,
|
||||
}),
|
||||
lossy: false,
|
||||
});
|
||||
}
|
||||
|
||||
Tracers {
|
||||
subscribers: tracers,
|
||||
interests: global_interests,
|
||||
levels: custom_levels,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Metrics {
|
||||
pub async fn parse(bp: &mut Bootstrap) -> Self {
|
||||
let metrics = bp.setting_infallible::<structs::Metrics>().await;
|
||||
let resource = Resource::builder()
|
||||
.with_service_name("stalwart")
|
||||
.with_attribute(KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")))
|
||||
.build();
|
||||
let instrumentation = InstrumentationScope::builder("stalwart")
|
||||
.with_version(env!("CARGO_PKG_VERSION"))
|
||||
.build();
|
||||
|
||||
Metrics {
|
||||
prometheus: match metrics.prometheus {
|
||||
MetricsPrometheus::Enabled(prom) => {
|
||||
let secret = prom
|
||||
.auth_secret
|
||||
.secret()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
bp.build_error(
|
||||
ObjectType::Metrics.singleton(),
|
||||
format!("Unable to retrieve Prometheus auth secret: {err}"),
|
||||
);
|
||||
})
|
||||
.unwrap_or_default();
|
||||
Some(PrometheusMetrics {
|
||||
auth: prom.auth_username.and_then(|user| {
|
||||
secret.map(|secret| STANDARD.encode(format!("{user}:{secret}")))
|
||||
}),
|
||||
})
|
||||
}
|
||||
MetricsPrometheus::Disabled => None,
|
||||
},
|
||||
otel: match metrics.open_telemetry {
|
||||
structs::MetricsOtel::Http(otel) => {
|
||||
let headers = match otel.http_auth.build_headers(otel.http_headers, None).await
|
||||
{
|
||||
Ok(headers) => headers
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| {
|
||||
k.and_then(|k| Some((k.to_string(), v.to_str().ok()?.to_string())))
|
||||
})
|
||||
.collect::<HashMap<String, String>>(),
|
||||
Err(err) => {
|
||||
bp.build_error(
|
||||
ObjectType::Metrics.singleton(),
|
||||
format!("Failed to build OpenTelemetry HTTP headers: {err}"),
|
||||
);
|
||||
Default::default()
|
||||
}
|
||||
};
|
||||
|
||||
let mut exporter = MetricExporter::builder()
|
||||
.with_temporality(Temporality::Delta)
|
||||
.with_http()
|
||||
.with_endpoint(otel.endpoint)
|
||||
.with_timeout(otel.timeout.into_inner());
|
||||
if !headers.is_empty() {
|
||||
exporter = exporter.with_headers(headers);
|
||||
}
|
||||
|
||||
match exporter.build() {
|
||||
Ok(exporter) => Some(Arc::new(OtelMetrics {
|
||||
exporter,
|
||||
interval: otel.interval.into_inner(),
|
||||
resource,
|
||||
instrumentation,
|
||||
})),
|
||||
Err(err) => {
|
||||
bp.build_error(
|
||||
ObjectType::Metrics.singleton(),
|
||||
format!("Failed to build OpenTelemetry metrics exporter: {err}"),
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
structs::MetricsOtel::Grpc(otel) => {
|
||||
let mut exporter = MetricExporter::builder()
|
||||
.with_temporality(Temporality::Delta)
|
||||
.with_tonic()
|
||||
.with_protocol(opentelemetry_otlp::Protocol::Grpc)
|
||||
.with_timeout(otel.timeout.into_inner());
|
||||
if let Some(endpoint) = otel.endpoint {
|
||||
exporter = exporter.with_endpoint(endpoint);
|
||||
}
|
||||
|
||||
match exporter.build() {
|
||||
Ok(exporter) => Some(Arc::new(OtelMetrics {
|
||||
exporter,
|
||||
interval: otel.interval.into_inner(),
|
||||
resource,
|
||||
instrumentation,
|
||||
})),
|
||||
Err(err) => {
|
||||
bp.build_error(
|
||||
ObjectType::Metrics.singleton(),
|
||||
format!("Failed to build OpenTelemetry metrics exporter: {err}"),
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
structs::MetricsOtel::Disabled => None,
|
||||
},
|
||||
log_path: bp
|
||||
.list_infallible::<Tracer>()
|
||||
.await
|
||||
.into_iter()
|
||||
.find_map(|tracer| {
|
||||
if let Tracer::Log(log_tracer) = tracer.object
|
||||
&& log_tracer.enable
|
||||
{
|
||||
Some(log_tracer.path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_events(
|
||||
event_types: impl IntoIterator<Item = EventType>,
|
||||
policy: EventPolicy,
|
||||
mut apply_fn: impl FnMut(EventType),
|
||||
) {
|
||||
let mut exclude_events = AHashSet::new();
|
||||
|
||||
for event_type in event_types {
|
||||
if policy == EventPolicy::Include {
|
||||
apply_fn(event_type);
|
||||
} else {
|
||||
exclude_events.insert(event_type);
|
||||
}
|
||||
}
|
||||
|
||||
if policy != EventPolicy::Include {
|
||||
for event_type in EventType::variants() {
|
||||
if !exclude_events.contains(event_type) {
|
||||
apply_fn(*event_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_metrics(
|
||||
event_types: impl IntoIterator<Item = MetricType>,
|
||||
policy: EventPolicy,
|
||||
mut apply_fn: impl FnMut(MetricType),
|
||||
) {
|
||||
let mut exclude_events = AHashSet::new();
|
||||
|
||||
for event_type in event_types {
|
||||
if policy == EventPolicy::Include {
|
||||
apply_fn(event_type);
|
||||
} else {
|
||||
exclude_events.insert(event_type);
|
||||
}
|
||||
}
|
||||
|
||||
if policy != EventPolicy::Include {
|
||||
for event_type in MetricType::variants() {
|
||||
if !exclude_events.contains(event_type) {
|
||||
apply_fn(*event_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for OtelMetrics {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("OtelMetrics")
|
||||
.field("interval", &self.interval)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user