Skip to content

Commit

Permalink
[receiver/splunkhec] Align hec receiver errors messages to splunk ent…
Browse files Browse the repository at this point in the history
…erprise (#19769)

* Align hec receiver errors messages to splunk enterprise

* include chlog

* revert removing obsrecv in raw
  • Loading branch information
timannguyen authored Mar 19, 2023
1 parent ce31815 commit 8ec09d3
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 11 deletions.
11 changes: 11 additions & 0 deletions .chloggen/splunkhecreceiver-align-error-message.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: splunkhecreceiver

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: align error message with splunk enterprise to include No Data, Invalid Data Format, Event field is required, and Event field cannot be blank

# One or more tracking issues related to the change
issues: [19219]
27 changes: 22 additions & 5 deletions receiver/splunkhecreceiver/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,16 @@ const (
responseOK = "OK"
responseInvalidMethod = `Only "POST" method is supported`
responseInvalidEncoding = `"Content-Encoding" must be "gzip" or empty`
responseInvalidDataFormat = `{"text":"Invalid data format","code":6}`
responseErrEventRequired = `{"text":"Event field is required","code":12}`
responseErrEventBlank = `{"text":"Event field cannot be blank","code":13}`
responseErrGzipReader = "Error on gzip body"
responseErrUnmarshalBody = "Failed to unmarshal message body"
responseErrInternalServerError = "Internal Server Error"
responseErrUnsupportedMetricEvent = "Unsupported metric event"
responseErrUnsupportedLogEvent = "Unsupported log event"
responseErrHandlingIndexedFields = `{"text":"Error in handling indexed fields","code":15,"invalid-event-number":%d}`
responseNoData = `{"text":"No data","code":5}`
// Centralizing some HTTP and related string constants.
gzipEncoding = "gzip"
httpContentEncodingHeader = "Content-Encoding"
Expand All @@ -64,13 +68,17 @@ var (
errInvalidEncoding = errors.New("invalid encoding")

okRespBody = initJSONResponse(responseOK)
invalidMethodRespBody = initJSONResponse(responseInvalidMethod)
eventRequiredRespBody = initJSONResponse(responseErrEventRequired)
eventBlankRespBody = initJSONResponse(responseErrEventBlank)
invalidEncodingRespBody = initJSONResponse(responseInvalidEncoding)
invalidFormatRespBody = initJSONResponse(responseInvalidDataFormat)
invalidMethodRespBody = initJSONResponse(responseInvalidMethod)
errGzipReaderRespBody = initJSONResponse(responseErrGzipReader)
errUnmarshalBodyRespBody = initJSONResponse(responseErrUnmarshalBody)
errInternalServerError = initJSONResponse(responseErrInternalServerError)
errUnsupportedMetricEvent = initJSONResponse(responseErrUnsupportedMetricEvent)
errUnsupportedLogEvent = initJSONResponse(responseErrUnsupportedLogEvent)
noDataRespBody = initJSONResponse(responseNoData)
)

// splunkReceiver implements the receiver.Metrics for Splunk HEC metric protocol.
Expand Down Expand Up @@ -246,6 +254,7 @@ func (r *splunkReceiver) handleRawReq(resp http.ResponseWriter, req *http.Reques

if req.ContentLength == 0 {
r.obsrecv.EndLogsOp(ctx, typeStr, 0, nil)
r.failRequest(ctx, resp, http.StatusBadRequest, noDataRespBody, 0, nil)
return
}

Expand Down Expand Up @@ -311,9 +320,7 @@ func (r *splunkReceiver) handleReq(resp http.ResponseWriter, req *http.Request)
}

if req.ContentLength == 0 {
if _, err := resp.Write(okRespBody); err != nil {
r.failRequest(ctx, resp, http.StatusInternalServerError, errInternalServerError, 0, err)
}
r.failRequest(ctx, resp, http.StatusBadRequest, noDataRespBody, 0, nil)
return
}

Expand All @@ -325,7 +332,17 @@ func (r *splunkReceiver) handleReq(resp http.ResponseWriter, req *http.Request)
var msg splunk.Event
err := dec.Decode(&msg)
if err != nil {
r.failRequest(ctx, resp, http.StatusBadRequest, errUnmarshalBodyRespBody, len(events), err)
r.failRequest(ctx, resp, http.StatusBadRequest, invalidFormatRespBody, len(events), err)
return
}

if msg.Event == nil {
r.failRequest(ctx, resp, http.StatusBadRequest, eventRequiredRespBody, len(events), nil)
return
}

if msg.Event == "" {
r.failRequest(ctx, resp, http.StatusBadRequest, eventBlankRespBody, len(events), nil)
return
}

Expand Down
58 changes: 52 additions & 6 deletions receiver/splunkhecreceiver/receiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@ func Test_splunkhecReceiver_handleReq(t *testing.T) {
{
name: "incorrect_content_type",
req: func() *http.Request {
req := httptest.NewRequest("POST", "http://localhost/foo", nil)
msgBytes, err := json.Marshal(splunkMsg)
require.NoError(t, err)
req := httptest.NewRequest("POST", "http://localhost/foo", bytes.NewReader(msgBytes))
req.Header.Set("Content-Type", "application/not-json")
return req
}(),
Expand Down Expand Up @@ -234,7 +236,7 @@ func Test_splunkhecReceiver_handleReq(t *testing.T) {
}(),
assertResponse: func(t *testing.T, status int, body string) {
assert.Equal(t, http.StatusBadRequest, status)
assert.Equal(t, responseErrUnmarshalBody, body)
assert.Equal(t, responseInvalidDataFormat, body)
},
},
{
Expand All @@ -244,8 +246,51 @@ func Test_splunkhecReceiver_handleReq(t *testing.T) {
return req
}(),
assertResponse: func(t *testing.T, status int, body string) {
assert.Equal(t, http.StatusOK, status)
assert.Equal(t, responseOK, body)
assert.Equal(t, http.StatusBadRequest, status)
assert.Equal(t, responseNoData, body)
},
},
{
name: "invalid_data_format",
req: func() *http.Request {
msgBytes, err := json.Marshal(`{"foo":"bar"}`)
require.NoError(t, err)
req := httptest.NewRequest("POST", "http://localhost/foo", bytes.NewReader(msgBytes))
return req
}(),
assertResponse: func(t *testing.T, status int, body string) {
assert.Equal(t, http.StatusBadRequest, status)
assert.Equal(t, responseInvalidDataFormat, body)
},
},
{
name: "event_required_error",
req: func() *http.Request {
nilEventMsg := buildSplunkHecMsg(currentTime, 3)
nilEventMsg.Event = nil
msgBytes, err := json.Marshal(nilEventMsg)
require.NoError(t, err)
req := httptest.NewRequest("POST", "http://localhost/foo", bytes.NewReader(msgBytes))
return req
}(),
assertResponse: func(t *testing.T, status int, body string) {
assert.Equal(t, http.StatusBadRequest, status)
assert.Equal(t, responseErrEventRequired, body)
},
},
{
name: "event_cannot_be_blank_error",
req: func() *http.Request {
blankEventMsg := buildSplunkHecMsg(currentTime, 3)
blankEventMsg.Event = ""
msgBytes, err := json.Marshal(blankEventMsg)
require.NoError(t, err)
req := httptest.NewRequest("POST", "http://localhost/foo", bytes.NewReader(msgBytes))
return req
}(),
assertResponse: func(t *testing.T, status int, body string) {
assert.Equal(t, http.StatusBadRequest, status)
assert.Equal(t, responseErrEventBlank, body)
},
},
{
Expand Down Expand Up @@ -864,7 +909,7 @@ func Test_splunkhecReceiver_handleRawReq(t *testing.T) {
{
name: "incorrect_content_type",
req: func() *http.Request {
req := httptest.NewRequest("POST", "http://localhost/foo", nil)
req := httptest.NewRequest("POST", "http://localhost/foo", strings.NewReader("foo\nbar"))
req.Header.Set("Content-Type", "application/not-json")
return req
}(),
Expand All @@ -891,7 +936,8 @@ func Test_splunkhecReceiver_handleRawReq(t *testing.T) {
return req
}(),
assertResponse: func(t *testing.T, status int, body string) {
assert.Equal(t, http.StatusOK, status)
assert.Equal(t, http.StatusBadRequest, status)
assert.Equal(t, responseNoData, body)
},
},

Expand Down

0 comments on commit 8ec09d3

Please sign in to comment.