Files
tasks/common/rpc/interceptor/mask_internal_error.go
zeekay 5a601d081b rebrand: go.temporal.io/server -> github.com/hanzoai/tasks
Full module path rebrand from Temporal to Hanzo Tasks:
- go.mod module: github.com/hanzoai/tasks
- All internal Go imports updated (1906 files)
- cmd/server renamed to cmd/tasksd
- Binary name: tasksd (was temporal-server)
- Docker images: hanzoai/tasks (was temporalio/server)
- README rewritten with Hanzo Tasks branding
- LLM.md created with integration notes
- Makefile, goreleaser, CI workflows updated
- go.temporal.io/sdk and go.temporal.io/api imports preserved (separate repos)

Fork of Temporal.io (MIT license).
2026-03-19 10:36:40 -07:00

113 lines
3.3 KiB
Go

package interceptor
import (
"context"
"fmt"
"go.temporal.io/api/serviceerror"
"github.com/hanzoai/tasks/common"
"github.com/hanzoai/tasks/common/api"
"github.com/hanzoai/tasks/common/dynamicconfig"
"github.com/hanzoai/tasks/common/log"
"github.com/hanzoai/tasks/common/log/tag"
"github.com/hanzoai/tasks/common/namespace"
"github.com/hanzoai/tasks/common/rpc/interceptor/logtags"
"github.com/hanzoai/tasks/common/tasktoken"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var errorFrontendMasked = "something went wrong, please retry"
type MaskInternalErrorDetailsInterceptor struct {
maskInternalError dynamicconfig.BoolPropertyFnWithNamespaceFilter
namespaceRegistry namespace.Registry
logger log.Logger
workflowTags *logtags.WorkflowTags
}
func NewMaskInternalErrorDetailsInterceptor(
maskErrorSetting dynamicconfig.BoolPropertyFnWithNamespaceFilter,
namespaceRegistry namespace.Registry,
logger log.Logger,
) *MaskInternalErrorDetailsInterceptor {
return &MaskInternalErrorDetailsInterceptor{
maskInternalError: maskErrorSetting,
namespaceRegistry: namespaceRegistry,
workflowTags: logtags.NewWorkflowTags(tasktoken.NewSerializer(), logger),
logger: logger,
}
}
func (mi *MaskInternalErrorDetailsInterceptor) Intercept(
ctx context.Context,
req any,
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (any, error) {
resp, err := handler(ctx, req)
if err != nil && mi.shouldMaskErrors(req) {
err = mi.maskUnknownOrInternalErrors(req, info.FullMethod, err)
}
return resp, err
}
func (mi *MaskInternalErrorDetailsInterceptor) shouldMaskErrors(req any) bool {
ns := MustGetNamespaceName(mi.namespaceRegistry, req)
if ns.IsEmpty() {
return false
}
return mi.maskInternalError(ns.String())
}
func (mi *MaskInternalErrorDetailsInterceptor) maskUnknownOrInternalErrors(
req any, fullMethodName string, err error,
) error {
statusCode := serviceerror.ToStatus(err).Code()
if statusCode != codes.Unknown && statusCode != codes.Internal {
return err
}
// we need to log the original error with hash.
// This code is similar to the one in telemetry.go
// convert internal and unknown errors into neutral error with hash code of the original error
errorHash := common.ErrorHash(err)
// logging the error with hash code
mi.logError(req, fullMethodName, err, errorHash, statusCode)
// returning masked error
maskedErrorMessage := fmt.Sprintf("%s (%s)", errorFrontendMasked, errorHash)
return status.New(statusCode, maskedErrorMessage).Err()
}
func (mi *MaskInternalErrorDetailsInterceptor) logError(
req any,
fullMethod string,
err error,
errorHash string,
statusCode codes.Code,
) {
methodName := api.MethodName(fullMethod)
overridedMethodName := telemetryOverrideOperationTag(fullMethod, methodName)
nsName := MustGetNamespaceName(mi.namespaceRegistry, req)
var logTags []tag.Tag
if nsName == "" {
logTags = []tag.Tag{tag.Operation(overridedMethodName)}
} else {
logTags = []tag.Tag{tag.Operation(overridedMethodName), tag.WorkflowNamespace(nsName.String())}
}
logTags = append(logTags, tag.String("hash", errorHash))
logTags = append(logTags, tag.Stringer("grpc_code", statusCode))
logTags = append(logTags, mi.workflowTags.Extract(req, fullMethod)...)
mi.logger.Error("masked service failures", append(logTags, tag.Error(err))...)
}