From 0d0274b5267c4f865180e3e28bd7ee363832be1a Mon Sep 17 00:00:00 2001 From: Brian Marks Date: Thu, 23 Jul 2026 18:39:08 -0400 Subject: [PATCH 1/2] Add OTLP export fields to core startup diagnostic log Report whether the tracer exports each telemetry signal over OTLP in the "DATADOG CONFIGURATION - CORE" startup log via three boolean fields: otlp_traces_export_enabled (always false; Ruby has no OTLP trace exporter), otlp_metrics_export_enabled, and otlp_logs_export_enabled. The metrics and logs values read from the opentelemetry settings namespace, accessed defensively so an unregistered namespace defaults to false. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../core/diagnostics/environment_logger.rb | 31 ++++++++++++- .../core/diagnostics/environment_logger.rbs | 6 ++- .../diagnostics/environment_logger_spec.rb | 43 ++++++++++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/lib/datadog/core/diagnostics/environment_logger.rb b/lib/datadog/core/diagnostics/environment_logger.rb index eae398ce0f..d1646d47de 100644 --- a/lib/datadog/core/diagnostics/environment_logger.rb +++ b/lib/datadog/core/diagnostics/environment_logger.rb @@ -75,7 +75,10 @@ def collect_config! tags: tags, runtime_metrics_enabled: runtime_metrics_enabled, vm: vm, - health_metrics_enabled: health_metrics_enabled + health_metrics_enabled: health_metrics_enabled, + otlp_traces_export_enabled: otlp_traces_export_enabled, + otlp_metrics_export_enabled: otlp_metrics_export_enabled, + otlp_logs_export_enabled: otlp_logs_export_enabled } end @@ -159,8 +162,34 @@ def health_metrics_enabled !!Datadog.configuration.health_metrics.enabled end + # @return [Boolean] whether the tracer exports traces over OTLP. + # Always false: Ruby exports spans in Datadog's native format and has no OTLP trace exporter. + def otlp_traces_export_enabled + false + end + + # @return [Boolean] whether the tracer exports metrics over OTLP + def otlp_metrics_export_enabled + !!opentelemetry_settings&.metrics&.enabled + end + + # @return [Boolean] whether the tracer exports logs over OTLP + def otlp_logs_export_enabled + !!opentelemetry_settings&.logs&.enabled + end + private + # The `opentelemetry` settings namespace is registered by core configuration, but access it + # defensively so a missing/unregistered namespace defaults to `false` rather than raising. + def opentelemetry_settings + return unless Datadog.configuration.respond_to?(:opentelemetry) + + Datadog.configuration.opentelemetry + rescue + nil + end + # Outputs "k1:v1,k2:v2,..." def hash_serializer(h) h.map { |k, v| "#{k}:#{v}" }.join(",") diff --git a/sig/datadog/core/diagnostics/environment_logger.rbs b/sig/datadog/core/diagnostics/environment_logger.rbs index 1efb97226a..ad5c6fa3be 100644 --- a/sig/datadog/core/diagnostics/environment_logger.rbs +++ b/sig/datadog/core/diagnostics/environment_logger.rbs @@ -17,7 +17,7 @@ module Datadog def self.collect_and_log!: (?Hash[Symbol, untyped]? extra_fields) -> void end module EnvironmentCollector - def self.collect_config!: () -> { date: untyped, os_name: untyped, version: untyped, lang: untyped, lang_version: untyped, env: untyped, service: untyped, dd_version: untyped, debug: untyped, tags: untyped, runtime_metrics_enabled: untyped, vm: untyped, health_metrics_enabled: untyped } + def self.collect_config!: () -> { date: untyped, os_name: untyped, version: untyped, lang: untyped, lang_version: untyped, env: untyped, service: untyped, dd_version: untyped, debug: untyped, tags: untyped, runtime_metrics_enabled: untyped, vm: untyped, health_metrics_enabled: untyped, otlp_traces_export_enabled: bool, otlp_metrics_export_enabled: bool, otlp_logs_export_enabled: bool } def self.date: () -> untyped def self.os_name: () -> untyped @@ -32,8 +32,12 @@ module Datadog def self.runtime_metrics_enabled: () -> untyped def self.vm: () -> ::String def self.health_metrics_enabled: () -> untyped + def self.otlp_traces_export_enabled: () -> bool + def self.otlp_metrics_export_enabled: () -> bool + def self.otlp_logs_export_enabled: () -> bool private + def self.opentelemetry_settings: () -> untyped def self.hash_serializer: (untyped h) -> untyped end end diff --git a/spec/datadog/core/diagnostics/environment_logger_spec.rb b/spec/datadog/core/diagnostics/environment_logger_spec.rb index cf3b7fe288..63fb78a45e 100644 --- a/spec/datadog/core/diagnostics/environment_logger_spec.rb +++ b/spec/datadog/core/diagnostics/environment_logger_spec.rb @@ -17,6 +17,17 @@ Datadog.configuration.reset! end + # The dev shell may export OTLP-related env vars; clear them so "default"-state + # assertions are deterministic regardless of the surrounding environment. + around do |example| + ClimateControl.modify( + "DD_METRICS_OTEL_ENABLED" => nil, + "DD_LOGS_OTEL_ENABLED" => nil, + ) do + example.run + end + end + describe "#collect_and_log!" do include_context "non-development execution environment" @@ -38,6 +49,9 @@ "runtime_metrics_enabled" => false, "vm" => be_a(String), "health_metrics_enabled" => false, + "otlp_traces_export_enabled" => false, + "otlp_metrics_export_enabled" => false, + "otlp_logs_export_enabled" => false, } end @@ -134,7 +148,10 @@ tags: nil, runtime_metrics_enabled: false, vm: be_a(String), - health_metrics_enabled: false + health_metrics_enabled: false, + otlp_traces_export_enabled: false, + otlp_metrics_export_enabled: false, + otlp_logs_export_enabled: false ) end @@ -206,6 +223,30 @@ it { is_expected.to include health_metrics_enabled: true } end + + context "with OTLP metrics export enabled" do + before { expect(Datadog.configuration.opentelemetry.metrics).to receive(:enabled).and_return(true) } + + it { is_expected.to include otlp_metrics_export_enabled: true } + end + + context "with OTLP logs export enabled" do + before { expect(Datadog.configuration.opentelemetry.logs).to receive(:enabled).and_return(true) } + + it { is_expected.to include otlp_logs_export_enabled: true } + end + + context "when the opentelemetry settings namespace is unavailable" do + before { allow(Datadog.configuration).to receive(:respond_to?).with(:opentelemetry).and_return(false) } + + it do + is_expected.to include( + otlp_traces_export_enabled: false, + otlp_metrics_export_enabled: false, + otlp_logs_export_enabled: false, + ) + end + end end end end From 543d2a6fa08fb675ccc09964e5811df4621eec96 Mon Sep 17 00:00:00 2001 From: Brian Marks Date: Fri, 24 Jul 2026 18:37:09 -0400 Subject: [PATCH 2/2] Honor "none" exporter in OTLP export startup log fields Report otlp_metrics_export_enabled and otlp_logs_export_enabled as false when the signal's exporter is set to "none" (OTEL_METRICS_EXPORTER=none / OTEL_LOGS_EXPORTER=none). The OpenTelemetry metrics and logs configuration skips adding the OTLP reader/processor for that value even when the signal is enabled, so the startup diagnostic log should report export as disabled. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../core/diagnostics/environment_logger.rb | 10 ++++++++-- .../diagnostics/environment_logger_spec.rb | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/datadog/core/diagnostics/environment_logger.rb b/lib/datadog/core/diagnostics/environment_logger.rb index d1646d47de..4f993e951a 100644 --- a/lib/datadog/core/diagnostics/environment_logger.rb +++ b/lib/datadog/core/diagnostics/environment_logger.rb @@ -170,12 +170,18 @@ def otlp_traces_export_enabled # @return [Boolean] whether the tracer exports metrics over OTLP def otlp_metrics_export_enabled - !!opentelemetry_settings&.metrics&.enabled + metrics = opentelemetry_settings&.metrics + # A "none" exporter skips the OTLP metric reader even when metrics are enabled + # (mirrors Datadog::OpenTelemetry::Ext::EXPORTER_NONE). + !!(metrics&.enabled && metrics.exporter != "none") end # @return [Boolean] whether the tracer exports logs over OTLP def otlp_logs_export_enabled - !!opentelemetry_settings&.logs&.enabled + logs = opentelemetry_settings&.logs + # A "none" exporter skips the OTLP log record processor even when logs are enabled + # (mirrors Datadog::OpenTelemetry::Ext::EXPORTER_NONE). + !!(logs&.enabled && logs.exporter != "none") end private diff --git a/spec/datadog/core/diagnostics/environment_logger_spec.rb b/spec/datadog/core/diagnostics/environment_logger_spec.rb index 63fb78a45e..7f60891756 100644 --- a/spec/datadog/core/diagnostics/environment_logger_spec.rb +++ b/spec/datadog/core/diagnostics/environment_logger_spec.rb @@ -230,12 +230,30 @@ it { is_expected.to include otlp_metrics_export_enabled: true } end + context "with OTLP metrics enabled but the exporter set to none" do + before do + allow(Datadog.configuration.opentelemetry.metrics).to receive(:enabled).and_return(true) + allow(Datadog.configuration.opentelemetry.metrics).to receive(:exporter).and_return("none") + end + + it { is_expected.to include otlp_metrics_export_enabled: false } + end + context "with OTLP logs export enabled" do before { expect(Datadog.configuration.opentelemetry.logs).to receive(:enabled).and_return(true) } it { is_expected.to include otlp_logs_export_enabled: true } end + context "with OTLP logs enabled but the exporter set to none" do + before do + allow(Datadog.configuration.opentelemetry.logs).to receive(:enabled).and_return(true) + allow(Datadog.configuration.opentelemetry.logs).to receive(:exporter).and_return("none") + end + + it { is_expected.to include otlp_logs_export_enabled: false } + end + context "when the opentelemetry settings namespace is unavailable" do before { allow(Datadog.configuration).to receive(:respond_to?).with(:opentelemetry).and_return(false) }