@@ -29,16 +29,25 @@ 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:: { EXTRACT_LOG_KEY , LOG_SOURCE_KEY , STREAM_NAME_HEADER_KEY } ;
33
34
use crate :: metadata:: SchemaVersion ;
34
35
use crate :: option:: Mode ;
35
- use crate :: otel:: logs:: OTEL_LOG_KNOWN_FIELD_LIST ;
36
+ use crate :: otel:: logs:: { flatten_otel_protobuf , OTEL_LOG_KNOWN_FIELD_LIST } ;
36
37
use crate :: otel:: metrics:: OTEL_METRICS_KNOWN_FIELD_LIST ;
37
38
use crate :: otel:: traces:: OTEL_TRACES_KNOWN_FIELD_LIST ;
38
39
use crate :: parseable:: { PARSEABLE , StreamNotFound } ;
39
40
use crate :: storage:: { ObjectStorageError , StreamType } ;
40
41
use crate :: utils:: header_parsing:: ParseHeaderError ;
41
42
use crate :: utils:: json:: { flatten:: JsonFlattenError , strict:: StrictValue } ;
43
+ use actix_web:: web:: { self , Json , Path } ;
44
+ use actix_web:: { http:: header:: ContentType , HttpRequest , HttpResponse } ;
45
+ use arrow_array:: RecordBatch ;
46
+ use bytes:: Bytes ;
47
+ use chrono:: Utc ;
48
+ use http:: StatusCode ;
49
+ use opentelemetry_proto:: tonic:: collector:: logs:: v1:: ExportLogsServiceRequest ;
50
+ use prost:: Message ;
42
51
43
52
use super :: logstream:: error:: { CreateStreamError , StreamError } ;
44
53
use super :: modal:: utils:: ingest_utils:: { flatten_and_push_logs, get_custom_fields_from_header} ;
@@ -157,7 +166,7 @@ pub async fn ingest_internal_stream(stream_name: String, body: Bytes) -> Result<
157
166
// creates if stream does not exist
158
167
pub async fn handle_otel_logs_ingestion (
159
168
req : HttpRequest ,
160
- Json ( json ) : Json < StrictValue > ,
169
+ body : web :: Bytes ,
161
170
) -> Result < HttpResponse , PostError > {
162
171
let Some ( stream_name) = req. headers ( ) . get ( STREAM_NAME_HEADER_KEY ) else {
163
172
return Err ( PostError :: Header ( ParseHeaderError :: MissingStreamName ) ) ;
@@ -207,14 +216,35 @@ pub async fn handle_otel_logs_ingestion(
207
216
. await ?;
208
217
209
218
let p_custom_fields = get_custom_fields_from_header ( & req) ;
219
+ match req. headers ( ) . get ( "Content-Type" ) {
220
+ Some ( content_type) => {
221
+ if content_type == "application/json" {
222
+ flatten_and_push_logs (
223
+ serde_json:: from_slice ( & body) ?,
224
+ & stream_name,
225
+ & log_source,
226
+ & p_custom_fields,
227
+ )
228
+ . await ?;
229
+ }
210
230
211
- flatten_and_push_logs (
212
- json. into_inner ( ) ,
213
- & stream_name,
214
- & log_source,
215
- & p_custom_fields,
216
- )
217
- . await ?;
231
+ if content_type == "application/x-protobuf" {
232
+ match ExportLogsServiceRequest :: decode ( body) {
233
+ Ok ( json) => {
234
+ for record in flatten_otel_protobuf ( & json) {
235
+ push_logs ( & stream_name, record, & log_source, & p_custom_fields) . await ?;
236
+ }
237
+ }
238
+ Err ( e) => {
239
+ return Err ( PostError :: Invalid ( e. into ( ) ) ) ;
240
+ }
241
+ }
242
+ }
243
+ }
244
+ None => {
245
+ return Err ( PostError :: Header ( ParseHeaderError :: InvalidValue ) ) ;
246
+ }
247
+ }
218
248
219
249
Ok ( HttpResponse :: Ok ( ) . finish ( ) )
220
250
}
0 commit comments