• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2021 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #ifndef GRPC_SRC_CORE_TELEMETRY_CALL_TRACER_H
20 #define GRPC_SRC_CORE_TELEMETRY_CALL_TRACER_H
21 
22 #include <grpc/support/port_platform.h>
23 #include <grpc/support/time.h>
24 
25 #include <memory>
26 #include <string>
27 
28 #include "absl/status/status.h"
29 #include "absl/strings/string_view.h"
30 #include "absl/types/optional.h"
31 #include "src/core/lib/channel/channel_args.h"
32 #include "src/core/lib/iomgr/error.h"
33 #include "src/core/lib/promise/context.h"
34 #include "src/core/lib/resource_quota/arena.h"
35 #include "src/core/lib/slice/slice_buffer.h"
36 #include "src/core/lib/transport/call_final_info.h"
37 #include "src/core/lib/transport/metadata_batch.h"
38 #include "src/core/telemetry/tcp_tracer.h"
39 #include "src/core/util/ref_counted_string.h"
40 
41 namespace grpc_core {
42 
43 // The interface hierarchy is as follows -
44 //                 CallTracerAnnotationInterface
45 //                    |                  |
46 //        ClientCallTracer       CallTracerInterface
47 //                                |              |
48 //                      CallAttemptTracer    ServerCallTracer
49 
50 // The base class for all tracer implementations.
51 class CallTracerAnnotationInterface {
52  public:
53   // Enum associated with types of Annotations.
54   enum class AnnotationType {
55     kMetadataSizes,
56     kHttpTransport,
57     kDoNotUse_MustBeLast,
58   };
59 
60   // Base class to define a new type of annotation.
61   class Annotation {
62    public:
Annotation(AnnotationType type)63     explicit Annotation(AnnotationType type) : type_(type) {}
type()64     AnnotationType type() const { return type_; }
65     virtual std::string ToString() const = 0;
66     virtual ~Annotation() = default;
67 
68    private:
69     const AnnotationType type_;
70   };
71 
~CallTracerAnnotationInterface()72   virtual ~CallTracerAnnotationInterface() {}
73   // Records an annotation on the call attempt.
74   // TODO(yashykt): If needed, extend this to attach attributes with
75   // annotations.
76   virtual void RecordAnnotation(absl::string_view annotation) = 0;
77   virtual void RecordAnnotation(const Annotation& annotation) = 0;
78   virtual std::string TraceId() = 0;
79   virtual std::string SpanId() = 0;
80   virtual bool IsSampled() = 0;
81   // Indicates whether this tracer is a delegating tracer or not.
82   // `DelegatingClientCallTracer`, `DelegatingClientCallAttemptTracer` and
83   // `DelegatingServerCallTracer` are the only delegating call tracers.
IsDelegatingTracer()84   virtual bool IsDelegatingTracer() { return false; }
85 };
86 
87 // The base class for CallAttemptTracer and ServerCallTracer.
88 // TODO(yashykt): What's a better name for this?
89 class CallTracerInterface : public CallTracerAnnotationInterface {
90  public:
~CallTracerInterface()91   ~CallTracerInterface() override {}
92   // Please refer to `grpc_transport_stream_op_batch_payload` for details on
93   // arguments.
94   virtual void RecordSendInitialMetadata(
95       grpc_metadata_batch* send_initial_metadata) = 0;
96   virtual void RecordSendTrailingMetadata(
97       grpc_metadata_batch* send_trailing_metadata) = 0;
98   virtual void RecordSendMessage(const SliceBuffer& send_message) = 0;
99   // Only invoked if message was actually compressed.
100   virtual void RecordSendCompressedMessage(
101       const SliceBuffer& send_compressed_message) = 0;
102   // The `RecordReceivedInitialMetadata()` and `RecordReceivedMessage()`
103   // methods should only be invoked when the metadata/message was
104   // successfully received, i.e., without any error.
105   virtual void RecordReceivedInitialMetadata(
106       grpc_metadata_batch* recv_initial_metadata) = 0;
107   virtual void RecordReceivedMessage(const SliceBuffer& recv_message) = 0;
108   // Only invoked if message was actually decompressed.
109   virtual void RecordReceivedDecompressedMessage(
110       const SliceBuffer& recv_decompressed_message) = 0;
111   virtual void RecordCancel(grpc_error_handle cancel_error) = 0;
112 
113   struct TransportByteSize {
114     uint64_t framing_bytes = 0;
115     uint64_t data_bytes = 0;
116     uint64_t header_bytes = 0;
117 
118     TransportByteSize& operator+=(const TransportByteSize& other);
119   };
120   virtual void RecordIncomingBytes(
121       const TransportByteSize& transport_byte_size) = 0;
122   virtual void RecordOutgoingBytes(
123       const TransportByteSize& transport_byte_size) = 0;
124 
125   // Traces a new TCP transport attempt for this call attempt. Note the TCP
126   // transport may finish tracing and unref the TCP tracer before or after the
127   // call completion in gRPC core. No TCP tracing when null is returned.
128   virtual std::shared_ptr<TcpTracerInterface> StartNewTcpTrace() = 0;
129 };
130 
131 // Interface for a tracer that records activities on a call. Actual attempts for
132 // this call are traced with CallAttemptTracer after invoking RecordNewAttempt()
133 // on the ClientCallTracer object.
134 class ClientCallTracer : public CallTracerAnnotationInterface {
135  public:
136   // Interface for a tracer that records activities on a particular call
137   // attempt.
138   // (A single RPC can have multiple attempts due to retry/hedging policies or
139   // as transparent retry attempts.)
140   class CallAttemptTracer : public CallTracerInterface {
141    public:
142     // Note that not all of the optional label keys are exposed as public API.
143     enum class OptionalLabelKey : std::uint8_t {
144       kXdsServiceName,       // not public
145       kXdsServiceNamespace,  // not public
146       kLocality,
147       kSize  // should be last
148     };
149 
~CallAttemptTracer()150     ~CallAttemptTracer() override {}
151 
152     // TODO(yashykt): The following two methods `RecordReceivedTrailingMetadata`
153     // and `RecordEnd` should be moved into CallTracerInterface.
154     // If the call was cancelled before the recv_trailing_metadata op
155     // was started, recv_trailing_metadata and transport_stream_stats
156     // will be null.
157     virtual void RecordReceivedTrailingMetadata(
158         absl::Status status, grpc_metadata_batch* recv_trailing_metadata,
159         // TODO(roth): Remove this argument when the
160         // call_tracer_in_transport experiment finishes rolling out.
161         const grpc_transport_stream_stats* transport_stream_stats) = 0;
162     // Should be the last API call to the object. Once invoked, the tracer
163     // library is free to destroy the object.
164     virtual void RecordEnd(const gpr_timespec& latency) = 0;
165 
166     // Sets an optional label on the per-attempt metrics recorded at the end of
167     // the attempt.
168     virtual void SetOptionalLabel(OptionalLabelKey key,
169                                   RefCountedStringValue value) = 0;
170   };
171 
~ClientCallTracer()172   ~ClientCallTracer() override {}
173 
174   // Records a new attempt for the associated call. \a transparent denotes
175   // whether the attempt is being made as a transparent retry or as a
176   // non-transparent retry/hedging attempt. (There will be at least one attempt
177   // even if the call is not being retried.) The `ClientCallTracer` object
178   // retains ownership to the newly created `CallAttemptTracer` object.
179   // RecordEnd() serves as an indication that the call stack is done with all
180   // API calls, and the tracer library is free to destroy it after that.
181   virtual CallAttemptTracer* StartNewAttempt(bool is_transparent_retry) = 0;
182 };
183 
184 // Interface for a tracer that records activities on a server call.
185 class ServerCallTracer : public CallTracerInterface {
186  public:
~ServerCallTracer()187   ~ServerCallTracer() override {}
188   // TODO(yashykt): The following two methods `RecordReceivedTrailingMetadata`
189   // and `RecordEnd` should be moved into CallTracerInterface.
190   virtual void RecordReceivedTrailingMetadata(
191       grpc_metadata_batch* recv_trailing_metadata) = 0;
192   // Should be the last API call to the object. Once invoked, the tracer
193   // library is free to destroy the object.
194   virtual void RecordEnd(const grpc_call_final_info* final_info) = 0;
195 };
196 
197 // Interface for a factory that can create a ServerCallTracer object per
198 // server call.
199 class ServerCallTracerFactory {
200  public:
201   struct RawPointerChannelArgTag {};
202 
~ServerCallTracerFactory()203   virtual ~ServerCallTracerFactory() {}
204 
205   virtual ServerCallTracer* CreateNewServerCallTracer(
206       Arena* arena, const ChannelArgs& channel_args) = 0;
207 
208   // Returns true if a server is to be traced, false otherwise.
IsServerTraced(const ChannelArgs &)209   virtual bool IsServerTraced(const ChannelArgs& /*args*/) { return true; }
210 
211   // Use this method to get the server call tracer factory from channel args,
212   // instead of directly fetching it with `GetObject`.
213   static ServerCallTracerFactory* Get(const ChannelArgs& channel_args);
214 
215   // Registers a global ServerCallTracerFactory that will be used by default if
216   // no corresponding channel arg was found. It is only valid to call this
217   // before grpc_init(). It is the responsibility of the caller to maintain
218   // this for the lifetime of the process.
219   static void RegisterGlobal(ServerCallTracerFactory* factory);
220 
221   // Deletes any previous registered ServerCallTracerFactory.
222   static void TestOnlyReset();
223 
224   static absl::string_view ChannelArgName();
225 };
226 
227 // Convenience functions to add call tracers to a call context. Allows setting
228 // multiple call tracers to a single call. It is only valid to add client call
229 // tracers before the client_channel filter sees the send_initial_metadata op.
230 void AddClientCallTracerToContext(Arena* arena, ClientCallTracer* tracer);
231 
232 // TODO(yashykt): We want server call tracers to be registered through the
233 // ServerCallTracerFactory, which has yet to be made into a list.
234 void AddServerCallTracerToContext(Arena* arena, ServerCallTracer* tracer);
235 
236 template <>
237 struct ArenaContextType<CallTracerInterface> {
238   static void Destroy(CallTracerAnnotationInterface*) {}
239 };
240 
241 template <>
242 struct ArenaContextType<CallTracerAnnotationInterface> {
243   static void Destroy(CallTracerAnnotationInterface*) {}
244 };
245 
246 template <>
247 struct ContextSubclass<ClientCallTracer::CallAttemptTracer> {
248   using Base = CallTracerInterface;
249 };
250 
251 template <>
252 struct ContextSubclass<ServerCallTracer> {
253   using Base = CallTracerInterface;
254 };
255 
256 template <>
257 struct ContextSubclass<ClientCallTracer> {
258   using Base = CallTracerAnnotationInterface;
259 };
260 
261 }  // namespace grpc_core
262 
263 #endif  // GRPC_SRC_CORE_TELEMETRY_CALL_TRACER_H
264