use std::sync::Arc;
#[cfg(any(feature = "logs-grpc", feature = "logs-http"))]
use std::time::Duration;
#[cfg(any(feature = "logs-grpc", feature = "logs-http"))]
use opentelemetry_otlp::{LogExporter, WithExportConfig};
use opentelemetry_sdk::logs::SdkLoggerProvider;
use opentelemetry_sdk::Resource;
#[cfg(any(feature = "logs-grpc", feature = "logs-http"))]
use crate::configuration::OtlpProtocol;
use crate::core::configuration::Config;
use crate::dd_warn;
#[cfg(any(feature = "logs-grpc", feature = "logs-http"))]
use crate::otlp_utils::{
build_otel_resource, get_otlp_logs_endpoint, get_otlp_logs_protocol, get_otlp_logs_timeout,
is_unsupported_protocol,
};
#[cfg(any(feature = "logs-grpc", feature = "logs-http"))]
use crate::telemetry_logs_exporter::TelemetryTrackingLogExporter;
#[cfg(any(feature = "logs-grpc", feature = "logs-http"))]
pub fn create_logger_provider(
config: Arc<Config>,
resource: Option<Resource>,
) -> SdkLoggerProvider {
if !config.logs_otel_enabled() {
return SdkLoggerProvider::builder().build();
}
if config.otel_logs_exporter() == "none" {
dd_warn!("OTEL_LOGS_EXPORTER is set to 'none'. Logs will not be exported.");
return SdkLoggerProvider::builder().build();
}
let protocol = get_otlp_logs_protocol(&config);
if is_unsupported_protocol(protocol) {
dd_warn!("UNSUPPORTED PROTOCOL: HTTP/JSON protocol is not natively supported by opentelemetry-otlp. Logs will not be exported. Use 'grpc' or 'http/protobuf' instead.");
return SdkLoggerProvider::builder().build();
}
#[cfg(not(feature = "logs-grpc"))]
if matches!(protocol, OtlpProtocol::Grpc) {
dd_warn!("FEATURE MISMATCH: Protocol 'grpc' configured but 'logs-grpc' feature is not enabled. Logs will not be exported. Enable 'logs-grpc' in Cargo.toml or set OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf.");
return SdkLoggerProvider::builder().build();
}
#[cfg(not(feature = "logs-http"))]
if matches!(protocol, OtlpProtocol::HttpProtobuf) {
dd_warn!("FEATURE MISMATCH: Protocol 'http/protobuf' configured but 'logs-http' feature is not enabled. Logs will not be exported. Enable 'logs-http' in Cargo.toml or set OTEL_EXPORTER_OTLP_PROTOCOL=grpc.");
return SdkLoggerProvider::builder().build();
}
let mut endpoint = match get_otlp_logs_endpoint(&config, &protocol) {
Ok(endpoint) => endpoint,
Err(err) => {
dd_warn!(
"Failed to get OTLP logs endpoint: {}. Logs will not be exported.",
err
);
return SdkLoggerProvider::builder().build();
}
};
if matches!(protocol, OtlpProtocol::HttpProtobuf) && !endpoint.ends_with("/v1/logs") {
endpoint = endpoint.trim_end_matches('/').to_string();
if !endpoint.is_empty() {
endpoint.push_str("/v1/logs");
}
}
let timeout = Duration::from_millis(get_otlp_logs_timeout(&config) as u64);
let exporter = match build_logs_exporter(protocol, endpoint.clone(), timeout) {
Ok(exporter) => exporter,
Err(err) => {
dd_warn!(
"Failed to create logs exporter: {}. Logs will not be exported.",
err
);
return SdkLoggerProvider::builder().build();
}
};
let telemetry_exporter = TelemetryTrackingLogExporter::new(exporter, protocol);
let final_resource = build_otel_resource(&config, resource);
SdkLoggerProvider::builder()
.with_log_processor(
opentelemetry_sdk::logs::BatchLogProcessor::builder(telemetry_exporter).build(),
)
.with_resource(final_resource)
.build()
}
#[cfg(any(feature = "logs-grpc", feature = "logs-http"))]
fn build_logs_exporter(
protocol: OtlpProtocol,
endpoint: String,
timeout: Duration,
) -> Result<LogExporter, String> {
match protocol {
#[cfg(feature = "logs-grpc")]
OtlpProtocol::Grpc => opentelemetry_otlp::LogExporter::builder()
.with_tonic()
.with_endpoint(endpoint)
.with_timeout(timeout)
.build()
.map_err(|e| format!("Failed to build OTLP gRPC exporter: {e}")),
#[cfg(not(feature = "logs-grpc"))]
OtlpProtocol::Grpc => Err("gRPC protocol requires 'logs-grpc' feature".to_string()),
#[cfg(feature = "logs-http")]
OtlpProtocol::HttpProtobuf => opentelemetry_otlp::LogExporter::builder()
.with_http()
.with_endpoint(endpoint)
.with_timeout(timeout)
.build()
.map_err(|e| format!("Failed to build OTLP HTTP/protobuf exporter: {e}")),
#[cfg(not(feature = "logs-http"))]
OtlpProtocol::HttpProtobuf => {
Err("HTTP/protobuf protocol requires 'logs-http' feature".to_string())
}
OtlpProtocol::HttpJson => Err("HTTP/JSON protocol not supported".to_string()),
}
}