18
18
19
19
use std:: collections:: { HashMap , HashSet } ;
20
20
21
- use actix_web:: web:: { Json , Path } ;
21
+ use actix_web:: web:: { self , Json , Path } ;
22
22
use actix_web:: { HttpRequest , HttpResponse , http:: header:: ContentType } ;
23
23
use arrow_array:: RecordBatch ;
24
24
use bytes:: Bytes ;
@@ -29,18 +29,21 @@ use crate::event::error::EventError;
29
29
use crate :: event:: format:: known_schema:: { self , KNOWN_SCHEMA_LIST } ;
30
30
use crate :: event:: format:: { self , EventFormat , LogSource , LogSourceEntry } ;
31
31
use crate :: event:: { self , FORMAT_KEY , USER_AGENT_KEY } ;
32
+ use crate :: handlers:: http:: modal:: utils:: ingest_utils:: push_logs;
32
33
use crate :: handlers:: {
33
34
EXTRACT_LOG_KEY , LOG_SOURCE_KEY , STREAM_NAME_HEADER_KEY , TELEMETRY_TYPE_KEY , TelemetryType ,
34
35
} ;
35
36
use crate :: metadata:: SchemaVersion ;
36
37
use crate :: option:: Mode ;
37
- use crate :: otel:: logs:: OTEL_LOG_KNOWN_FIELD_LIST ;
38
+ use crate :: otel:: logs:: { OTEL_LOG_KNOWN_FIELD_LIST , flatten_otel_protobuf } ;
38
39
use crate :: otel:: metrics:: OTEL_METRICS_KNOWN_FIELD_LIST ;
39
40
use crate :: otel:: traces:: OTEL_TRACES_KNOWN_FIELD_LIST ;
40
41
use crate :: parseable:: { PARSEABLE , StreamNotFound } ;
41
42
use crate :: storage:: { ObjectStorageError , StreamType } ;
42
43
use crate :: utils:: header_parsing:: ParseHeaderError ;
43
44
use crate :: utils:: json:: { flatten:: JsonFlattenError , strict:: StrictValue } ;
45
+ use opentelemetry_proto:: tonic:: collector:: logs:: v1:: ExportLogsServiceRequest ;
46
+ use prost:: Message ;
44
47
45
48
use super :: logstream:: error:: { CreateStreamError , StreamError } ;
46
49
use super :: modal:: utils:: ingest_utils:: { flatten_and_push_logs, get_custom_fields_from_header} ;
@@ -166,7 +169,7 @@ pub async fn ingest_internal_stream(stream_name: String, body: Bytes) -> Result<
166
169
// creates if stream does not exist
167
170
pub async fn handle_otel_logs_ingestion (
168
171
req : HttpRequest ,
169
- Json ( json ) : Json < StrictValue > ,
172
+ body : web :: Bytes ,
170
173
) -> Result < HttpResponse , PostError > {
171
174
let Some ( stream_name) = req. headers ( ) . get ( STREAM_NAME_HEADER_KEY ) else {
172
175
return Err ( PostError :: Header ( ParseHeaderError :: MissingStreamName ) ) ;
@@ -217,14 +220,35 @@ pub async fn handle_otel_logs_ingestion(
217
220
. await ?;
218
221
219
222
let p_custom_fields = get_custom_fields_from_header ( & req) ;
223
+ match req. headers ( ) . get ( "Content-Type" ) {
224
+ Some ( content_type) => {
225
+ if content_type == "application/json" {
226
+ flatten_and_push_logs (
227
+ serde_json:: from_slice ( & body) ?,
228
+ & stream_name,
229
+ & log_source,
230
+ & p_custom_fields,
231
+ )
232
+ . await ?;
233
+ }
220
234
221
- flatten_and_push_logs (
222
- json. into_inner ( ) ,
223
- & stream_name,
224
- & log_source,
225
- & p_custom_fields,
226
- )
227
- . await ?;
235
+ if content_type == "application/x-protobuf" {
236
+ match ExportLogsServiceRequest :: decode ( body) {
237
+ Ok ( json) => {
238
+ for record in flatten_otel_protobuf ( & json) {
239
+ push_logs ( & stream_name, record, & log_source, & p_custom_fields) . await ?;
240
+ }
241
+ }
242
+ Err ( e) => {
243
+ return Err ( PostError :: Invalid ( e. into ( ) ) ) ;
244
+ }
245
+ }
246
+ }
247
+ }
248
+ None => {
249
+ return Err ( PostError :: Header ( ParseHeaderError :: InvalidValue ) ) ;
250
+ }
251
+ }
228
252
229
253
Ok ( HttpResponse :: Ok ( ) . finish ( ) )
230
254
}
0 commit comments