@@ -47,6 +47,65 @@ pub const LOGS: &str = "logs";
4747pub const METRICS : & str = "metrics" ;
4848pub const TRACES : & str = "traces" ;
4949
50+ /// Configuration for OTLP decoding behavior.
51+ #[ configurable_component]
52+ #[ derive( Clone , Debug , Default , PartialEq , Eq ) ]
53+ #[ serde( deny_unknown_fields) ]
54+ pub struct OtlpDecodingConfig {
55+ /// Whether to use OTLP decoding for logs.
56+ ///
57+ /// When `true`, logs preserve their OTLP format.
58+ /// When `false` (default), logs are converted to Vector's native format.
59+ #[ serde( default ) ]
60+ pub logs : bool ,
61+
62+ /// Whether to use OTLP decoding for metrics.
63+ ///
64+ /// When `true`, metrics preserve their OTLP format but are processed as logs.
65+ /// When `false` (default), metrics are converted to Vector's native metric format.
66+ #[ serde( default ) ]
67+ pub metrics : bool ,
68+
69+ /// Whether to use OTLP decoding for traces.
70+ ///
71+ /// When `true`, traces preserve their OTLP format.
72+ /// When `false` (default), traces are converted to Vector's native format.
73+ #[ serde( default ) ]
74+ pub traces : bool ,
75+ }
76+
77+ impl From < bool > for OtlpDecodingConfig {
78+ /// Converts a boolean value to an OtlpDecodingConfig.
79+ ///
80+ /// This provides backward compatibility with the previous boolean configuration.
81+ /// - `true` enables OTLP decoding for all signals
82+ /// - `false` disables OTLP decoding for all signals (uses Vector native format)
83+ fn from ( value : bool ) -> Self {
84+ Self {
85+ logs : value,
86+ metrics : value,
87+ traces : value,
88+ }
89+ }
90+ }
91+
92+ impl OtlpDecodingConfig {
93+ /// Returns true if any signal is configured to use OTLP decoding.
94+ pub const fn any_enabled ( & self ) -> bool {
95+ self . logs || self . metrics || self . traces
96+ }
97+
98+ /// Returns true if all signals are configured to use OTLP decoding.
99+ pub const fn all_enabled ( & self ) -> bool {
100+ self . logs && self . metrics && self . traces
101+ }
102+
103+ /// Returns true if signals have mixed configuration (some enabled, some disabled).
104+ pub const fn is_mixed ( & self ) -> bool {
105+ self . any_enabled ( ) && !self . all_enabled ( )
106+ }
107+ }
108+
50109/// Configuration for the `opentelemetry` source.
51110#[ configurable_component( source( "opentelemetry" , "Receive OTLP data through gRPC or HTTP." ) ) ]
52111#[ derive( Clone , Debug ) ]
@@ -67,14 +126,36 @@ pub struct OpentelemetryConfig {
67126 #[ serde( default ) ]
68127 pub log_namespace : Option < bool > ,
69128
70- /// Setting this field will override the legacy mapping of OTEL protos to Vector events and use the proto directly .
129+ /// Configuration for OTLP decoding behavior .
71130 ///
72- /// One major caveat here is that the incoming metrics will be parsed as logs but they will preserve the OTLP format.
73- /// This means that components that work on metrics, will not be compatible with this output.
74- /// However, these events can be forwarded directly to a downstream OTEL collector.
75- #[ configurable( derived) ]
76- #[ serde( default ) ]
77- pub use_otlp_decoding : bool ,
131+ /// This configuration controls how OpenTelemetry Protocol (OTLP) data is decoded for each
132+ /// signal type (logs, metrics, traces). When a signal is configured to use OTLP decoding, the raw OTLP format is
133+ /// preserved, allowing the data to be forwarded to downstream OTLP collectors without transformation.
134+ /// Otherwise, the signal is converted to Vector's native event format.
135+ ///
136+ /// Simple boolean form:
137+ ///
138+ /// ```yaml
139+ /// use_otlp_decoding: true # All signals preserve OTLP format
140+ /// # or
141+ /// use_otlp_decoding: false # All signals use Vector native format (default)
142+ /// ```
143+ ///
144+ /// Per-signal configuration:
145+ ///
146+ /// ```yaml
147+ /// use_otlp_decoding:
148+ /// logs: false # Convert to Vector native format
149+ /// metrics: false # Convert to Vector native format
150+ /// traces: true # Preserve OTLP format
151+ /// ```
152+ ///
153+ /// **Note:** When OTLP decoding is enabled for metrics:
154+ /// - Metrics are parsed as logs while preserving the OTLP format
155+ /// - Vector's metric transforms will NOT be compatible with this output
156+ /// - The events can be forwarded directly (passthrough) to a downstream OTLP collector
157+ #[ serde( default , deserialize_with = "bool_or_struct" ) ]
158+ pub use_otlp_decoding : OtlpDecodingConfig ,
78159}
79160
80161/// Configuration for the `opentelemetry` gRPC server.
@@ -152,18 +233,24 @@ impl GenerateConfig for OpentelemetryConfig {
152233 http : example_http_config ( ) ,
153234 acknowledgements : Default :: default ( ) ,
154235 log_namespace : None ,
155- use_otlp_decoding : false ,
236+ use_otlp_decoding : OtlpDecodingConfig :: default ( ) ,
156237 } )
157238 . unwrap ( )
158239 }
159240}
160241
161242impl OpentelemetryConfig {
162- fn get_signal_deserializer (
243+ pub ( crate ) fn get_signal_deserializer (
163244 & self ,
164245 signal_type : OtlpSignalType ,
165246 ) -> vector_common:: Result < Option < OtlpDeserializer > > {
166- if self . use_otlp_decoding {
247+ let should_use_otlp = match signal_type {
248+ OtlpSignalType :: Logs => self . use_otlp_decoding . logs ,
249+ OtlpSignalType :: Metrics => self . use_otlp_decoding . metrics ,
250+ OtlpSignalType :: Traces => self . use_otlp_decoding . traces ,
251+ } ;
252+
253+ if should_use_otlp {
167254 Ok ( Some ( OtlpDeserializer :: new_with_signals ( IndexSet :: from ( [
168255 signal_type,
169256 ] ) ) ) )
@@ -183,6 +270,16 @@ impl SourceConfig for OpentelemetryConfig {
183270
184271 let grpc_tls_settings = MaybeTlsSettings :: from_config ( self . grpc . tls . as_ref ( ) , true ) ?;
185272
273+ // Log info message when using mixed OTLP decoding formats
274+ if self . use_otlp_decoding . is_mixed ( ) {
275+ info ! (
276+ message = "Signals with OTLP decoding enabled will preserve raw format; others will use Vector native format." ,
277+ logs_otlp = self . use_otlp_decoding. logs,
278+ metrics_otlp = self . use_otlp_decoding. metrics,
279+ traces_otlp = self . use_otlp_decoding. traces,
280+ ) ;
281+ }
282+
186283 let logs_deserializer = self . get_signal_deserializer ( OtlpSignalType :: Logs ) ?;
187284 let metrics_deserializer = self . get_signal_deserializer ( OtlpSignalType :: Metrics ) ?;
188285 let traces_deserializer = self . get_signal_deserializer ( OtlpSignalType :: Traces ) ?;
@@ -352,13 +449,13 @@ impl SourceConfig for OpentelemetryConfig {
352449 }
353450 } ;
354451
355- let logs_output = if self . use_otlp_decoding {
452+ let logs_output = if self . use_otlp_decoding . logs {
356453 SourceOutput :: new_maybe_logs ( DataType :: Log , Definition :: any ( ) ) . with_port ( LOGS )
357454 } else {
358455 SourceOutput :: new_maybe_logs ( DataType :: Log , schema_definition) . with_port ( LOGS )
359456 } ;
360457
361- let metrics_output = if self . use_otlp_decoding {
458+ let metrics_output = if self . use_otlp_decoding . metrics {
362459 SourceOutput :: new_maybe_logs ( DataType :: Log , Definition :: any ( ) ) . with_port ( METRICS )
363460 } else {
364461 SourceOutput :: new_metrics ( ) . with_port ( METRICS )
0 commit comments