Files
Alex ShtinandGitHub 8e8f1b0f7c Remove license header from every file (#7689)
## What changed?
<!-- Describe what has changed in this PR -->
Remove license header from every file. Because it is really hard to
follow in this PR here is the summary:
1. License header is removed from all `.go` and `.proto` files
:fireworks::fireworks:🎆.
2. `LICENSE` file in the root directory has only Temporal and Uber
copyrights.
3. 5 other `LICENSE` files added to the packages which have copyrights
different from Temporal and Uber: Datadog, Xargin, "Mat Ryer, Tyler
Bunnell and contributors".
4. `license_file` flag is removed from all code generation tools.
5. `copyright_file` flag is removed from `go:generate mockgen`
directive.
6. All copyright related targets are removed from `Makefile`.
7. Updated Temporal copyright year to 2025 everywhere.

## Why?
<!-- Tell your future self why have you made these changes -->
I double checked with legal department that it is not needed to have
license header in every file. One file per repo is enough. I put all
copyrights to the root `LICENSE` file and removed header from all other
files. Also updated tools and `Makefile`.
2025-05-01 18:50:21 -07:00

198 lines
5.8 KiB
Go

package telemetry
import (
"context"
"time"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
otelnoop "go.opentelemetry.io/otel/trace/noop"
"go.temporal.io/server/common/log"
"go.temporal.io/server/common/log/tag"
"go.temporal.io/server/common/rpc/interceptor/logtags"
"go.temporal.io/server/common/tasktoken"
"google.golang.org/grpc/stats"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
type methodNameKey struct{}
type (
// ServerStatsHandler gives a named type to the stats.Handler implementation provided by otelgrpc.
ServerStatsHandler stats.Handler
// ClientStatsHandler gives a named type to the grpc.UnaryClientInterceptor implementation provided by otelgrpc.
ClientStatsHandler stats.Handler
customServerStatsHandler struct {
isDebug bool
wrapped stats.Handler
tags *logtags.WorkflowTags
}
)
// NewServerStatsHandler creates a new gRPC stats handler that tracks each request with an encapsulating span
// using the provided TracerProvider and TextMapPropagator.
//
// NOTE: If the TracerProvider is `noop.TracerProvider`, it returns `nil`.
func NewServerStatsHandler(
tp trace.TracerProvider,
tmp propagation.TextMapPropagator,
logger log.Logger,
) ServerStatsHandler {
if !isEnabled(tp) {
return nil
}
return newCustomServerStatsHandler(
otelgrpc.NewServerHandler(
otelgrpc.WithPropagators(tmp),
otelgrpc.WithTracerProvider(tp),
),
logger)
}
// NewClientStatsHandler creates a new gRPC stats handler that tracks each request with an encapsulating span
// using the provided TracerProvider and TextMapPropagator.
//
// NOTE: If the TracerProvider is `noop.TracerProvider`, it returns `nil`.
func NewClientStatsHandler(
tp trace.TracerProvider,
tmp propagation.TextMapPropagator,
) ClientStatsHandler {
if !isEnabled(tp) {
return nil
}
return otelgrpc.NewClientHandler(
otelgrpc.WithPropagators(tmp),
otelgrpc.WithTracerProvider(tp),
)
}
func newCustomServerStatsHandler(
handler stats.Handler,
logger log.Logger,
) *customServerStatsHandler {
return &customServerStatsHandler{
wrapped: handler,
isDebug: DebugMode(),
tags: logtags.NewWorkflowTags(tasktoken.NewSerializer(), logger),
}
}
func (c *customServerStatsHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
return c.wrapped.TagRPC(
context.WithValue(ctx, methodNameKey{}, info.FullMethodName),
info)
}
func (c *customServerStatsHandler) HandleRPC(ctx context.Context, stat stats.RPCStats) {
// handling `End` before wrapped stats.Handler since it closes the span
switch s := stat.(type) {
case *stats.End:
// annotate with gRPC error payload
if c.isDebug {
span := trace.SpanFromContext(ctx)
//revive:disable-next-line:unchecked-type-assertion
statusErr, ok := status.FromError(s.Error)
if ok && statusErr != nil {
payload, _ := protojson.Marshal(statusErr.Proto())
span.SetAttributes(attribute.Key("rpc.response.error").String(string(payload)))
}
}
}
c.wrapped.HandleRPC(ctx, stat)
switch s := stat.(type) {
case *stats.InHeader:
if c.isDebug {
span := trace.SpanFromContext(ctx)
for key, values := range s.Header {
span.SetAttributes(attribute.StringSlice("rpc.request.headers."+key, values))
}
if deadline, ok := ctx.Deadline(); ok {
span.SetAttributes(attribute.String("rpc.request.deadline", deadline.Format(time.RFC3339Nano)))
span.SetAttributes(attribute.String("rpc.request.timeout", time.Until(deadline).String()))
}
}
case *stats.InPayload:
span := trace.SpanFromContext(ctx)
c.annotateTags(ctx, span, s.Payload)
// annotate with gRPC request payload
if c.isDebug {
//revive:disable-next-line:unchecked-type-assertion
reqMsg := s.Payload.(proto.Message)
payload, _ := protojson.Marshal(reqMsg)
msgType := string(proto.MessageName(reqMsg).Name())
span.SetAttributes(attribute.Key("rpc.request.payload").String(string(payload)))
span.SetAttributes(attribute.Key("rpc.request.type").String(msgType))
}
case *stats.OutHeader:
if c.isDebug {
span := trace.SpanFromContext(ctx)
for key, values := range s.Header {
span.SetAttributes(attribute.StringSlice("rpc.response.headers."+key, values))
}
}
case *stats.OutPayload:
span := trace.SpanFromContext(ctx)
c.annotateTags(ctx, span, s.Payload)
// annotate with gRPC response payload
if c.isDebug {
//revive:disable-next-line:unchecked-type-assertion
respMsg := s.Payload.(proto.Message)
payload, _ := protojson.Marshal(respMsg)
msgType := string(proto.MessageName(respMsg).Name())
span.SetAttributes(attribute.Key("rpc.response.payload").String(string(payload)))
span.SetAttributes(attribute.Key("rpc.response.type").String(msgType))
}
}
}
func (c *customServerStatsHandler) annotateTags(
ctx context.Context,
span trace.Span,
payload any,
) {
methodName, ok := ctx.Value(methodNameKey{}).(string)
if !ok {
methodName = "unknown"
}
// annotate span with workflow tags (same ones the Temporal SDKs use)
for _, logTag := range c.tags.Extract(payload, methodName) {
var k string
switch logTag.Key() {
case tag.WorkflowIDKey:
k = WorkflowIDKey
case tag.WorkflowRunIDKey:
k = WorkflowRunIDKey
default:
continue
}
span.SetAttributes(attribute.Key(k).String(logTag.Value().(string)))
}
}
func (c *customServerStatsHandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
return c.wrapped.TagConn(ctx, info)
}
func (c *customServerStatsHandler) HandleConn(ctx context.Context, stat stats.ConnStats) {
c.wrapped.HandleConn(ctx, stat)
}
func isEnabled(tp trace.TracerProvider) bool {
_, isNoop := tp.(otelnoop.TracerProvider)
return !isNoop
}