Skip to content

Commit 96b34c3

Browse files
Deprecate experimental/errorsource and remove experimental/errorsource/httpclient (#1150)
* Experimental error source: Deprecate and remove * Update * Fix errors * Fix lint * Update tests * Update experimental/errorsource/error_source_middleware.go Co-authored-by: Will Browne <[email protected]> * Update experimental/errorsource/error_source_middleware.go Co-authored-by: Will Browne <[email protected]> * Update experimental/errorsource/error_source_middleware.go Co-authored-by: Will Browne <[email protected]> * Don't prepend error source before error * Update tests to reflect changes from previous commit --------- Co-authored-by: Will Browne <[email protected]>
1 parent 66c983f commit 96b34c3

File tree

13 files changed

+109
-179
lines changed

13 files changed

+109
-179
lines changed

backend/error_source.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package backend
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67

78
"github.com/grafana/grafana-plugin-sdk-go/experimental/status"
89
)
910

1011
// ErrorSource type defines the source of the error
1112
type ErrorSource = status.Source
13+
type ErrorWithSource = status.ErrorWithSource
1214

1315
const (
1416
// ErrorSourcePlugin error originates from plugin.
@@ -21,6 +23,10 @@ const (
2123
DefaultErrorSource = status.SourcePlugin
2224
)
2325

26+
func NewErrorWithSource(err error, source ErrorSource) ErrorWithSource {
27+
return status.NewErrorWithSource(err, source)
28+
}
29+
2430
// ErrorSourceFromHTTPStatus returns an [ErrorSource] based on provided HTTP status code.
2531
func ErrorSourceFromHTTPStatus(statusCode int) ErrorSource {
2632
return status.SourceFromHTTPStatus(statusCode)
@@ -43,6 +49,11 @@ func DownstreamError(err error) error {
4349
return status.DownstreamError(err)
4450
}
4551

52+
// PluginError creates a new error with status [ErrorSourcePlugin].
53+
func PluginError(err error) error {
54+
return status.PluginError(err)
55+
}
56+
4657
// DownstreamErrorf creates a new error with status [ErrorSourceDownstream] and formats
4758
// according to a format specifier and returns the string as a value that satisfies error.
4859
func DownstreamErrorf(format string, a ...any) error {
@@ -75,3 +86,18 @@ func WithErrorSource(ctx context.Context, s ErrorSource) error {
7586
func WithDownstreamErrorSource(ctx context.Context) error {
7687
return status.WithDownstreamSource(ctx)
7788
}
89+
90+
// Response returns an error DataResponse with error and source of the error if present.
91+
// If the error does not have a source, it keeps the ErrorSource empty.
92+
func ErrorResponseWithErrorSource(err error) DataResponse {
93+
var e ErrorWithSource
94+
if errors.As(err, &e) {
95+
return DataResponse{
96+
Error: e,
97+
ErrorSource: e.ErrorSource(),
98+
}
99+
}
100+
return DataResponse{
101+
Error: err,
102+
}
103+
}

backend/gtime/gtime.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"strings"
88
"time"
99

10-
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
10+
"github.com/grafana/grafana-plugin-sdk-go/backend"
1111
)
1212

1313
var dateUnitPattern = regexp.MustCompile(`^(\d+)([dwMy])$`)
@@ -17,7 +17,7 @@ var dateUnitPattern = regexp.MustCompile(`^(\d+)([dwMy])$`)
1717
func ParseInterval(inp string) (time.Duration, error) {
1818
dur, period, err := parse(inp)
1919
if err != nil {
20-
return 0, errorsource.DownstreamError(err, false)
20+
return 0, backend.DownstreamError(err)
2121
}
2222
if period == "" {
2323
return dur, nil
@@ -39,15 +39,15 @@ func ParseInterval(inp string) (time.Duration, error) {
3939
return now.AddDate(num, 0, 0).Sub(now), nil
4040
}
4141

42-
return 0, errorsource.DownstreamError(fmt.Errorf("invalid interval %q", inp), false)
42+
return 0, backend.DownstreamError(fmt.Errorf("invalid interval %q", inp))
4343
}
4444

4545
// ParseDuration parses a duration with support for all units that Grafana uses.
4646
// Durations are independent of wall time.
4747
func ParseDuration(inp string) (time.Duration, error) {
4848
dur, period, err := parse(inp)
4949
if err != nil {
50-
return 0, errorsource.DownstreamError(err, false)
50+
return 0, backend.DownstreamError(err)
5151
}
5252
if period == "" {
5353
return dur, nil
@@ -71,7 +71,7 @@ func ParseDuration(inp string) (time.Duration, error) {
7171
return dur * year, nil
7272
}
7373

74-
return 0, errorsource.DownstreamError(fmt.Errorf("invalid duration %q", inp), false)
74+
return 0, backend.DownstreamError(fmt.Errorf("invalid duration %q", inp))
7575
}
7676

7777
func parse(inp string) (time.Duration, string, error) {

backend/httpclient/error_source_middleware.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ const ErrorSourceMiddlewareName = "ErrorSource"
1111

1212
// ErrorSourceMiddleware inspect the response error and wraps it in a [status.DownstreamError] if [status.IsDownstreamHTTPError] returns true.
1313
func ErrorSourceMiddleware() Middleware {
14-
return NamedMiddlewareFunc(ErrorSourceMiddlewareName, func(_ Options, next http.RoundTripper) http.RoundTripper {
15-
return RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
16-
res, err := next.RoundTrip(req)
17-
if err != nil && status.IsDownstreamHTTPError(err) {
18-
return res, status.DownstreamError(err)
19-
}
14+
return NamedMiddlewareFunc(ErrorSourceMiddlewareName, ErrorSourceRoundTripper)
15+
}
16+
17+
// ErrorSourceRoundTripper inspect the response error and wraps it in a [status.DownstreamError] if [status.IsDownstreamHTTPError] returns true.
18+
func ErrorSourceRoundTripper(_ Options, next http.RoundTripper) http.RoundTripper {
19+
return RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
20+
res, err := next.RoundTrip(req)
21+
if err != nil && status.IsDownstreamHTTPError(err) {
22+
return res, status.DownstreamError(err)
23+
}
2024

21-
return res, err
22-
})
25+
return res, err
2326
})
2427
}

backend/proxy/secure_socks_proxy_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ func TestInstrumentedSocksDialer(t *testing.T) {
350350
c, err := cd.DialContext(context.Background(), "n", "addr")
351351
assert.Nil(t, c)
352352
assert.NotNil(t, err)
353-
assert.Equal(t, "downstream error: custom error", err.Error())
353+
assert.Equal(t, "custom error", err.Error())
354354
})
355355
}
356356

data/sqlutil/scanrow.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"fmt"
66
"reflect"
77

8-
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
8+
"github.com/grafana/grafana-plugin-sdk-go/backend"
99
)
1010

1111
// A ScanRow is a container for SQL metadata for a single row.
@@ -62,7 +62,7 @@ func MakeScanRow(colTypes []*sql.ColumnType, colNames []string, converters ...Co
6262
seen := map[string]int{}
6363
for i, name := range colNames {
6464
if j, ok := seen[name]; ok {
65-
return nil, errorsource.DownstreamError(fmt.Errorf(`duplicate column names are not allowed, found identical name "%v" at column indices %v and %v`, name, j, i), false)
65+
return nil, backend.DownstreamError(fmt.Errorf(`duplicate column names are not allowed, found identical name "%v" at column indices %v and %v`, name, j, i))
6666
}
6767
seen[name] = i
6868
}

experimental/errorsource/error_source.go

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,103 +6,73 @@ import (
66
"github.com/grafana/grafana-plugin-sdk-go/backend"
77
)
88

9-
func New(err error, source backend.ErrorSource, status backend.Status) Error {
10-
return Error{err: err, source: source, status: status}
11-
}
12-
13-
// Error captures error source and implements the error interface
14-
type Error struct {
15-
source backend.ErrorSource
16-
status backend.Status
17-
18-
err error
19-
}
9+
type Error = backend.ErrorWithSource
2010

21-
// Error implements the interface
22-
func (r Error) Error() string {
23-
return r.err.Error()
24-
}
25-
26-
// Unwrap implements the interface
27-
func (r Error) Unwrap() error {
28-
return r.err
29-
}
30-
31-
// Source provides the error source
32-
func (r Error) Source() backend.ErrorSource {
33-
return r.source
34-
}
35-
36-
func (r Error) ErrorSource() backend.ErrorSource {
37-
return r.source
11+
// New creates a new error with the source
12+
// Deprecated: use backend.NewErrorWithSource instead
13+
func New(err error, source backend.ErrorSource, _ backend.Status) Error {
14+
// We are not using status here, but we are keeping it for compatibility
15+
return backend.NewErrorWithSource(err, source)
3816
}
3917

4018
// PluginError will apply the source as plugin
41-
func PluginError(err error, override bool) error {
19+
// Deprecated: use backend.PluginError instead
20+
func PluginError(err error, _ bool) error {
4221
if err != nil {
43-
return SourceError(backend.ErrorSourcePlugin, err, override)
22+
return backend.PluginError(err)
4423
}
4524
return nil
4625
}
4726

4827
// DownstreamError will apply the source as downstream
49-
func DownstreamError(err error, override bool) error {
28+
// Deprecated: use backend.DownstreamError instead
29+
func DownstreamError(err error, _ bool) error {
5030
if err != nil {
51-
return SourceError(backend.ErrorSourceDownstream, err, override)
31+
return backend.DownstreamError(err)
5232
}
5333
return nil
5434
}
5535

5636
// SourceError returns an error with the source
5737
// If source is already defined, it will return it, or you can override
38+
// Deprecated: Use backend.DownstreamError or backend.PluginError instead
5839
func SourceError(source backend.ErrorSource, err error, override bool) Error {
5940
var sourceError Error
6041
if errors.As(err, &sourceError) && !override {
6142
return sourceError // already has a source
6243
}
63-
return Error{
64-
source: source,
65-
err: err,
66-
}
44+
return New(err, source, 0)
6745
}
6846

6947
// Response returns an error DataResponse given status, source of the error and message.
48+
// Deprecated: Use backend.ErrorResponseWithErrorSource instead
7049
func Response(err error) backend.DataResponse {
71-
var e Error
72-
if !errors.As(err, &e) {
73-
// generic error, default to "plugin" error source
74-
return backend.DataResponse{
75-
Error: err,
76-
ErrorSource: backend.ErrorSourcePlugin,
77-
Status: backend.StatusUnknown,
78-
}
79-
}
80-
return backend.DataResponse{
81-
Error: err,
82-
ErrorSource: e.source,
83-
Status: e.status,
84-
}
50+
return backend.ErrorResponseWithErrorSource(err)
8551
}
8652

8753
// FromStatus returns error source from status
54+
// Deprecated: Use backend.ErrorSourceFromHTTPStatus instead
8855
func FromStatus(status backend.Status) backend.ErrorSource {
8956
return backend.ErrorSourceFromHTTPStatus(int(status))
9057
}
9158

9259
// AddPluginErrorToResponse adds the error as plugin error source to the response
9360
// if the error already has a source, the existing source will be used
61+
// Deprecated: Use backend.ErrorResponse instead
9462
func AddPluginErrorToResponse(refID string, response *backend.QueryDataResponse, err error) *backend.QueryDataResponse {
9563
return AddErrorToResponse(refID, response, PluginError(err, false))
9664
}
9765

9866
// AddDownstreamErrorToResponse adds the error as downstream source to the response
9967
// if the error already has a source, the existing source will be used
68+
// Deprecated: Use backend.ErrorResponse instead and set the response directly
10069
func AddDownstreamErrorToResponse(refID string, response *backend.QueryDataResponse, err error) *backend.QueryDataResponse {
10170
return AddErrorToResponse(refID, response, DownstreamError(err, false))
10271
}
10372

10473
// AddErrorToResponse adds the error to the response
74+
// Deprecated: Use backend.ErrorResponse instead and set the response directly
10575
func AddErrorToResponse(refID string, response *backend.QueryDataResponse, err error) *backend.QueryDataResponse {
106-
response.Responses[refID] = Response(err)
76+
response.Responses[refID] = backend.ErrorResponseWithErrorSource(err)
10777
return response
10878
}

experimental/errorsource/error_source_middleware.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import (
66

77
"github.com/grafana/grafana-plugin-sdk-go/backend"
88
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
9-
"github.com/grafana/grafana-plugin-sdk-go/experimental/status"
109
)
1110

1211
// Middleware captures error source metric
12+
// Deprecated: If you are using sdk httpclient, this is already included in the default middleware.
13+
// If you are not using the sdk httpclient, you should use httpclient.ErrorSourceMiddleware instead.
1314
func Middleware(plugin string) httpclient.Middleware {
1415
return httpclient.NamedMiddlewareFunc(plugin, RoundTripper)
1516
}
1617

1718
// RoundTripper returns the error source
19+
// Deprecated: If you are using sdk httpclient, this is already included in the default middleware.
20+
// If you are not using the sdk httpclient, you should use httpclient.ErrorSourceRoundTripper instead.
1821
func RoundTripper(_ httpclient.Options, next http.RoundTripper) http.RoundTripper {
1922
return httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
2023
res, err := next.RoundTrip(req)
@@ -23,11 +26,11 @@ func RoundTripper(_ httpclient.Options, next http.RoundTripper) http.RoundTrippe
2326
if err == nil {
2427
err = errors.New(res.Status)
2528
}
26-
return res, Error{source: errorSource, err: err}
29+
return res, backend.NewErrorWithSource(err, errorSource)
2730
}
2831

29-
if status.IsDownstreamHTTPError(err) {
30-
return res, Error{source: backend.ErrorSourceDownstream, err: err}
32+
if backend.IsDownstreamHTTPError(err) {
33+
return res, backend.NewErrorWithSource(err, backend.ErrorSourceDownstream)
3134
}
3235

3336
return res, err

experimental/errorsource/error_source_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,18 @@ func TestResponse(t *testing.T) {
2020
{
2121
name: "generic error",
2222
err: errors.New("other"),
23-
expStatus: backend.StatusUnknown,
2423
expErrorMessage: "other",
25-
expErrorSource: backend.ErrorSourcePlugin,
24+
expErrorSource: "",
2625
},
2726
{
2827
name: "downstream error",
2928
err: DownstreamError(errors.New("bad gateway"), false),
30-
expStatus: 0,
3129
expErrorMessage: "bad gateway",
3230
expErrorSource: backend.ErrorSourceDownstream,
3331
},
3432
{
3533
name: "plugin error",
3634
err: PluginError(errors.New("internal error"), false),
37-
expStatus: 0,
3835
expErrorMessage: "internal error",
3936
expErrorSource: backend.ErrorSourcePlugin,
4037
},
@@ -78,7 +75,6 @@ func TestResponseWithOptions(t *testing.T) {
7875
t.Run(tc.name, func(t *testing.T) {
7976
res := Response(tc.err)
8077
require.Error(t, res.Error)
81-
require.Equal(t, tc.expStatus, res.Status)
8278
require.Equal(t, tc.expErrorMessage, res.Error.Error())
8379
require.Equal(t, tc.expErrorSource, res.ErrorSource)
8480
})

experimental/errorsource/httpclient/http_client.go

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)