diff options
Diffstat (limited to 'crates/arti')
| -rw-r--r-- | crates/arti/Cargo.toml | 4 | ||||
| -rw-r--r-- | crates/arti/src/cfg.rs | 3 | ||||
| -rw-r--r-- | crates/arti/src/logging.rs | 137 | ||||
| -rw-r--r-- | crates/arti/src/logging/otlp_file_exporter.rs | 83 |
4 files changed, 19 insertions, 208 deletions
diff --git a/crates/arti/Cargo.toml b/crates/arti/Cargo.toml index cce45ad87..ad1f49aad 100644 --- a/crates/arti/Cargo.toml +++ b/crates/arti/Cargo.toml @@ -125,10 +125,12 @@ syslog = ["syslog-tracing"] opentelemetry = [ "tracing-opentelemetry", "dep:opentelemetry", + "dep:otlp-file-exporter", "opentelemetry_sdk", "opentelemetry-otlp", "opentelemetry-appender-tracing", "opentelemetry-proto", + "tor-config-shared/opentelemetry", "__is_experimental", ] @@ -200,6 +202,7 @@ opentelemetry-appender-tracing = { version = "0.32.0", optional = true } opentelemetry-otlp = { version = "0.32.0", optional = true } opentelemetry-proto = { version = "0.32.0", optional = true } opentelemetry_sdk = { version = "0.32.1", features = ["rt-tokio"], optional = true } # TODO: what's up with this feature +otlp-file-exporter = { path = "../otlp-file-exporter", version = "0.1.0", optional = true } paste = "1.0.3" pin-project = "1" postage = { version = "0.5.0", default-features = false, features = ["futures-traits"] } @@ -221,6 +224,7 @@ tor-basic-utils = { path = "../tor-basic-utils", version = "0.45.0" } tor-cell = { path = "../tor-cell", version = "0.45.0", optional = true } tor-config = { path = "../tor-config", version = "0.45.0" } tor-config-path = { path = "../tor-config-path", version = "0.45.0" } +tor-config-shared = { path = "../tor-config-shared", version = "0.45.0" } tor-error = { path = "../tor-error", version = "0.45.0", default-features = false, features = ["tracing"] } tor-general-addr = { path = "../tor-general-addr", version = "0.45.0" } tor-hsclient = { path = "../tor-hsclient", version = "0.45.0", optional = true } diff --git a/crates/arti/src/cfg.rs b/crates/arti/src/cfg.rs index 181ab295d..50081c877 100644 --- a/crates/arti/src/cfg.rs +++ b/crates/arti/src/cfg.rs @@ -21,7 +21,8 @@ use arti_client::TorClientConfig; #[cfg(feature = "onion-service-service")] use tor_config::define_list_builder_accessors; use tor_config::derive::prelude::*; -pub(crate) use tor_config::{ConfigBuildError, Listen, MetricsConfig, MetricsConfigBuilder}; +pub(crate) use tor_config::{ConfigBuildError, Listen}; +pub(crate) use tor_config_shared::metrics::{MetricsConfig, MetricsConfigBuilder}; use crate::{LoggingConfig, LoggingConfigBuilder}; diff --git a/crates/arti/src/logging.rs b/crates/arti/src/logging.rs index fde918b77..ad9347a0a 100644 --- a/crates/arti/src/logging.rs +++ b/crates/arti/src/logging.rs @@ -7,9 +7,9 @@ use serde::{Deserialize, Serialize}; use std::io::IsTerminal as _; use std::path::Path; use std::str::FromStr; -use std::time::Duration; use tor_basic_utils::PathExt as _; use tor_config::ConfigBuildError; +use tor_config_shared::opentelemetry::{OpentelemetryConfig, OpentelemetryConfigBuilder}; use tor_config::derive::prelude::*; use tor_config_path::{CfgPath, CfgPathResolver}; use tor_error::warn_report; @@ -20,8 +20,6 @@ use tracing_subscriber::prelude::*; use tracing_subscriber::{Layer, filter::Targets, fmt, registry}; mod fields; -#[cfg(feature = "opentelemetry")] -mod otlp_file_exporter; mod time; /// Structure to hold our logging configuration options @@ -149,109 +147,6 @@ pub(crate) enum LogRotation { Never, } -/// Configuration for exporting spans with OpenTelemetry. -#[derive(Debug, Deftly, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[derive_deftly(TorConfig)] -#[cfg_attr(feature = "experimental-api", visibility::make(pub))] -#[cfg_attr(feature = "experimental-api", deftly(tor_config(vis = "pub")))] -pub(crate) struct OpentelemetryConfig { - /// Write spans to a file in OTLP JSON format. - #[deftly(tor_config(default))] - file: Option<OpentelemetryFileExporterConfig>, - /// Export spans via HTTP. - #[deftly(tor_config(default))] - http: Option<OpentelemetryHttpExporterConfig>, -} - -/// Configuration for the OpenTelemetry HTTP exporter. -#[derive(Debug, Deftly, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[derive_deftly(TorConfig)] -#[deftly(tor_config(no_default_trait))] -#[cfg_attr(feature = "experimental-api", visibility::make(pub))] -#[cfg_attr(feature = "experimental-api", deftly(tor_config(vis = "pub")))] -pub(crate) struct OpentelemetryHttpExporterConfig { - /// HTTP(S) endpoint to send spans to. - /// - /// For Jaeger, this should be something like: `http://localhost:4318/v1/traces` - #[deftly(tor_config(no_default))] - endpoint: String, - /// Configuration for how to batch exports. - #[deftly(tor_config(sub_builder))] - batch: OpentelemetryBatchConfig, - /// Timeout for sending data. - /// - /// If this is set to [`None`], it will be left at the OpenTelemetry default, which is - /// currently 10 seconds unless overridden with a environment variable. - // - // NOTE: there is no way to actually override this with None, so we have to say - // "no magic" to tell dd(TorConfig) not to worry about that. - #[deftly(tor_config(no_magic, default))] - timeout: Option<Duration>, - // TODO: Once opentelemetry-otlp supports more than one protocol over HTTP, add a config option - // to choose protocol here. -} - -/// Configuration for the OpenTelemetry HTTP exporter. -#[derive(Debug, Deftly, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[derive_deftly(TorConfig)] -#[deftly(tor_config(no_default_trait))] -#[cfg_attr(feature = "experimental-api", visibility::make(pub))] -#[cfg_attr(feature = "experimental-api", deftly(tor_config(vis = "pub")))] -pub(crate) struct OpentelemetryFileExporterConfig { - /// The path to write the JSON file to. - #[deftly(tor_config(no_default))] - path: CfgPath, - /// Configuration for how to batch writes. - #[deftly(tor_config(sub_builder))] - batch: OpentelemetryBatchConfig, -} - -/// Configuration for the Opentelemetry batch exporting. -/// -/// This is a copy of [`opentelemetry_sdk::trace::BatchConfig`]. -#[derive(Debug, Deftly, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[derive_deftly(TorConfig)] -#[cfg_attr(feature = "experimental-api", visibility::make(pub))] -#[cfg_attr(feature = "experimental-api", deftly(tor_config(vis = "pub")))] -pub(crate) struct OpentelemetryBatchConfig { - /// Maximum queue size. See [`opentelemetry_sdk::trace::BatchConfig::max_queue_size`]. - #[deftly(tor_config(default))] - max_queue_size: Option<usize>, - /// Maximum export batch size. See [`opentelemetry_sdk::trace::BatchConfig::max_export_batch_size`]. - #[deftly(tor_config(default))] - max_export_batch_size: Option<usize>, - /// Scheduled delay. See [`opentelemetry_sdk::trace::BatchConfig::scheduled_delay`]. - #[deftly(tor_config(no_magic, default))] - scheduled_delay: Option<Duration>, -} - -#[cfg(feature = "opentelemetry")] -impl From<OpentelemetryBatchConfig> for opentelemetry_sdk::trace::BatchConfig { - fn from(config: OpentelemetryBatchConfig) -> opentelemetry_sdk::trace::BatchConfig { - let batch_config = opentelemetry_sdk::trace::BatchConfigBuilder::default(); - - let batch_config = if let Some(max_queue_size) = config.max_queue_size { - batch_config.with_max_queue_size(max_queue_size) - } else { - batch_config - }; - - let batch_config = if let Some(max_export_batch_size) = config.max_export_batch_size { - batch_config.with_max_export_batch_size(max_export_batch_size) - } else { - batch_config - }; - - let batch_config = if let Some(scheduled_delay) = config.scheduled_delay { - batch_config.with_scheduled_delay(scheduled_delay) - } else { - batch_config - }; - - batch_config.build() - } -} - /// Configuration for logging to the tokio console. #[derive(Debug, Deftly, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] #[derive_deftly(TorConfig)] @@ -372,7 +267,7 @@ where use opentelemetry::trace::TracerProvider; use opentelemetry_otlp::WithExportConfig; - if config.opentelemetry.file.is_some() && config.opentelemetry.http.is_some() { + if config.opentelemetry.file().is_some() && config.opentelemetry.http().is_some() { return Err(ConfigBuildError::Invalid { field: "logging.opentelemetry".into(), problem: "Only one OpenTelemetry exporter can be enabled at once.".into(), @@ -384,21 +279,21 @@ where .with_service_name("arti") .build(); - let span_processor = if let Some(otel_file_config) = &config.opentelemetry.file { + let span_processor = if let Some(otel_file_config) = &config.opentelemetry.file() { let file = std::fs::File::options() .create(true) .append(true) - .open(otel_file_config.path.path(path_resolver)?)?; + .open(otel_file_config.path().path(path_resolver)?)?; let exporter = otlp_file_exporter::FileExporter::new(file, resource.clone()); opentelemetry_sdk::trace::BatchSpanProcessor::builder(exporter) - .with_batch_config(otel_file_config.batch.into()) + .with_batch_config(otel_file_config.batch().clone().into()) .build() - } else if let Some(otel_http_config) = &config.opentelemetry.http { - if otel_http_config.endpoint.starts_with("http://") - && !(otel_http_config.endpoint.starts_with("http://localhost") - || otel_http_config.endpoint.starts_with("http://127.0.0.1")) + } else if let Some(otel_http_config) = &config.opentelemetry.http() { + if otel_http_config.endpoint().starts_with("http://") + && !(otel_http_config.endpoint().starts_with("http://localhost") + || otel_http_config.endpoint().starts_with("http://127.0.0.1")) { return Err(ConfigBuildError::Invalid { field: "logging.opentelemetry.http.endpoint".into(), @@ -408,18 +303,12 @@ where } let exporter = opentelemetry_otlp::SpanExporter::builder() .with_http() - .with_endpoint(otel_http_config.endpoint.clone()); - - let exporter = if let Some(timeout) = otel_http_config.timeout { - exporter.with_timeout(timeout) - } else { - exporter - }; - - let exporter = exporter.build()?; + .with_endpoint(otel_http_config.endpoint().clone()) + .with_timeout(*otel_http_config.timeout()) + .build()?; opentelemetry_sdk::trace::BatchSpanProcessor::builder(exporter) - .with_batch_config(otel_http_config.batch.into()) + .with_batch_config(otel_http_config.batch().clone().into()) .build() } else { return Ok(None); diff --git a/crates/arti/src/logging/otlp_file_exporter.rs b/crates/arti/src/logging/otlp_file_exporter.rs deleted file mode 100644 index 19943b1e4..000000000 --- a/crates/arti/src/logging/otlp_file_exporter.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Tracing exporter to write spans to a file in the OTLP JSON format. - -// TODO: If https://github.com/open-telemetry/opentelemetry-rust/issues/2602 gets fixed, we can -// replace this entire file with whatever upstream has for doing this. - -use opentelemetry_proto::transform::common::tonic::ResourceAttributesWithSchema; -use opentelemetry_proto::transform::trace::tonic::group_spans_by_resource_and_scope; -use opentelemetry_sdk::{ - Resource, - error::{OTelSdkError, OTelSdkResult}, - trace::SpanExporter, -}; -use std::{ - fmt::Debug, - io::{LineWriter, Write}, - sync::{Arc, Mutex}, -}; - -/// Tracing exporter to write OTLP JSON to a file (or anything else that implements [`LineWriter`]. -#[derive(Debug)] -pub(crate) struct FileExporter<W: Write + Send + Debug> { - /// The [`LineWriter`] to write to. - writer: Arc<Mutex<LineWriter<W>>>, - /// The [`Resource`] to associate spans with. - resource: Resource, -} - -impl<W: Write + Send + Debug> FileExporter<W> { - /// Create a new [`FileExporter`] - pub(crate) fn new(writer: W, resource: Resource) -> Self { - Self { - writer: Arc::new(Mutex::new(LineWriter::new(writer))), - resource, - } - } -} - -// Note that OpenTelemetry can only represent events as children of spans, so this exporter only -// works on spans. If you want a event to be exported, you need to make sure it exists within some -// span. -impl<W: Write + Send + Debug> SpanExporter for FileExporter<W> { - fn export( - &self, - batch: Vec<opentelemetry_sdk::trace::SpanData>, - ) -> impl futures::Future< - Output = std::result::Result<(), opentelemetry_sdk::error::OTelSdkError>, - > + std::marker::Send { - let resource = ResourceAttributesWithSchema::from(&self.resource); - let data = group_spans_by_resource_and_scope(batch, &resource); - let mut writer = self.writer.lock().expect("Lock poisoned"); - Box::pin(std::future::ready('write: { - // See https://opentelemetry.io/docs/specs/otel/protocol/file-exporter/ for format - - if let Err(err) = serde_json::to_writer( - writer.get_mut(), - &serde_json::json!({"resourceSpans": data}), - ) { - break 'write Err(OTelSdkError::InternalFailure(err.to_string())); - } - - if let Err(err) = writer.write(b"\n") { - break 'write Err(OTelSdkError::InternalFailure(err.to_string())); - } - - Ok(()) - })) - } - - fn force_flush(&self) -> OTelSdkResult { - let mut writer = self - .writer - .lock() - .map_err(|e| OTelSdkError::InternalFailure(e.to_string()))?; - - writer - .flush() - .map_err(|e| OTelSdkError::InternalFailure(e.to_string())) - } - - fn set_resource(&mut self, res: &opentelemetry_sdk::Resource) { - self.resource = res.clone(); - } -} |
