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