File: grpcstatus.go

package info (click to toggle)
golang-github-grpc-ecosystem-go-grpc-prometheus 1.2.0%2Bgit20191002.6af20e3-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 264 kB
  • sloc: makefile: 34; sh: 11
file content (57 lines) | stat: -rw-r--r-- 1,674 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package grpcstatus

import (
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type gRPCStatus interface {
	GRPCStatus() *status.Status
}

func unwrapPkgErrorsGRPCStatus(err error) (*status.Status, bool) {
	type causer interface {
		Cause() error
	}

	// Unwrapping the github.com/pkg/errors causer interface, using `Cause` directly could miss some error implementing
	// the `GRPCStatus` function so we have to check it on our selves.
	unwrappedCauser := err
	for unwrappedCauser != nil {
		if s, ok := unwrappedCauser.(gRPCStatus); ok {
			return s.GRPCStatus(), true
		}
		cause, ok := unwrappedCauser.(causer)
		if !ok {
			break
		}
		unwrappedCauser = cause.Cause()
	}
	return nil, false
}

// Since error can be wrapped and the `FromError` function only checks for `GRPCStatus` function
// and as a fallback uses the `Unknown` gRPC status we need to unwrap the error if possible to get the original status.
// pkg/errors and Go native errors packages have two different approaches so we try to unwrap both types.
// Eventually should be implemented in the go-grpc status function `FromError`. See https://github.com/grpc/grpc-go/issues/2934
func FromError(err error) (s *status.Status, ok bool) {
	s, ok = status.FromError(err)
	if ok {
		return s, true
	}

	// Try to unwrap `github.com/pkg/errors` wrapped error
	s, ok = unwrapPkgErrorsGRPCStatus(err)
	if ok {
		return s, true
	}

	// Try to unwrap native wrapped errors using `fmt.Errorf` and `%w`
	s, ok = unwrapNativeWrappedGRPCStatus(err)
	if ok {
		return s, true
	}

	// We failed to unwrap any GRPSStatus so return default `Unknown`
	return status.New(codes.Unknown, err.Error()), false
}