trace_common.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Copyright 2017, OpenCensus Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ocgrpc
  15. import (
  16. "strings"
  17. "google.golang.org/grpc/codes"
  18. "context"
  19. "go.opencensus.io/trace"
  20. "go.opencensus.io/trace/propagation"
  21. "google.golang.org/grpc/metadata"
  22. "google.golang.org/grpc/stats"
  23. "google.golang.org/grpc/status"
  24. )
  25. const traceContextKey = "grpc-trace-bin"
  26. // TagRPC creates a new trace span for the client side of the RPC.
  27. //
  28. // It returns ctx with the new trace span added and a serialization of the
  29. // SpanContext added to the outgoing gRPC metadata.
  30. func (c *ClientHandler) traceTagRPC(ctx context.Context, rti *stats.RPCTagInfo) context.Context {
  31. name := strings.TrimPrefix(rti.FullMethodName, "/")
  32. name = strings.Replace(name, "/", ".", -1)
  33. ctx, span := trace.StartSpan(ctx, name,
  34. trace.WithSampler(c.StartOptions.Sampler),
  35. trace.WithSpanKind(trace.SpanKindClient)) // span is ended by traceHandleRPC
  36. traceContextBinary := propagation.Binary(span.SpanContext())
  37. return metadata.AppendToOutgoingContext(ctx, traceContextKey, string(traceContextBinary))
  38. }
  39. // TagRPC creates a new trace span for the server side of the RPC.
  40. //
  41. // It checks the incoming gRPC metadata in ctx for a SpanContext, and if
  42. // it finds one, uses that SpanContext as the parent context of the new span.
  43. //
  44. // It returns ctx, with the new trace span added.
  45. func (s *ServerHandler) traceTagRPC(ctx context.Context, rti *stats.RPCTagInfo) context.Context {
  46. md, _ := metadata.FromIncomingContext(ctx)
  47. name := strings.TrimPrefix(rti.FullMethodName, "/")
  48. name = strings.Replace(name, "/", ".", -1)
  49. traceContext := md[traceContextKey]
  50. var (
  51. parent trace.SpanContext
  52. haveParent bool
  53. )
  54. if len(traceContext) > 0 {
  55. // Metadata with keys ending in -bin are actually binary. They are base64
  56. // encoded before being put on the wire, see:
  57. // https://github.com/grpc/grpc-go/blob/08d6261/Documentation/grpc-metadata.md#storing-binary-data-in-metadata
  58. traceContextBinary := []byte(traceContext[0])
  59. parent, haveParent = propagation.FromBinary(traceContextBinary)
  60. if haveParent && !s.IsPublicEndpoint {
  61. ctx, _ := trace.StartSpanWithRemoteParent(ctx, name, parent,
  62. trace.WithSpanKind(trace.SpanKindServer),
  63. trace.WithSampler(s.StartOptions.Sampler),
  64. )
  65. return ctx
  66. }
  67. }
  68. ctx, span := trace.StartSpan(ctx, name,
  69. trace.WithSpanKind(trace.SpanKindServer),
  70. trace.WithSampler(s.StartOptions.Sampler))
  71. if haveParent {
  72. span.AddLink(trace.Link{TraceID: parent.TraceID, SpanID: parent.SpanID, Type: trace.LinkTypeChild})
  73. }
  74. return ctx
  75. }
  76. func traceHandleRPC(ctx context.Context, rs stats.RPCStats) {
  77. span := trace.FromContext(ctx)
  78. // TODO: compressed and uncompressed sizes are not populated in every message.
  79. switch rs := rs.(type) {
  80. case *stats.Begin:
  81. span.AddAttributes(
  82. trace.BoolAttribute("Client", rs.Client),
  83. trace.BoolAttribute("FailFast", rs.FailFast))
  84. case *stats.InPayload:
  85. span.AddMessageReceiveEvent(0 /* TODO: messageID */, int64(rs.Length), int64(rs.WireLength))
  86. case *stats.OutPayload:
  87. span.AddMessageSendEvent(0, int64(rs.Length), int64(rs.WireLength))
  88. case *stats.End:
  89. if rs.Error != nil {
  90. s, ok := status.FromError(rs.Error)
  91. if ok {
  92. span.SetStatus(trace.Status{Code: int32(s.Code()), Message: s.Message()})
  93. } else {
  94. span.SetStatus(trace.Status{Code: int32(codes.Internal), Message: rs.Error.Error()})
  95. }
  96. }
  97. span.End()
  98. }
  99. }