Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2023-07-06 09:00:24 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2023-07-06 14:00:01 +0300
commit23c5e74210aac0f360bb24cb2677bf37c559322f (patch)
tree652cea4b1d192a59bb82b33f65019c5ed17884d8
parent4487da54883de88595e74d2a83d0afe605aca0a8 (diff)
structerr: Provide convenience function to extract metadata from errors
Callers that wish to extract error metadata from a generic error need to manually extract the `structerr.Error` first and then call `Metadata()` on it, which is a bit cumbersome. Furthermore, we're about to extend the logic to also allow for any other error types to carry metadata via an interface, which would require them to also be on the lookout for any such interface types. Refactor the code and pull out the logic to extract error metadata into a standalone `structerr.ExtractMetadata()` function. Given a generic error, it will return all error metadata that is contained in the error chain. This makes it easy to extend the logic going forward. Adjust existing callsites to use this new function.
-rw-r--r--internal/structerr/error.go41
-rw-r--r--internal/structerr/error_test.go1
-rw-r--r--internal/structerr/grpc_server.go9
-rw-r--r--internal/testhelper/testserver/structerr_interceptors.go9
4 files changed, 27 insertions, 33 deletions
diff --git a/internal/structerr/error.go b/internal/structerr/error.go
index 184b0da90..786522516 100644
--- a/internal/structerr/error.go
+++ b/internal/structerr/error.go
@@ -269,24 +269,9 @@ func (e Error) errorChain() []Error {
return result
}
-// Metadata returns the Error's metadata. The metadata will contain the combination of all added
-// metadata of this error as well as any wrapped Errors.
-//
-// When the same metada key exists multiple times in the error chain, then the value that is
-// highest up the callchain will be returned. This is done because in general, the higher up the
-// callchain one is the more context is available.
+// Metadata returns the Error's metadata. Please refer to `ExtractMetadata()` for the exact semantics of this function.
func (e Error) Metadata() map[string]any {
- result := map[string]any{}
-
- for _, err := range e.errorChain() {
- for _, m := range err.metadata {
- if _, exists := result[m.Key]; !exists {
- result[m.Key] = m.Value
- }
- }
- }
-
- return result
+ return ExtractMetadata(e)
}
// MetadataItems returns a copy of all metadata items added to this error. This function has the
@@ -356,3 +341,25 @@ func (e Error) WithGRPCCode(code codes.Code) Error {
e.code = code
return e
}
+
+// ExtractMetadata extracts metadata from the given error if any of the errors in its chain contain any. The metadata
+// will contain the combination of all added metadata of this error as well as any wrapped Errors.
+//
+// When the same metada key exists multiple times in the error chain, then the value that is
+// highest up the callchain will be returned. This is done because in general, the higher up the
+// callchain one is the more context is available.
+func ExtractMetadata(err error) map[string]any {
+ metadata := map[string]any{}
+
+ for ; err != nil; err = errors.Unwrap(err) {
+ if structErr, ok := err.(Error); ok {
+ for _, m := range structErr.metadata {
+ if _, exists := metadata[m.Key]; !exists {
+ metadata[m.Key] = m.Value
+ }
+ }
+ }
+ }
+
+ return metadata
+}
diff --git a/internal/structerr/error_test.go b/internal/structerr/error_test.go
index c1a65b689..dc8852977 100644
--- a/internal/structerr/error_test.go
+++ b/internal/structerr/error_test.go
@@ -338,6 +338,7 @@ func TestError_Metadata(t *testing.T) {
expectedItemsByKey[item.Key] = item.Value
}
require.Equal(t, expectedItemsByKey, err.Metadata())
+ require.Equal(t, expectedItemsByKey, ExtractMetadata(err))
}
t.Run("without metadata", func(t *testing.T) {
diff --git a/internal/structerr/grpc_server.go b/internal/structerr/grpc_server.go
index 367f149e7..d2f565849 100644
--- a/internal/structerr/grpc_server.go
+++ b/internal/structerr/grpc_server.go
@@ -2,7 +2,6 @@ package structerr
import (
"context"
- "errors"
"github.com/sirupsen/logrus"
)
@@ -10,13 +9,7 @@ import (
// FieldsProducer extracts metadata from err if it contains a `structerr.Error` and exposes it as
// logged fields. This function is supposed to be used with `log.MessageProducer()`.
func FieldsProducer(_ context.Context, err error) logrus.Fields {
- var structErr Error
- if errors.As(err, &structErr) {
- metadata := structErr.Metadata()
- if len(metadata) == 0 {
- return nil
- }
-
+ if metadata := ExtractMetadata(err); len(metadata) > 0 {
return logrus.Fields{
"error_metadata": metadata,
}
diff --git a/internal/testhelper/testserver/structerr_interceptors.go b/internal/testhelper/testserver/structerr_interceptors.go
index 26b53d63c..6c4ffb4b1 100644
--- a/internal/testhelper/testserver/structerr_interceptors.go
+++ b/internal/testhelper/testserver/structerr_interceptors.go
@@ -2,7 +2,6 @@ package testserver
import (
"context"
- "errors"
"sort"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
@@ -26,13 +25,7 @@ func StructErrStreamInterceptor(srv interface{}, stream grpc.ServerStream, info
}
func interceptedError(err error) error {
- var structErr structerr.Error
- if errors.As(err, &structErr) {
- metadata := structErr.Metadata()
- if len(metadata) == 0 {
- return err
- }
-
+ if metadata := structerr.ExtractMetadata(err); len(metadata) > 0 {
keys := make([]string, 0, len(metadata))
for key := range metadata {
keys = append(keys, key)