@@ -20,6 +20,8 @@ import (
2020 "go.opentelemetry.io/collector/component"
2121 "go.opentelemetry.io/collector/consumer"
2222 "go.opentelemetry.io/collector/pdata/plog"
23+ "go.opentelemetry.io/collector/pdata/pmetric"
24+ "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp"
2325 "go.opentelemetry.io/collector/receiver"
2426 "go.opentelemetry.io/collector/receiver/receiverhelper"
2527 "go.uber.org/zap"
@@ -32,9 +34,11 @@ import (
3234const (
3335 defaultServerTimeout = 20 * time .Second
3436
35- responseOK = "OK"
36- responseInvalidMethod = "Only \" POST\" method is supported"
37- responseInvalidContentType = "\" Content-Type\" must be \" application/x-protobuf\" "
37+ responseOK = "OK"
38+ responseInvalidMethod = "Only \" POST\" method is supported"
39+ responseEventsInvalidContentType = "\" Content-Type\" must be \" application/x-protobuf\" "
40+
41+ responseInvalidContentType = "\" Content-Type\" must be either \" application/x-protobuf\" or \" application/x-protobuf;format=otlp\" "
3842 responseInvalidEncoding = "\" Content-Encoding\" must be \" gzip\" or empty"
3943 responseErrGzipReader = "Error on gzip body"
4044 responseErrReadBody = "Failed to read message body"
@@ -45,22 +49,24 @@ const (
4549
4650 // Centralizing some HTTP and related string constants.
4751 protobufContentType = "application/x-protobuf"
52+ otlpProtobufContentType = "application/x-protobuf;format=otlp"
4853 gzipEncoding = "gzip"
4954 httpContentTypeHeader = "Content-Type"
5055 httpContentEncodingHeader = "Content-Encoding"
5156)
5257
5358var (
54- okRespBody = initJSONResponse (responseOK )
55- invalidMethodRespBody = initJSONResponse (responseInvalidMethod )
56- invalidContentRespBody = initJSONResponse (responseInvalidContentType )
57- invalidEncodingRespBody = initJSONResponse (responseInvalidEncoding )
58- errGzipReaderRespBody = initJSONResponse (responseErrGzipReader )
59- errReadBodyRespBody = initJSONResponse (responseErrReadBody )
60- errUnmarshalBodyRespBody = initJSONResponse (responseErrUnmarshalBody )
61- errNextConsumerRespBody = initJSONResponse (responseErrNextConsumer )
62- errLogsNotConfigured = initJSONResponse (responseErrLogsNotConfigured )
63- errMetricsNotConfigured = initJSONResponse (responseErrMetricsNotConfigured )
59+ okRespBody = initJSONResponse (responseOK )
60+ invalidMethodRespBody = initJSONResponse (responseInvalidMethod )
61+ invalidContentRespBody = initJSONResponse (responseInvalidContentType )
62+ invalidEventsContentRespBody = initJSONResponse (responseEventsInvalidContentType )
63+ invalidEncodingRespBody = initJSONResponse (responseInvalidEncoding )
64+ errGzipReaderRespBody = initJSONResponse (responseErrGzipReader )
65+ errReadBodyRespBody = initJSONResponse (responseErrReadBody )
66+ errUnmarshalBodyRespBody = initJSONResponse (responseErrUnmarshalBody )
67+ errNextConsumerRespBody = initJSONResponse (responseErrNextConsumer )
68+ errLogsNotConfigured = initJSONResponse (responseErrLogsNotConfigured )
69+ errMetricsNotConfigured = initJSONResponse (responseErrMetricsNotConfigured )
6470
6571 translator = & signalfx.ToTranslator {}
6672)
@@ -166,16 +172,6 @@ func (r *sfxReceiver) Shutdown(context.Context) error {
166172}
167173
168174func (r * sfxReceiver ) readBody (ctx context.Context , resp http.ResponseWriter , req * http.Request ) ([]byte , bool ) {
169- if req .Method != http .MethodPost {
170- r .failRequest (ctx , resp , http .StatusBadRequest , invalidMethodRespBody , nil )
171- return nil , false
172- }
173-
174- if req .Header .Get (httpContentTypeHeader ) != protobufContentType {
175- r .failRequest (ctx , resp , http .StatusUnsupportedMediaType , invalidContentRespBody , nil )
176- return nil , false
177- }
178-
179175 encoding := req .Header .Get (httpContentEncodingHeader )
180176 if encoding != "" && encoding != gzipEncoding {
181177 r .failRequest (ctx , resp , http .StatusUnsupportedMediaType , invalidEncodingRespBody , nil )
@@ -221,40 +217,64 @@ func (r *sfxReceiver) handleDatapointReq(resp http.ResponseWriter, req *http.Req
221217 return
222218 }
223219
224- body , ok := r . readBody ( ctx , resp , req )
225- if ! ok {
220+ if req . Method != http . MethodPost {
221+ r . failRequest ( ctx , resp , http . StatusBadRequest , invalidMethodRespBody , nil )
226222 return
227223 }
228224
229- msg := & sfxpb.DataPointUploadMessage {}
230- if err := msg .Unmarshal (body ); err != nil {
231- r .failRequest (ctx , resp , http .StatusBadRequest , errUnmarshalBodyRespBody , err )
225+ otlpFormat := false
226+ switch req .Header .Get (httpContentTypeHeader ) {
227+ case protobufContentType :
228+ case otlpProtobufContentType :
229+ otlpFormat = true
230+ default :
231+ r .failRequest (ctx , resp , http .StatusUnsupportedMediaType , invalidContentRespBody , nil )
232232 return
233233 }
234234
235- if len (msg .Datapoints ) == 0 {
236- r .obsrecv .EndMetricsOp (ctx , metadata .Type .String (), 0 , nil )
237- _ , _ = resp .Write (okRespBody )
235+ body , ok := r .readBody (ctx , resp , req )
236+ if ! ok {
238237 return
239238 }
240239
241- md , err := translator .ToMetrics (msg .Datapoints )
242- if err != nil {
243- r .settings .Logger .Debug ("SignalFx conversion error" , zap .Error (err ))
244- }
240+ r .settings .Logger .Debug ("Handling metrics data" )
245241
246- if r .config .AccessTokenPassthrough {
247- if accessToken := req .Header .Get (splunk .SFxAccessTokenHeader ); accessToken != "" {
248- for i := 0 ; i < md .ResourceMetrics ().Len (); i ++ {
249- rm := md .ResourceMetrics ().At (i )
250- res := rm .Resource ()
251- res .Attributes ().PutStr (splunk .SFxAccessTokenLabel , accessToken )
252- }
242+ var md pmetric.Metrics
243+
244+ if otlpFormat {
245+ r .settings .Logger .Debug ("Received request is in OTLP format" )
246+ otlpreq := pmetricotlp .NewExportRequest ()
247+ if err := otlpreq .UnmarshalProto (body ); err != nil {
248+ r .settings .Logger .Debug ("OTLP data unmarshalling failed" , zap .Error (err ))
249+ r .failRequest (ctx , resp , http .StatusBadRequest , errUnmarshalBodyRespBody , err )
250+ return
253251 }
252+ md = otlpreq .Metrics ()
253+ } else {
254+ msg := & sfxpb.DataPointUploadMessage {}
255+ err := msg .Unmarshal (body )
256+ if err != nil {
257+ r .failRequest (ctx , resp , http .StatusBadRequest , errUnmarshalBodyRespBody , err )
258+ return
259+ }
260+
261+ md , err = translator .ToMetrics (msg .Datapoints )
262+ if err != nil {
263+ r .settings .Logger .Debug ("SignalFx conversion error" , zap .Error (err ))
264+ }
265+ }
266+
267+ dataPointCount := md .DataPointCount ()
268+ if dataPointCount == 0 {
269+ r .obsrecv .EndMetricsOp (ctx , metadata .Type .String (), 0 , nil )
270+ _ , _ = resp .Write (okRespBody )
271+ return
254272 }
255273
256- err = r .metricsConsumer .ConsumeMetrics (ctx , md )
257- r .obsrecv .EndMetricsOp (ctx , metadata .Type .String (), len (msg .Datapoints ), err )
274+ r .addAccessTokenLabel (md , req )
275+
276+ err := r .metricsConsumer .ConsumeMetrics (ctx , md )
277+ r .obsrecv .EndMetricsOp (ctx , metadata .Type .String (), dataPointCount , err )
258278
259279 r .writeResponse (ctx , resp , err )
260280}
@@ -267,6 +287,16 @@ func (r *sfxReceiver) handleEventReq(resp http.ResponseWriter, req *http.Request
267287 return
268288 }
269289
290+ if req .Method != http .MethodPost {
291+ r .failRequest (ctx , resp , http .StatusBadRequest , invalidMethodRespBody , nil )
292+ return
293+ }
294+
295+ if req .Header .Get (httpContentTypeHeader ) != protobufContentType {
296+ r .failRequest (ctx , resp , http .StatusUnsupportedMediaType , invalidEventsContentRespBody , nil )
297+ return
298+ }
299+
270300 body , ok := r .readBody (ctx , resp , req )
271301 if ! ok {
272302 return
@@ -336,6 +366,18 @@ func (r *sfxReceiver) failRequest(
336366 )
337367}
338368
369+ func (r * sfxReceiver ) addAccessTokenLabel (md pmetric.Metrics , req * http.Request ) {
370+ if r .config .AccessTokenPassthrough {
371+ if accessToken := req .Header .Get (splunk .SFxAccessTokenHeader ); accessToken != "" {
372+ for i := 0 ; i < md .ResourceMetrics ().Len (); i ++ {
373+ rm := md .ResourceMetrics ().At (i )
374+ res := rm .Resource ()
375+ res .Attributes ().PutStr (splunk .SFxAccessTokenLabel , accessToken )
376+ }
377+ }
378+ }
379+ }
380+
339381func initJSONResponse (s string ) []byte {
340382 respBody , err := json .Marshal (s )
341383 if err != nil {
0 commit comments