Skip to content

Commit b9a0715

Browse files
MovieStoreGuyLucianoGiannotti
authored andcommitted
Enhancement: Add path to Splunk errors (open-telemetry#39026)
#### Description To help clarify what endpoint is being used within the collector once errors are being reported, this makes it apparent to all which is the impacted endpoint. #### Link to tracking issue Tracked externally #### Testing Updated existing tests. #### Documentation No user facing changes made, no additional documentation required.
1 parent d95a817 commit b9a0715

File tree

7 files changed

+114
-37
lines changed

7 files changed

+114
-37
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: signalfxexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Errors will now include the URL that it was trying to access
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [ 39026 ]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [ user ]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: splunkhecexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Errors will now include the URL that it was trying to access
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [ 39026 ]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

exporter/signalfxexporter/exporter_test.go

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"crypto/tls"
1010
"encoding/json"
11+
"errors"
1112
"fmt"
1213
"io"
1314
"net/http"
@@ -122,7 +123,7 @@ func TestConsumeMetrics(t *testing.T) {
122123
wantErr bool
123124
wantPermanentErr bool
124125
wantThrottleErr bool
125-
expectedErrorMsg string
126+
wantStatusCode int
126127
}{
127128
{
128129
name: "happy_path",
@@ -135,22 +136,23 @@ func TestConsumeMetrics(t *testing.T) {
135136
httpResponseCode: http.StatusForbidden,
136137
numDroppedTimeSeries: 1,
137138
wantErr: true,
138-
expectedErrorMsg: "HTTP 403 \"Forbidden\"",
139+
wantStatusCode: 403,
139140
},
140141
{
141142
name: "response_bad_request",
142143
md: smallBatch,
143144
httpResponseCode: http.StatusBadRequest,
144145
numDroppedTimeSeries: 1,
145146
wantPermanentErr: true,
146-
expectedErrorMsg: "Permanent error: \"HTTP/1.1 400 Bad Request",
147+
wantStatusCode: 400,
147148
},
148149
{
149150
name: "response_throttle",
150151
md: smallBatch,
151152
httpResponseCode: http.StatusTooManyRequests,
152153
numDroppedTimeSeries: 1,
153154
wantThrottleErr: true,
155+
wantStatusCode: 429,
154156
},
155157
{
156158
name: "response_throttle_with_header",
@@ -159,6 +161,7 @@ func TestConsumeMetrics(t *testing.T) {
159161
httpResponseCode: http.StatusServiceUnavailable,
160162
numDroppedTimeSeries: 1,
161163
wantThrottleErr: true,
164+
wantStatusCode: 503,
162165
},
163166
{
164167
name: "large_batch",
@@ -207,25 +210,29 @@ func TestConsumeMetrics(t *testing.T) {
207210
converter: c,
208211
}
209212

213+
errMsg := fmt.Sprintf("HTTP \"/v2/datapoint\" %d %q",
214+
tt.wantStatusCode,
215+
http.StatusText(tt.wantStatusCode),
216+
)
217+
210218
numDroppedTimeSeries, err := dpClient.pushMetricsData(context.Background(), tt.md)
211219
assert.Equal(t, tt.numDroppedTimeSeries, numDroppedTimeSeries)
212220

213221
if tt.wantErr {
214222
assert.Error(t, err)
215-
assert.EqualError(t, err, tt.expectedErrorMsg)
223+
assert.EqualError(t, err, errMsg)
216224
return
217225
}
218226

219227
if tt.wantPermanentErr {
220228
assert.Error(t, err)
221229
assert.True(t, consumererror.IsPermanent(err))
222-
assert.True(t, strings.HasPrefix(err.Error(), tt.expectedErrorMsg))
223-
assert.ErrorContains(t, err, "response content")
230+
assert.ErrorContains(t, err, errMsg)
224231
return
225232
}
226233

227234
if tt.wantThrottleErr {
228-
expected := fmt.Errorf("HTTP %d %q", tt.httpResponseCode, http.StatusText(tt.httpResponseCode))
235+
expected := errors.New(errMsg)
229236
expected = exporterhelper.NewThrottleRetry(expected, time.Duration(tt.retryAfter)*time.Second)
230237
assert.EqualValues(t, expected, err)
231238
return
@@ -1892,8 +1899,8 @@ func TestConsumeMixedMetrics(t *testing.T) {
18921899
wantErr bool
18931900
wantPermanentErr bool
18941901
wantThrottleErr bool
1895-
expectedErrorMsg string
18961902
wantPartialMetricsErr bool
1903+
wantStatusCode int
18971904
}{
18981905
{
18991906
name: "happy_path",
@@ -1912,15 +1919,15 @@ func TestConsumeMixedMetrics(t *testing.T) {
19121919
sfxHTTPResponseCode: http.StatusForbidden,
19131920
numDroppedTimeSeries: 1,
19141921
wantErr: true,
1915-
expectedErrorMsg: "HTTP 403 \"Forbidden\"",
1922+
wantStatusCode: 403,
19161923
},
19171924
{
19181925
name: "response_forbidden_otlp",
19191926
md: smallBatchHistogramOnly,
19201927
otlpHTTPResponseCode: http.StatusForbidden,
19211928
numDroppedTimeSeries: 2,
19221929
wantErr: true,
1923-
expectedErrorMsg: "HTTP 403 \"Forbidden\"",
1930+
wantStatusCode: 403,
19241931
},
19251932
{
19261933
name: "response_forbidden_mixed",
@@ -1929,23 +1936,23 @@ func TestConsumeMixedMetrics(t *testing.T) {
19291936
otlpHTTPResponseCode: http.StatusForbidden,
19301937
numDroppedTimeSeries: 2,
19311938
wantErr: true,
1932-
expectedErrorMsg: "HTTP 403 \"Forbidden\"",
1939+
wantStatusCode: 403,
19331940
},
19341941
{
19351942
name: "response_bad_request_sfx",
19361943
md: smallBatch,
19371944
sfxHTTPResponseCode: http.StatusBadRequest,
19381945
numDroppedTimeSeries: 1,
19391946
wantPermanentErr: true,
1940-
expectedErrorMsg: "Permanent error: \"HTTP/1.1 400 Bad Request",
1947+
wantStatusCode: 400,
19411948
},
19421949
{
19431950
name: "response_bad_request_otlp",
19441951
md: smallBatchHistogramOnly,
19451952
otlpHTTPResponseCode: http.StatusBadRequest,
19461953
numDroppedTimeSeries: 2,
19471954
wantPermanentErr: true,
1948-
expectedErrorMsg: "Permanent error: \"HTTP/1.1 400 Bad Request",
1955+
wantStatusCode: 400,
19491956
},
19501957
{
19511958
name: "response_bad_request_mixed",
@@ -1954,14 +1961,15 @@ func TestConsumeMixedMetrics(t *testing.T) {
19541961
otlpHTTPResponseCode: http.StatusBadRequest,
19551962
numDroppedTimeSeries: 2,
19561963
wantPermanentErr: true,
1957-
expectedErrorMsg: "Permanent error: \"HTTP/1.1 400 Bad Request",
1964+
wantStatusCode: 400,
19581965
},
19591966
{
19601967
name: "response_throttle_sfx",
19611968
md: smallBatch,
19621969
sfxHTTPResponseCode: http.StatusTooManyRequests,
19631970
numDroppedTimeSeries: 1,
19641971
wantThrottleErr: true,
1972+
wantStatusCode: 429,
19651973
},
19661974
{
19671975
name: "response_throttle_mixed",
@@ -1971,6 +1979,7 @@ func TestConsumeMixedMetrics(t *testing.T) {
19711979
numDroppedTimeSeries: 2,
19721980
wantThrottleErr: true,
19731981
wantPartialMetricsErr: true,
1982+
wantStatusCode: 429,
19741983
},
19751984
{
19761985
name: "response_throttle_otlp",
@@ -1979,6 +1988,7 @@ func TestConsumeMixedMetrics(t *testing.T) {
19791988
numDroppedTimeSeries: 2,
19801989
wantThrottleErr: true,
19811990
wantPartialMetricsErr: true,
1991+
wantStatusCode: 429,
19821992
},
19831993
{
19841994
name: "response_throttle_with_header_sfx",
@@ -1987,6 +1997,7 @@ func TestConsumeMixedMetrics(t *testing.T) {
19871997
sfxHTTPResponseCode: http.StatusServiceUnavailable,
19881998
numDroppedTimeSeries: 1,
19891999
wantThrottleErr: true,
2000+
wantStatusCode: 503,
19902001
},
19912002
{
19922003
name: "response_throttle_with_header_otlp",
@@ -1996,6 +2007,7 @@ func TestConsumeMixedMetrics(t *testing.T) {
19962007
numDroppedTimeSeries: 2,
19972008
wantThrottleErr: true,
19982009
wantPartialMetricsErr: true,
2010+
wantStatusCode: 503,
19992011
},
20002012
{
20012013
name: "response_throttle_with_header_mixed",
@@ -2006,6 +2018,7 @@ func TestConsumeMixedMetrics(t *testing.T) {
20062018
numDroppedTimeSeries: 2,
20072019
wantThrottleErr: true,
20082020
wantPartialMetricsErr: true,
2021+
wantStatusCode: 503,
20092022
},
20102023
{
20112024
name: "large_batch",
@@ -2065,31 +2078,36 @@ func TestConsumeMixedMetrics(t *testing.T) {
20652078
numDroppedTimeSeries, err := sfxClient.pushMetricsData(context.Background(), tt.md)
20662079
assert.Equal(t, tt.numDroppedTimeSeries, numDroppedTimeSeries)
20672080

2081+
errMsg := fmt.Sprintf("HTTP \"/v2/datapoint\" %d %q",
2082+
tt.wantStatusCode,
2083+
http.StatusText(tt.wantStatusCode),
2084+
)
2085+
20682086
if tt.wantErr {
20692087
assert.Error(t, err)
2070-
assert.EqualError(t, err, tt.expectedErrorMsg)
2088+
assert.EqualError(t, err, errMsg)
20712089
return
20722090
}
20732091

20742092
if tt.wantPermanentErr {
2093+
errMsg = "Permanent error: " + errMsg
20752094
assert.Error(t, err)
20762095
assert.True(t, consumererror.IsPermanent(err))
2077-
assert.True(t, strings.HasPrefix(err.Error(), tt.expectedErrorMsg))
2078-
assert.ErrorContains(t, err, "response content")
2096+
assert.EqualError(t, err, errMsg)
20792097
return
20802098
}
20812099

20822100
if tt.wantThrottleErr {
20832101
if tt.wantPartialMetricsErr {
20842102
partialMetrics, _ := utils.GetHistograms(smallBatch)
2085-
throttleErr := fmt.Errorf("HTTP %d %q", tt.otlpHTTPResponseCode, http.StatusText(tt.otlpHTTPResponseCode))
2103+
throttleErr := errors.New(errMsg)
20862104
throttleErr = exporterhelper.NewThrottleRetry(throttleErr, time.Duration(tt.retryAfter)*time.Second)
20872105
testErr := consumererror.NewMetrics(throttleErr, partialMetrics)
20882106
assert.EqualValues(t, testErr, err)
20892107
return
20902108
}
20912109

2092-
expected := fmt.Errorf("HTTP %d %q", tt.sfxHTTPResponseCode, http.StatusText(tt.sfxHTTPResponseCode))
2110+
expected := errors.New(errMsg)
20932111
expected = exporterhelper.NewThrottleRetry(expected, time.Duration(tt.retryAfter)*time.Second)
20942112
assert.EqualValues(t, expected, err)
20952113
return

exporter/splunkhecexporter/client_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ func newTestClientWithPresetResponses(codes []int, bodies []string) (*http.Clien
6666

6767
return &http.Response{
6868
StatusCode: code,
69+
Request: req,
6970
Body: io.NopCloser(bytes.NewBufferString(body)),
7071
Header: make(http.Header),
7172
}
@@ -1316,7 +1317,11 @@ func TestErrorReceived(t *testing.T) {
13161317
case <-time.After(5 * time.Second):
13171318
t.Fatal("Should have received request")
13181319
}
1319-
assert.EqualError(t, err, "HTTP 500 \"Internal Server Error\"")
1320+
errMsg := fmt.Sprintf("HTTP \"/services/collector\" %d %q",
1321+
http.StatusInternalServerError,
1322+
http.StatusText(http.StatusInternalServerError),
1323+
)
1324+
assert.EqualError(t, err, errMsg)
13201325
}
13211326

13221327
func TestInvalidLogs(t *testing.T) {
@@ -1394,7 +1399,9 @@ func TestHeartbeatStartupFailed(t *testing.T) {
13941399
assert.NoError(t, err)
13951400
assert.EqualError(t,
13961401
exporter.Start(context.Background(), componenttest.NewNopHost()),
1397-
fmt.Sprintf("%s: heartbeat on startup failed: HTTP 403 \"Forbidden\"", params.ID.String()),
1402+
fmt.Sprintf("%s: heartbeat on startup failed: HTTP \"/services/collector\" 403 \"Forbidden\"",
1403+
params.ID.String(),
1404+
),
13981405
)
13991406
assert.NoError(t, exporter.Shutdown(context.Background()))
14001407
}
@@ -1593,7 +1600,7 @@ func Test_pushLogData_PostError(t *testing.T) {
15931600

15941601
func Test_pushLogData_ShouldAddResponseTo400Error(t *testing.T) {
15951602
config := NewFactory().CreateDefaultConfig().(*Config)
1596-
url := &url.URL{Scheme: "http", Host: "splunk"}
1603+
url := &url.URL{Scheme: "http", Host: "splunk", Path: "/v1/endpoint"}
15971604
splunkClient := newLogsClient(exportertest.NewNopSettings(metadata.Type), NewFactory().CreateDefaultConfig().(*Config))
15981605
logs := createLogData(1, 1, 1)
15991606

@@ -1605,17 +1612,16 @@ func Test_pushLogData_ShouldAddResponseTo400Error(t *testing.T) {
16051612
// Sending logs using the client.
16061613
err := splunkClient.pushLogData(context.Background(), logs)
16071614
require.True(t, consumererror.IsPermanent(err), "Expecting permanent error")
1608-
require.ErrorContains(t, err, "HTTP/0.0 400")
1615+
require.EqualError(t, err, "Permanent error: HTTP \"/v1/endpoint\" 400 \"Bad Request\"")
16091616
// The returned error should contain the response body responseBody.
1610-
assert.ErrorContains(t, err, responseBody)
16111617

16121618
// An HTTP client that returns some other status code other than 400 and response body responseBody.
16131619
httpClient, _ = newTestClient(500, responseBody)
16141620
splunkClient.hecWorker = &defaultHecWorker{url, httpClient, buildHTTPHeaders(config, component.NewDefaultBuildInfo()), zap.NewNop()}
16151621
// Sending logs using the client.
16161622
err = splunkClient.pushLogData(context.Background(), logs)
16171623
require.False(t, consumererror.IsPermanent(err), "Expecting non-permanent error")
1618-
require.ErrorContains(t, err, "HTTP 500")
1624+
require.EqualError(t, err, "HTTP \"/v1/endpoint\" 500 \"Internal Server Error\"")
16191625
// The returned error should not contain the response body responseBody.
16201626
assert.NotContains(t, err.Error(), responseBody)
16211627
}

internal/splunk/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ require (
99
go.opentelemetry.io/collector/pdata v1.29.1-0.20250402200755-cb5c3f4fb9dc
1010
go.opentelemetry.io/collector/semconv v0.123.1-0.20250402200755-cb5c3f4fb9dc
1111
go.uber.org/goleak v1.3.0
12-
go.uber.org/multierr v1.11.0
1312
)
1413

1514
require (
@@ -47,6 +46,7 @@ require (
4746
go.opentelemetry.io/otel/metric v1.35.0 // indirect
4847
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
4948
go.opentelemetry.io/otel/trace v1.35.0 // indirect
49+
go.uber.org/multierr v1.11.0 // indirect
5050
go.uber.org/zap v1.27.0 // indirect
5151
golang.org/x/net v0.37.0 // indirect
5252
golang.org/x/sys v0.31.0 // indirect

0 commit comments

Comments
 (0)