diff --git a/client/history/metricClient.go b/client/history/metricClient.go index bcfa663f230..1d3faa931ca 100644 --- a/client/history/metricClient.go +++ b/client/history/metricClient.go @@ -617,7 +617,7 @@ func (c *metricClient) finishMetricsRecording( err error, ) { if err != nil { - c.throttledLogger.Error("history client encountered error", tag.Error(err)) + c.throttledLogger.Error("history client encountered error", tag.Error(err), tag.ErrorType(err)) scope.Tagged(metrics.ServiceErrorTypeTag(err)).IncCounter(metrics.ClientFailures) } stopwatch.Stop() diff --git a/client/matching/metricClient.go b/client/matching/metricClient.go index 7b3964570d6..8c114b1bb81 100644 --- a/client/matching/metricClient.go +++ b/client/matching/metricClient.go @@ -256,7 +256,7 @@ func (c *metricClient) finishMetricsRecording( err error, ) { if err != nil { - c.throttledLogger.Error("matching client encountered error", tag.Error(err)) + c.throttledLogger.Error("matching client encountered error", tag.Error(err), tag.ErrorType(err)) scope.Tagged(metrics.ServiceErrorTypeTag(err)).IncCounter(metrics.ClientFailures) } stopwatch.Stop() diff --git a/common/log/tag/tags.go b/common/log/tag/tags.go index 597cbacc5a9..dcb9a591945 100644 --- a/common/log/tag/tags.go +++ b/common/log/tag/tags.go @@ -26,6 +26,7 @@ package tag import ( "fmt" + "strings" "time" enumspb "go.temporal.io/api/enums/v1" @@ -42,7 +43,12 @@ import ( // 2. System : these tags are internal information which usually cannot be understood by our customers, // LoggingCallAtKey is reserved tag -const LoggingCallAtKey = "logging-call-at" +const ( + LoggingCallAtKey = "logging-call-at" + + getType = "%T" + errorPrefix = "*" +) /////////////////// Common tags defined here /////////////////// @@ -56,6 +62,11 @@ func Error(err error) ZapTag { return NewErrorTag(err) } +// ErrorType returns tag for ErrorType +func ErrorType(err error) ZapTag { + return NewStringTag("service-error-type", strings.TrimPrefix(fmt.Sprintf(getType, err), errorPrefix)) +} + // IsRetryable returns tag for IsRetryable func IsRetryable(isRetryable bool) ZapTag { return NewBoolTag("is-retryable", isRetryable) @@ -71,7 +82,7 @@ func Timestamp(timestamp time.Time) ZapTag { return NewTimeTag("timestamp", timestamp) } -// Timestamp returns tag for Timestamp +// TimestampPtr returns tag for TimestampPtr func TimestampPtr(t *time.Time) ZapTag { return NewTimeTag("timestamp", timestamp.TimeValue(t)) } diff --git a/common/log/tag/tags_test.go b/common/log/tag/tags_test.go new file mode 100644 index 00000000000..dc11f60e563 --- /dev/null +++ b/common/log/tag/tags_test.go @@ -0,0 +1,49 @@ +// The MIT License +// +// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. +// +// Copyright (c) 2020 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package tag + +import ( + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "go.temporal.io/api/serviceerror" +) + +func TestErrorType(t *testing.T) { + testData := []struct { + err error + expectedResult string + }{ + {serviceerror.NewInvalidArgument(""), "serviceerror.InvalidArgument"}, + {errors.New("test"), "errors.errorString"}, + {fmt.Errorf("test"), "errors.errorString"}, + } + + for id, data := range testData { + assert.Equal(t, data.expectedResult, ErrorType(data.err).Value().(string), "Unexpected error type in index", id) + } +} diff --git a/common/metrics/defs.go b/common/metrics/defs.go index b59921d8994..6e6f85b1c22 100644 --- a/common/metrics/defs.go +++ b/common/metrics/defs.go @@ -1717,23 +1717,6 @@ var ScopeDefs = map[ServiceIdx]map[int]scopeDefinition{ }, } -// Common error type -const ( - ErrorTypeUnknown = "unknown_error_type" - ErrorTypeInvalidArgument = "invalid_argument_error_type" - ErrorTypeInternal = "internal_error_type" - ErrorTypeUnavailable = "unavailable_error_type" - ErrorTypeCanceled = "canceled_error_type" - ErrorTypeTimedOut = "timed_out_error_type" - ErrorTypeNotFound = "not_found_error_type" - ErrorTypeNamespaceNotActive = "namespace_not_active_error_type" - ErrorTypeQueryFailed = "query_failed_error_type" - ErrorTypeClientVersionNotSupported = "client_version_not_supported_error_type" - ErrorTypeServerVersionNotSupported = "server_version_not_supported_error_type" - ErrorTypePermissionDenied = "permission_denied_error_type" - ErrorTypeResourceExhausted = "resource_exhausted_error_type" -) - // Common Metrics enum const ( ServiceRequests = iota diff --git a/common/metrics/defs_test.go b/common/metrics/defs_test.go index d0c296e3800..1c3fbe6b2dc 100644 --- a/common/metrics/defs_test.go +++ b/common/metrics/defs_test.go @@ -29,9 +29,6 @@ import ( "regexp" "testing" - "go.temporal.io/api/enums/v1" - "go.temporal.io/api/serviceerror" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -112,32 +109,3 @@ func TestMetricDefs(t *testing.T) { } } } - -func TestGetServiceErrorType(t *testing.T) { - testData := []struct { - err error - expectedResult string - }{ - {serviceerror.NewInvalidArgument(""), ErrorTypeInvalidArgument}, - {serviceerror.NewCanceled(""), ErrorTypeCanceled}, - {serviceerror.NewDataLoss(""), ErrorTypeInternal}, - {serviceerror.NewInternal(""), ErrorTypeInternal}, - {serviceerror.NewCancellationAlreadyRequested(""), ErrorTypeInvalidArgument}, - {serviceerror.NewNamespaceAlreadyExists(""), ErrorTypeInvalidArgument}, - {serviceerror.NewWorkflowExecutionAlreadyStarted("", "", ""), ErrorTypeInvalidArgument}, - {serviceerror.NewClientVersionNotSupported("", "", ""), ErrorTypeClientVersionNotSupported}, - {serviceerror.NewServerVersionNotSupported("", ""), ErrorTypeServerVersionNotSupported}, - {serviceerror.NewDeadlineExceeded(""), ErrorTypeTimedOut}, - {serviceerror.NewNamespaceNotActive("", "", ""), ErrorTypeNamespaceNotActive}, - {serviceerror.NewNotFound(""), ErrorTypeNotFound}, - {serviceerror.NewPermissionDenied("", ""), ErrorTypePermissionDenied}, - {serviceerror.NewQueryFailed(""), ErrorTypeQueryFailed}, - {serviceerror.NewResourceExhausted(enums.RESOURCE_EXHAUSTED_CAUSE_UNSPECIFIED, ""), ErrorTypeResourceExhausted}, - {serviceerror.NewUnavailable(""), ErrorTypeUnavailable}, - {serviceerror.NewUnimplemented(""), ErrorTypeUnknown}, - } - - for id, data := range testData { - assert.Equal(t, data.expectedResult, getErrorType(data.err), "Unexpected error type in index", id) - } -} diff --git a/common/metrics/tags.go b/common/metrics/tags.go index 827aecdf4c9..63eecba06f1 100644 --- a/common/metrics/tags.go +++ b/common/metrics/tags.go @@ -25,9 +25,9 @@ package metrics import ( + "fmt" "strconv" - - "go.temporal.io/api/serviceerror" + "strings" enumspb "go.temporal.io/api/enums/v1" ) @@ -51,6 +51,9 @@ const ( unknownValue = "_unknown_" totalMetricSuffix = "_total" tagExcludedValue = "_tag_excluded_" + + getType = "%T" + errorPrefix = "*" ) // Tag is an interface to define metrics tags @@ -202,7 +205,7 @@ func VisibilityTypeTag(value string) Tag { } func ServiceErrorTypeTag(err error) Tag { - return &tagImpl{key: ErrorTypeTagName, value: getErrorType(err)} + return &tagImpl{key: ErrorTypeTagName, value: strings.TrimPrefix(fmt.Sprintf(getType, err), errorPrefix)} } var standardVisibilityTypeTag = VisibilityTypeTag(standardVisibilityTagValue) @@ -224,37 +227,3 @@ func HttpStatusTag(value int) Tag { func ResourceExhaustedCauseTag(cause enumspb.ResourceExhaustedCause) Tag { return &tagImpl{key: resourceExhaustedTag, value: cause.String()} } - -func getErrorType(err error) string { - switch err.(type) { - case *serviceerror.InvalidArgument, - *serviceerror.CancellationAlreadyRequested, - *serviceerror.NamespaceAlreadyExists, - *serviceerror.WorkflowExecutionAlreadyStarted: - return ErrorTypeInvalidArgument - case *serviceerror.Internal, *serviceerror.DataLoss: - return ErrorTypeInternal - case *serviceerror.Unavailable: - return ErrorTypeUnavailable - case *serviceerror.NotFound: - return ErrorTypeNotFound - case *serviceerror.Canceled: - return ErrorTypeCanceled - case *serviceerror.DeadlineExceeded: - return ErrorTypeTimedOut - case *serviceerror.NamespaceNotActive: - return ErrorTypeNamespaceNotActive - case *serviceerror.QueryFailed: - return ErrorTypeQueryFailed - case *serviceerror.ClientVersionNotSupported: - return ErrorTypeClientVersionNotSupported - case *serviceerror.ServerVersionNotSupported: - return ErrorTypeServerVersionNotSupported - case *serviceerror.PermissionDenied: - return ErrorTypePermissionDenied - case *serviceerror.ResourceExhausted: - return ErrorTypeResourceExhausted - default: - return ErrorTypeUnknown - } -}