From 404b14c512c28a6787f2b68bc92b6d3510fa14a6 Mon Sep 17 00:00:00 2001 From: braydonk Date: Fri, 3 Oct 2025 13:51:26 +0000 Subject: [PATCH 01/16] consumererror: Add partial error type This PR adds functionality for consumers to create a partial error type. This will allow consumers to properly report partial success/failure with failed item counts, which can subsequently be used when reporting sent/failed metrics. --- .chloggen/consumererror_partial_success.yaml | 25 +++++++++++ consumer/consumererror/partial.go | 44 ++++++++++++++++++++ consumer/consumererror/partial_test.go | 19 +++++++++ 3 files changed, 88 insertions(+) create mode 100644 .chloggen/consumererror_partial_success.yaml create mode 100644 consumer/consumererror/partial.go create mode 100644 consumer/consumererror/partial_test.go diff --git a/.chloggen/consumererror_partial_success.yaml b/.chloggen/consumererror_partial_success.yaml new file mode 100644 index 00000000000..4d479b03eb8 --- /dev/null +++ b/.chloggen/consumererror_partial_success.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# 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. otlpreceiver) +component: consumererror + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add new partial error type to consumererror to allow consumers to report partial successes. + +# One or more tracking issues or pull requests related to the change +issues: [13423] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/consumer/consumererror/partial.go b/consumer/consumererror/partial.go new file mode 100644 index 00000000000..a401565b487 --- /dev/null +++ b/consumer/consumererror/partial.go @@ -0,0 +1,44 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package consumererror // import "go.opentelemetry.io/collector/consumer/consumererror" + +import "errors" + +type partialError struct { + inner error + failed int +} + +var _ error = partialError{} + +func (pe partialError) Error() string { + return pe.inner.Error() +} + +func (pe partialError) Unwrap() error { + return pe.inner +} + +func (pe partialError) Failed() int { + return pe.failed +} + +// NewPartial creates a new partial error. This is used by consumers +// to report errors where only a subset of the total items failed +// to be written, but it is not possible to tell which particular items +// failed. +func NewPartial(err error, failed int) error { + return NewPermanent(partialError{ + inner: err, + failed: failed, + }) +} + +// AsPartial checks if an error was wrapped with the NewPartial function, +// or if it contains one such error in its Unwrap() tree. +func AsPartial(err error) (partialError, bool) { + var pe partialError + ok := errors.As(err, &pe) + return pe, ok +} diff --git a/consumer/consumererror/partial_test.go b/consumer/consumererror/partial_test.go new file mode 100644 index 00000000000..54f246db9e1 --- /dev/null +++ b/consumer/consumererror/partial_test.go @@ -0,0 +1,19 @@ +package consumererror + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPartial(t *testing.T) { + internalErr := errors.New("some points failed") + err := NewPartial(internalErr, 5) + assert.True(t, IsPermanent(err)) + partialErr, ok := AsPartial(err) + assert.True(t, ok) + assert.Equal(t, 5, partialErr.Failed()) + assert.Equal(t, internalErr, partialErr.Unwrap()) + assert.Equal(t, internalErr.Error(), partialErr.Error()) +} From 69e26963c74cc26832ee1a025d83a3646e5123e2 Mon Sep 17 00:00:00 2001 From: braydonk Date: Fri, 3 Oct 2025 13:53:43 +0000 Subject: [PATCH 02/16] add licenses --- consumer/consumererror/partial_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/consumer/consumererror/partial_test.go b/consumer/consumererror/partial_test.go index 54f246db9e1..00c3979e58e 100644 --- a/consumer/consumererror/partial_test.go +++ b/consumer/consumererror/partial_test.go @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + package consumererror import ( From fbbad1d9e6bf96c2b4fbc76bf48f512d463ed7cf Mon Sep 17 00:00:00 2001 From: braydonk Date: Tue, 11 Nov 2025 19:21:44 +0000 Subject: [PATCH 03/16] move PartialError to xconsumererror --- consumer/consumererror/{ => xconsumererror}/partial.go | 10 +++++++--- .../consumererror/{ => xconsumererror}/partial_test.go | 5 +++-- 2 files changed, 10 insertions(+), 5 deletions(-) rename consumer/consumererror/{ => xconsumererror}/partial.go (79%) rename consumer/consumererror/{ => xconsumererror}/partial_test.go (78%) diff --git a/consumer/consumererror/partial.go b/consumer/consumererror/xconsumererror/partial.go similarity index 79% rename from consumer/consumererror/partial.go rename to consumer/consumererror/xconsumererror/partial.go index a401565b487..7ae72afbb8b 100644 --- a/consumer/consumererror/partial.go +++ b/consumer/consumererror/xconsumererror/partial.go @@ -1,9 +1,13 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package consumererror // import "go.opentelemetry.io/collector/consumer/consumererror" +package xconsumererror // import "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" -import "errors" +import ( + "errors" + + "go.opentelemetry.io/collector/consumer/consumererror" +) type partialError struct { inner error @@ -29,7 +33,7 @@ func (pe partialError) Failed() int { // to be written, but it is not possible to tell which particular items // failed. func NewPartial(err error, failed int) error { - return NewPermanent(partialError{ + return consumererror.NewPermanent(partialError{ inner: err, failed: failed, }) diff --git a/consumer/consumererror/partial_test.go b/consumer/consumererror/xconsumererror/partial_test.go similarity index 78% rename from consumer/consumererror/partial_test.go rename to consumer/consumererror/xconsumererror/partial_test.go index 00c3979e58e..02ff7d0bbf1 100644 --- a/consumer/consumererror/partial_test.go +++ b/consumer/consumererror/xconsumererror/partial_test.go @@ -1,19 +1,20 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package consumererror +package xconsumererror import ( "errors" "testing" "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/consumer/consumererror" ) func TestPartial(t *testing.T) { internalErr := errors.New("some points failed") err := NewPartial(internalErr, 5) - assert.True(t, IsPermanent(err)) + assert.True(t, consumererror.IsPermanent(err)) partialErr, ok := AsPartial(err) assert.True(t, ok) assert.Equal(t, 5, partialErr.Failed()) From 933c0eae53d2865bdb695e7e7430e2d74372d9cc Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 14:37:37 +0000 Subject: [PATCH 04/16] add testable examples and more detailed godoc --- .../consumererror/xconsumererror/partial.go | 22 +++++++--- .../xconsumererror/partial_test.go | 41 +++++++++++++++++-- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/consumer/consumererror/xconsumererror/partial.go b/consumer/consumererror/xconsumererror/partial.go index 7ae72afbb8b..e20891ae25b 100644 --- a/consumer/consumererror/xconsumererror/partial.go +++ b/consumer/consumererror/xconsumererror/partial.go @@ -28,10 +28,20 @@ func (pe partialError) Failed() int { return pe.failed } -// NewPartial creates a new partial error. This is used by consumers -// to report errors where only a subset of the total items failed -// to be written, but it is not possible to tell which particular items -// failed. +// NewPartial creates a new partial error. This is used to report errors +// where only a subset of the total items failed to be written, but it +// is not possible to tell which particular items failed. An example of this +// would be a backend that can report partial successes, but only communicate +// the number of failed items without specifying which specific items failed. +// +// A partial error wraps a PermanentError; it can be treated as any other permanent +// error with no changes, meaning that consumers can transition to producing this +// error when appropriate without breaking any parts of the pipeline that check for +// permanent errors. +// +// In a scenario where the exact items that failed are known and can be retried, +// it's recommended to use the respective signal error ([consumererror.Logs], +// [consumererror.Metrics], or [consumererror.Traces]). func NewPartial(err error, failed int) error { return consumererror.NewPermanent(partialError{ inner: err, @@ -40,7 +50,9 @@ func NewPartial(err error, failed int) error { } // AsPartial checks if an error was wrapped with the NewPartial function, -// or if it contains one such error in its Unwrap() tree. +// or if it contains one such error in its Unwrap() tree. The resulting +// error has a method Failed() that can be used to retrieve the count of +// failed items from the error. func AsPartial(err error) (partialError, bool) { var pe partialError ok := errors.As(err, &pe) diff --git a/consumer/consumererror/xconsumererror/partial_test.go b/consumer/consumererror/xconsumererror/partial_test.go index 02ff7d0bbf1..9aa91e9b04e 100644 --- a/consumer/consumererror/xconsumererror/partial_test.go +++ b/consumer/consumererror/xconsumererror/partial_test.go @@ -1,23 +1,58 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package xconsumererror +package xconsumererror_test import ( "errors" + "fmt" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/consumer/consumererror" + "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" ) func TestPartial(t *testing.T) { internalErr := errors.New("some points failed") - err := NewPartial(internalErr, 5) + err := xconsumererror.NewPartial(internalErr, 5) assert.True(t, consumererror.IsPermanent(err)) - partialErr, ok := AsPartial(err) + partialErr, ok := xconsumererror.AsPartial(err) assert.True(t, ok) assert.Equal(t, 5, partialErr.Failed()) assert.Equal(t, internalErr, partialErr.Unwrap()) assert.Equal(t, internalErr.Error(), partialErr.Error()) } + +func ExampleNewPartial() { + // Produce a partial error. + failedItems := 5 + consumptionErr := errors.New("some points failed to be written") + err := xconsumererror.NewPartial(consumptionErr, failedItems) + fmt.Println(err) + + // Output: "Permanent error: some points failed to be written" +} + +func ExampleAsPartial() { + // Produce a partial error. + partialErr := xconsumererror.NewPartial(errors.New("some points failed to be written"), 10) + + // The result of `xconsumererror.AsPartial` has a method `Failed` + // which can be used to retrieve the failed item count. + if err, ok := xconsumererror.AsPartial(partialErr); ok { + fmt.Println(err.Failed()) + } + + // Output: 10 +} + +func ExampleAsPartial_second() { + // Produce a partial error. + partialErr := xconsumererror.NewPartial(errors.New("some points failed to be written"), 10) + + // Partial errors wrap a Permanent error. + fmt.Println(consumererror.IsPermanent(partialErr)) + + // Output: true +} From 60ca1e8bd6e943487d311dd8b7d0b962b1dd028f Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 15:19:58 +0000 Subject: [PATCH 05/16] run make gotidy --- consumer/consumererror/xconsumererror/go.mod | 4 ++++ consumer/consumererror/xconsumererror/go.sum | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/consumer/consumererror/xconsumererror/go.mod b/consumer/consumererror/xconsumererror/go.mod index c05bfbcaa79..4abbbb50269 100644 --- a/consumer/consumererror/xconsumererror/go.mod +++ b/consumer/consumererror/xconsumererror/go.mod @@ -19,6 +19,10 @@ require ( go.opentelemetry.io/collector/featuregate v1.45.0 // indirect go.opentelemetry.io/collector/pdata v1.45.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/sys v0.34.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/grpc v1.76.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/consumer/consumererror/xconsumererror/go.sum b/consumer/consumererror/xconsumererror/go.sum index 903bf673575..5f7394205ee 100644 --- a/consumer/consumererror/xconsumererror/go.sum +++ b/consumer/consumererror/xconsumererror/go.sum @@ -1,6 +1,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -34,6 +38,16 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= +google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From d16fe30110a14fabdc6558e69155e239a25c6726 Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 15:26:30 +0000 Subject: [PATCH 06/16] add changelog --- .chloggen/partial_error.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .chloggen/partial_error.yaml diff --git a/.chloggen/partial_error.yaml b/.chloggen/partial_error.yaml new file mode 100644 index 00000000000..f0e0a9a272e --- /dev/null +++ b/.chloggen/partial_error.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# 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. otlpreceiver) +component: [consumer/consumererror/xconsumererror] + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add new Partial error, allowing consumers to express a permanent error with a failed item count. + +# One or more tracking issues or pull requests related to the change +issues: [13423] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [api] From d2c3541587d07c7045b64ab6747f7793fff7f93e Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 15:28:17 +0000 Subject: [PATCH 07/16] make gogenerate --- consumer/consumererror/xconsumererror/partial_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/consumer/consumererror/xconsumererror/partial_test.go b/consumer/consumererror/xconsumererror/partial_test.go index 9aa91e9b04e..d96f749674f 100644 --- a/consumer/consumererror/xconsumererror/partial_test.go +++ b/consumer/consumererror/xconsumererror/partial_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" ) From 2f5dd2894265f52131c341337a11526b6e696633 Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 16:49:41 +0000 Subject: [PATCH 08/16] change AsPartial to IsPartial The linter did not like exporting a private type, which is a fair point. I want to keep the error type private so that the only way to produce a partial error also necessitates that it's permanent, so I changed the API to `IsPartial` which produces a count and a boolean. --- .../consumererror/xconsumererror/partial.go | 16 ++++++-------- .../xconsumererror/partial_test.go | 21 +++++++++---------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/consumer/consumererror/xconsumererror/partial.go b/consumer/consumererror/xconsumererror/partial.go index e20891ae25b..2cbe84c34ac 100644 --- a/consumer/consumererror/xconsumererror/partial.go +++ b/consumer/consumererror/xconsumererror/partial.go @@ -24,10 +24,6 @@ func (pe partialError) Unwrap() error { return pe.inner } -func (pe partialError) Failed() int { - return pe.failed -} - // NewPartial creates a new partial error. This is used to report errors // where only a subset of the total items failed to be written, but it // is not possible to tell which particular items failed. An example of this @@ -49,12 +45,12 @@ func NewPartial(err error, failed int) error { }) } -// AsPartial checks if an error was wrapped with the NewPartial function, -// or if it contains one such error in its Unwrap() tree. The resulting -// error has a method Failed() that can be used to retrieve the count of -// failed items from the error. -func AsPartial(err error) (partialError, bool) { +// IsPartial checks if an error was wrapped with the NewPartial function, +// or if it contains one such error in its Unwrap() tree. The results are +// the count of failed items if the error is a partial error, and a boolean +// result of whether the error was a partial or not. +func IsPartial(err error) (int, bool) { var pe partialError ok := errors.As(err, &pe) - return pe, ok + return pe.failed, ok } diff --git a/consumer/consumererror/xconsumererror/partial_test.go b/consumer/consumererror/xconsumererror/partial_test.go index d96f749674f..6661a519720 100644 --- a/consumer/consumererror/xconsumererror/partial_test.go +++ b/consumer/consumererror/xconsumererror/partial_test.go @@ -18,11 +18,9 @@ func TestPartial(t *testing.T) { internalErr := errors.New("some points failed") err := xconsumererror.NewPartial(internalErr, 5) assert.True(t, consumererror.IsPermanent(err)) - partialErr, ok := xconsumererror.AsPartial(err) + failed, ok := xconsumererror.IsPartial(err) assert.True(t, ok) - assert.Equal(t, 5, partialErr.Failed()) - assert.Equal(t, internalErr, partialErr.Unwrap()) - assert.Equal(t, internalErr.Error(), partialErr.Error()) + assert.Equal(t, 5, failed) } func ExampleNewPartial() { @@ -35,24 +33,25 @@ func ExampleNewPartial() { // Output: "Permanent error: some points failed to be written" } -func ExampleAsPartial() { +func ExampleIsPartial() { // Produce a partial error. partialErr := xconsumererror.NewPartial(errors.New("some points failed to be written"), 10) - // The result of `xconsumererror.AsPartial` has a method `Failed` - // which can be used to retrieve the failed item count. - if err, ok := xconsumererror.AsPartial(partialErr); ok { - fmt.Println(err.Failed()) + // IsPartial will return the failed item count, and a boolean + // to indicate whether it is a partial error or not. + if count, ok := xconsumererror.IsPartial(partialErr); ok { + fmt.Println(count) } // Output: 10 } -func ExampleAsPartial_second() { +func ExampleIsPartial_second() { // Produce a partial error. partialErr := xconsumererror.NewPartial(errors.New("some points failed to be written"), 10) - // Partial errors wrap a Permanent error. + // Partial errors wrap a Permanent error, so it can simply be treated + // as one if the number of failed items isn't important. fmt.Println(consumererror.IsPermanent(partialErr)) // Output: true From fada42c16ef5254f2c34691431f7fe6cd6cf6394 Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 17:48:31 +0000 Subject: [PATCH 09/16] fix test example --- consumer/consumererror/xconsumererror/partial_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consumer/consumererror/xconsumererror/partial_test.go b/consumer/consumererror/xconsumererror/partial_test.go index 6661a519720..09203476710 100644 --- a/consumer/consumererror/xconsumererror/partial_test.go +++ b/consumer/consumererror/xconsumererror/partial_test.go @@ -30,7 +30,7 @@ func ExampleNewPartial() { err := xconsumererror.NewPartial(consumptionErr, failedItems) fmt.Println(err) - // Output: "Permanent error: some points failed to be written" + // Output: Permanent error: some points failed to be written } func ExampleIsPartial() { From aa68b1382fbcb9d103227aa848350ea8aab9605c Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 18:12:41 +0000 Subject: [PATCH 10/16] add xconsumererror to chloggen config --- .chloggen/config.yaml | 1 + .chloggen/partial_error.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.chloggen/config.yaml b/.chloggen/config.yaml index d5d46d80099..63912de7f4f 100644 --- a/.chloggen/config.yaml +++ b/.chloggen/config.yaml @@ -13,6 +13,7 @@ components: - connector/forward - connector/sample - consumer/xconsumer + - consumer/consumererror/xconsumererror - docs/rfcs - exporter/debug - exporter/nop diff --git a/.chloggen/partial_error.yaml b/.chloggen/partial_error.yaml index f0e0a9a272e..84c0f6dc1d9 100644 --- a/.chloggen/partial_error.yaml +++ b/.chloggen/partial_error.yaml @@ -4,7 +4,7 @@ change_type: enhancement # The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) -component: [consumer/consumererror/xconsumererror] +component: consumer/consumererror/xconsumererror # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). note: Add new Partial error, allowing consumers to express a permanent error with a failed item count. From 11944cfa653b6168dcf05a15645b4a1cd120bde9 Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 18:16:03 +0000 Subject: [PATCH 11/16] add unwrap case for coverage --- consumer/consumererror/xconsumererror/partial_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/consumer/consumererror/xconsumererror/partial_test.go b/consumer/consumererror/xconsumererror/partial_test.go index 09203476710..5bdb27753e5 100644 --- a/consumer/consumererror/xconsumererror/partial_test.go +++ b/consumer/consumererror/xconsumererror/partial_test.go @@ -17,7 +17,14 @@ import ( func TestPartial(t *testing.T) { internalErr := errors.New("some points failed") err := xconsumererror.NewPartial(internalErr, 5) + // The partial error must be wrapped and be able to be + // treated as a plain permanent error. assert.True(t, consumererror.IsPermanent(err)) + // The error should be unwrappable to verify the internal + // error if necessary. + assert.ErrorIs(t, err, internalErr) + // It must be possible to retrieve the failed items from + // the partial error. failed, ok := xconsumererror.IsPartial(err) assert.True(t, ok) assert.Equal(t, 5, failed) From b4eb6f794067d9e9f615376552510c868946c04a Mon Sep 17 00:00:00 2001 From: braydonk Date: Wed, 12 Nov 2025 19:07:49 +0000 Subject: [PATCH 12/16] linter doesn't like assert :( --- consumer/consumererror/xconsumererror/partial_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/consumer/consumererror/xconsumererror/partial_test.go b/consumer/consumererror/xconsumererror/partial_test.go index 5bdb27753e5..5abc6050423 100644 --- a/consumer/consumererror/xconsumererror/partial_test.go +++ b/consumer/consumererror/xconsumererror/partial_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" @@ -19,15 +19,15 @@ func TestPartial(t *testing.T) { err := xconsumererror.NewPartial(internalErr, 5) // The partial error must be wrapped and be able to be // treated as a plain permanent error. - assert.True(t, consumererror.IsPermanent(err)) + require.True(t, consumererror.IsPermanent(err)) // The error should be unwrappable to verify the internal // error if necessary. - assert.ErrorIs(t, err, internalErr) + require.ErrorIs(t, err, internalErr) // It must be possible to retrieve the failed items from // the partial error. failed, ok := xconsumererror.IsPartial(err) - assert.True(t, ok) - assert.Equal(t, 5, failed) + require.True(t, ok) + require.Equal(t, 5, failed) } func ExampleNewPartial() { From 933353ac24e6fedf5cc514e749311eda26282e8f Mon Sep 17 00:00:00 2001 From: braydonk Date: Mon, 17 Nov 2025 14:03:45 +0000 Subject: [PATCH 13/16] add metadata yaml to xconsumererror --- .github/CODEOWNERS | 12 ++++++++++++ .github/ISSUE_TEMPLATE/bug_report.yaml | 12 ++++++++++++ .github/ISSUE_TEMPLATE/feature_request.yaml | 12 ++++++++++++ .github/ISSUE_TEMPLATE/other.yaml | 12 ++++++++++++ consumer/consumererror/xconsumererror/metadata.yaml | 8 ++++++++ 5 files changed, 56 insertions(+) create mode 100644 consumer/consumererror/xconsumererror/metadata.yaml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 80aea4f3cd3..2b1bf2a1659 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -25,6 +25,17 @@ cmd/mdatagen/internal/samplefactoryreceiver/ @open-telemetry/collector-approvers cmd/mdatagen/internal/sampleprocessor/ @open-telemetry/collector-approvers cmd/mdatagen/internal/samplereceiver/ @open-telemetry/collector-approvers @dmitryax cmd/mdatagen/internal/samplescraper/ @open-telemetry/collector-approvers @dmitryax +config/configauth/ @open-telemetry/collector-approvers +config/configcompression/ @open-telemetry/collector-approvers +config/configgrpc/ @open-telemetry/collector-approvers +config/confighttp/ @open-telemetry/collector-approvers +config/configmiddleware/ @open-telemetry/collector-approvers +config/confignet/ @open-telemetry/collector-approvers +config/configopaque/ @open-telemetry/collector-approvers +config/configoptional/ @open-telemetry/collector-approvers +config/configretry/ @open-telemetry/collector-approvers +config/configtelemetry/ @open-telemetry/collector-approvers +config/configtls/ @open-telemetry/collector-approvers confmap/ @open-telemetry/collector-approvers @mx-psi @evan-bradley confmap/provider/envprovider/ @open-telemetry/collector-approvers confmap/provider/fileprovider/ @open-telemetry/collector-approvers @@ -33,6 +44,7 @@ confmap/provider/httpsprovider/ @open-telemetry/collector-approvers confmap/provider/yamlprovider/ @open-telemetry/collector-approvers connector/forwardconnector/ @open-telemetry/collector-approvers connector/xconnector/ @open-telemetry/collector-approvers @mx-psi @dmathieu +consumer/consumererror/xconsumererror/ @open-telemetry/collector-approvers consumer/xconsumer/ @open-telemetry/collector-approvers @mx-psi @dmathieu docs/rfcs/ @open-telemetry/collector-approvers @codeboten @bogdandrutu @dmitryax @mx-psi exporter/debugexporter/ @open-telemetry/collector-approvers @andrzej-stencel diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index bba1d2ed876..388b7657a6c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -25,6 +25,17 @@ body: - cmd/mdatagen/internal/sampleprocessor - cmd/mdatagen/internal/samplereceiver - cmd/mdatagen/internal/samplescraper + - config/configauth + - config/configcompression + - config/configgrpc + - config/confighttp + - config/configmiddleware + - config/confignet + - config/configopaque + - config/configoptional + - config/configretry + - config/configtelemetry + - config/configtls - confmap - confmap/provider/envprovider - confmap/provider/fileprovider @@ -33,6 +44,7 @@ body: - confmap/provider/yamlprovider - connector/forward - connector/x + - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 2b10eda576f..25d40b3d9d4 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -19,6 +19,17 @@ body: - cmd/mdatagen/internal/sampleprocessor - cmd/mdatagen/internal/samplereceiver - cmd/mdatagen/internal/samplescraper + - config/configauth + - config/configcompression + - config/configgrpc + - config/confighttp + - config/configmiddleware + - config/confignet + - config/configopaque + - config/configoptional + - config/configretry + - config/configtelemetry + - config/configtls - confmap - confmap/provider/envprovider - confmap/provider/fileprovider @@ -27,6 +38,7 @@ body: - confmap/provider/yamlprovider - connector/forward - connector/x + - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/.github/ISSUE_TEMPLATE/other.yaml b/.github/ISSUE_TEMPLATE/other.yaml index 8ec6a71b6e7..091adb93dd4 100644 --- a/.github/ISSUE_TEMPLATE/other.yaml +++ b/.github/ISSUE_TEMPLATE/other.yaml @@ -18,6 +18,17 @@ body: - cmd/mdatagen/internal/sampleprocessor - cmd/mdatagen/internal/samplereceiver - cmd/mdatagen/internal/samplescraper + - config/configauth + - config/configcompression + - config/configgrpc + - config/confighttp + - config/configmiddleware + - config/confignet + - config/configopaque + - config/configoptional + - config/configretry + - config/configtelemetry + - config/configtls - confmap - confmap/provider/envprovider - confmap/provider/fileprovider @@ -26,6 +37,7 @@ body: - confmap/provider/yamlprovider - connector/forward - connector/x + - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/consumer/consumererror/xconsumererror/metadata.yaml b/consumer/consumererror/xconsumererror/metadata.yaml new file mode 100644 index 00000000000..d0e21935dcd --- /dev/null +++ b/consumer/consumererror/xconsumererror/metadata.yaml @@ -0,0 +1,8 @@ +type: consumer/consumererror/xconsumererror +github_project: open-telemetry/opentelemetry-collector + +status: + disable_codecov_badge: true + class: consumer + stability: + development: [profiles] \ No newline at end of file From 8ff891445079ed2376a8fe8eec9053978d35a228 Mon Sep 17 00:00:00 2001 From: braydonk Date: Mon, 17 Nov 2025 15:45:28 +0000 Subject: [PATCH 14/16] also generate chloggen components --- .chloggen/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/config.yaml b/.chloggen/config.yaml index 63912de7f4f..f14ca30670b 100644 --- a/.chloggen/config.yaml +++ b/.chloggen/config.yaml @@ -12,8 +12,8 @@ components: - cmd/mdatagen - connector/forward - connector/sample + - consumer/consumer/consumererror/xconsumererror - consumer/xconsumer - - consumer/consumererror/xconsumererror - docs/rfcs - exporter/debug - exporter/nop From 4edad6bcacd8977ad69310f27cf16a9792f35ee8 Mon Sep 17 00:00:00 2001 From: braydonk Date: Mon, 17 Nov 2025 18:52:35 +0000 Subject: [PATCH 15/16] rename metadata component type --- .chloggen/config.yaml | 2 +- consumer/consumererror/xconsumererror/metadata.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.chloggen/config.yaml b/.chloggen/config.yaml index f14ca30670b..557841af6d9 100644 --- a/.chloggen/config.yaml +++ b/.chloggen/config.yaml @@ -12,7 +12,7 @@ components: - cmd/mdatagen - connector/forward - connector/sample - - consumer/consumer/consumererror/xconsumererror + - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/consumer/consumererror/xconsumererror/metadata.yaml b/consumer/consumererror/xconsumererror/metadata.yaml index d0e21935dcd..6c8c7aa1dca 100644 --- a/consumer/consumererror/xconsumererror/metadata.yaml +++ b/consumer/consumererror/xconsumererror/metadata.yaml @@ -1,4 +1,4 @@ -type: consumer/consumererror/xconsumererror +type: consumererror/xconsumererror github_project: open-telemetry/opentelemetry-collector status: From baf19df71714a3c28f9d317283dda9deed21843d Mon Sep 17 00:00:00 2001 From: braydonk Date: Tue, 18 Nov 2025 13:58:31 +0000 Subject: [PATCH 16/16] return to state before adding metadata yaml since I opened a separate PR --- .chloggen/config.yaml | 1 - .chloggen/consumererror_partial_success.yaml | 25 ------------------- .github/CODEOWNERS | 1 - .github/ISSUE_TEMPLATE/bug_report.yaml | 1 - .github/ISSUE_TEMPLATE/feature_request.yaml | 1 - .github/ISSUE_TEMPLATE/other.yaml | 1 - .../xconsumererror/metadata.yaml | 8 ------ 7 files changed, 38 deletions(-) delete mode 100644 .chloggen/consumererror_partial_success.yaml delete mode 100644 consumer/consumererror/xconsumererror/metadata.yaml diff --git a/.chloggen/config.yaml b/.chloggen/config.yaml index 557841af6d9..d5d46d80099 100644 --- a/.chloggen/config.yaml +++ b/.chloggen/config.yaml @@ -12,7 +12,6 @@ components: - cmd/mdatagen - connector/forward - connector/sample - - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/.chloggen/consumererror_partial_success.yaml b/.chloggen/consumererror_partial_success.yaml deleted file mode 100644 index 4d479b03eb8..00000000000 --- a/.chloggen/consumererror_partial_success.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Use this changelog template to create an entry for release notes. - -# 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. otlpreceiver) -component: consumererror - -# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: Add new partial error type to consumererror to allow consumers to report partial successes. - -# One or more tracking issues or pull requests related to the change -issues: [13423] - -# (Optional) One or more lines of additional information to render under the primary note. -# These lines will be padded with 2 spaces and then inserted directly into the document. -# Use pipe (|) for multiline entries. -subtext: - -# Optional: The change log or logs in which this entry should be included. -# e.g. '[user]' or '[user, api]' -# Include 'user' if the change is relevant to end users. -# Include 'api' if there is a change to a library API. -# Default: '[user]' -change_logs: [] diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2b1bf2a1659..838159785e6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -44,7 +44,6 @@ confmap/provider/httpsprovider/ @open-telemetry/collector-approvers confmap/provider/yamlprovider/ @open-telemetry/collector-approvers connector/forwardconnector/ @open-telemetry/collector-approvers connector/xconnector/ @open-telemetry/collector-approvers @mx-psi @dmathieu -consumer/consumererror/xconsumererror/ @open-telemetry/collector-approvers consumer/xconsumer/ @open-telemetry/collector-approvers @mx-psi @dmathieu docs/rfcs/ @open-telemetry/collector-approvers @codeboten @bogdandrutu @dmitryax @mx-psi exporter/debugexporter/ @open-telemetry/collector-approvers @andrzej-stencel diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 388b7657a6c..71b01562ee7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -44,7 +44,6 @@ body: - confmap/provider/yamlprovider - connector/forward - connector/x - - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 25d40b3d9d4..608f7a9d240 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -38,7 +38,6 @@ body: - confmap/provider/yamlprovider - connector/forward - connector/x - - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/.github/ISSUE_TEMPLATE/other.yaml b/.github/ISSUE_TEMPLATE/other.yaml index 091adb93dd4..b41db90ae2f 100644 --- a/.github/ISSUE_TEMPLATE/other.yaml +++ b/.github/ISSUE_TEMPLATE/other.yaml @@ -37,7 +37,6 @@ body: - confmap/provider/yamlprovider - connector/forward - connector/x - - consumer/consumererror/xconsumererror - consumer/xconsumer - docs/rfcs - exporter/debug diff --git a/consumer/consumererror/xconsumererror/metadata.yaml b/consumer/consumererror/xconsumererror/metadata.yaml deleted file mode 100644 index 6c8c7aa1dca..00000000000 --- a/consumer/consumererror/xconsumererror/metadata.yaml +++ /dev/null @@ -1,8 +0,0 @@ -type: consumererror/xconsumererror -github_project: open-telemetry/opentelemetry-collector - -status: - disable_codecov_badge: true - class: consumer - stability: - development: [profiles] \ No newline at end of file