LCOV - code coverage report
Current view: top level - source/common/tracing - http_tracer_impl.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 174 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 12 0.0 %

          Line data    Source code
       1             : #include "source/common/tracing/http_tracer_impl.h"
       2             : 
       3             : #include <string>
       4             : 
       5             : #include "envoy/config/core/v3/base.pb.h"
       6             : #include "envoy/network/address.h"
       7             : #include "envoy/tracing/tracer.h"
       8             : #include "envoy/type/metadata/v3/metadata.pb.h"
       9             : #include "envoy/type/tracing/v3/custom_tag.pb.h"
      10             : 
      11             : #include "source/common/common/assert.h"
      12             : #include "source/common/common/fmt.h"
      13             : #include "source/common/common/macros.h"
      14             : #include "source/common/common/utility.h"
      15             : #include "source/common/grpc/common.h"
      16             : #include "source/common/http/codes.h"
      17             : #include "source/common/http/header_map_impl.h"
      18             : #include "source/common/http/header_utility.h"
      19             : #include "source/common/http/headers.h"
      20             : #include "source/common/http/utility.h"
      21             : #include "source/common/protobuf/utility.h"
      22             : #include "source/common/stream_info/utility.h"
      23             : 
      24             : #include "absl/strings/str_cat.h"
      25             : 
      26             : namespace Envoy {
      27             : namespace Tracing {
      28             : 
      29             : // TODO(perf): Avoid string creations/copies in this entire file.
      30           0 : static std::string buildResponseCode(const StreamInfo::StreamInfo& info) {
      31           0 :   return info.responseCode() ? std::to_string(info.responseCode().value()) : "0";
      32           0 : }
      33             : 
      34             : static absl::string_view valueOrDefault(const Http::HeaderEntry* header,
      35           0 :                                         const char* default_value) {
      36           0 :   return header ? header->value().getStringView() : default_value;
      37           0 : }
      38             : 
      39           0 : static void addTagIfNotNull(Span& span, const std::string& tag, const Http::HeaderEntry* entry) {
      40           0 :   if (entry != nullptr) {
      41           0 :     span.setTag(tag, entry->value().getStringView());
      42           0 :   }
      43           0 : }
      44             : 
      45           0 : static void addGrpcRequestTags(Span& span, const Http::RequestHeaderMap& headers) {
      46           0 :   addTagIfNotNull(span, Tracing::Tags::get().GrpcPath, headers.Path());
      47           0 :   addTagIfNotNull(span, Tracing::Tags::get().GrpcAuthority, headers.Host());
      48           0 :   addTagIfNotNull(span, Tracing::Tags::get().GrpcContentType, headers.ContentType());
      49           0 :   addTagIfNotNull(span, Tracing::Tags::get().GrpcTimeout, headers.GrpcTimeout());
      50           0 : }
      51             : 
      52           0 : template <class T> static void addGrpcResponseTags(Span& span, const T& headers) {
      53           0 :   addTagIfNotNull(span, Tracing::Tags::get().GrpcStatusCode, headers.GrpcStatus());
      54           0 :   addTagIfNotNull(span, Tracing::Tags::get().GrpcMessage, headers.GrpcMessage());
      55             :   // Set error tag when Grpc status code represents an upstream error. See
      56             :   // https://github.com/envoyproxy/envoy/issues/18877.
      57           0 :   absl::optional<Grpc::Status::GrpcStatus> grpc_status_code = Grpc::Common::getGrpcStatus(headers);
      58           0 :   if (grpc_status_code.has_value()) {
      59           0 :     const auto& status = grpc_status_code.value();
      60           0 :     if (status != Grpc::Status::WellKnownGrpcStatus::InvalidCode) {
      61           0 :       switch (status) {
      62             :       // Each case below is considered to be a client side error, therefore should not be
      63             :       // tagged as an upstream error. See https://grpc.github.io/grpc/core/md_doc_statuscodes.html
      64             :       // for more details about how each Grpc status code is defined and whether it is an
      65             :       // upstream error or a client error.
      66           0 :       case Grpc::Status::WellKnownGrpcStatus::Ok:
      67           0 :       case Grpc::Status::WellKnownGrpcStatus::Canceled:
      68           0 :       case Grpc::Status::WellKnownGrpcStatus::InvalidArgument:
      69           0 :       case Grpc::Status::WellKnownGrpcStatus::NotFound:
      70           0 :       case Grpc::Status::WellKnownGrpcStatus::AlreadyExists:
      71           0 :       case Grpc::Status::WellKnownGrpcStatus::PermissionDenied:
      72           0 :       case Grpc::Status::WellKnownGrpcStatus::FailedPrecondition:
      73           0 :       case Grpc::Status::WellKnownGrpcStatus::Aborted:
      74           0 :       case Grpc::Status::WellKnownGrpcStatus::OutOfRange:
      75           0 :       case Grpc::Status::WellKnownGrpcStatus::Unauthenticated:
      76           0 :         break;
      77           0 :       case Grpc::Status::WellKnownGrpcStatus::Unknown:
      78           0 :       case Grpc::Status::WellKnownGrpcStatus::DeadlineExceeded:
      79           0 :       case Grpc::Status::WellKnownGrpcStatus::Unimplemented:
      80           0 :       case Grpc::Status::WellKnownGrpcStatus::ResourceExhausted:
      81           0 :       case Grpc::Status::WellKnownGrpcStatus::Internal:
      82           0 :       case Grpc::Status::WellKnownGrpcStatus::Unavailable:
      83           0 :       case Grpc::Status::WellKnownGrpcStatus::DataLoss:
      84           0 :         span.setTag(Tracing::Tags::get().Error, Tracing::Tags::get().True);
      85           0 :         break;
      86           0 :       }
      87           0 :     }
      88           0 :   }
      89           0 : }
      90             : 
      91           0 : static void annotateVerbose(Span& span, const StreamInfo::StreamInfo& stream_info) {
      92           0 :   const auto start_time = stream_info.startTime();
      93           0 :   StreamInfo::TimingUtility timing(stream_info);
      94           0 :   if (timing.lastDownstreamRxByteReceived()) {
      95           0 :     span.log(start_time + std::chrono::duration_cast<SystemTime::duration>(
      96           0 :                               *timing.lastDownstreamRxByteReceived()),
      97           0 :              Tracing::Logs::get().LastDownstreamRxByteReceived);
      98           0 :   }
      99           0 :   if (timing.firstUpstreamTxByteSent()) {
     100           0 :     span.log(start_time + std::chrono::duration_cast<SystemTime::duration>(
     101           0 :                               *timing.firstUpstreamTxByteSent()),
     102           0 :              Tracing::Logs::get().FirstUpstreamTxByteSent);
     103           0 :   }
     104           0 :   if (timing.lastUpstreamTxByteSent()) {
     105           0 :     span.log(start_time +
     106           0 :                  std::chrono::duration_cast<SystemTime::duration>(*timing.lastUpstreamTxByteSent()),
     107           0 :              Tracing::Logs::get().LastUpstreamTxByteSent);
     108           0 :   }
     109           0 :   if (timing.firstUpstreamRxByteReceived()) {
     110           0 :     span.log(start_time + std::chrono::duration_cast<SystemTime::duration>(
     111           0 :                               *timing.firstUpstreamRxByteReceived()),
     112           0 :              Tracing::Logs::get().FirstUpstreamRxByteReceived);
     113           0 :   }
     114           0 :   if (timing.lastUpstreamRxByteReceived()) {
     115           0 :     span.log(start_time + std::chrono::duration_cast<SystemTime::duration>(
     116           0 :                               *timing.lastUpstreamRxByteReceived()),
     117           0 :              Tracing::Logs::get().LastUpstreamRxByteReceived);
     118           0 :   }
     119           0 :   if (timing.firstDownstreamTxByteSent()) {
     120           0 :     span.log(start_time + std::chrono::duration_cast<SystemTime::duration>(
     121           0 :                               *timing.firstDownstreamTxByteSent()),
     122           0 :              Tracing::Logs::get().FirstDownstreamTxByteSent);
     123           0 :   }
     124           0 :   if (timing.lastDownstreamTxByteSent()) {
     125           0 :     span.log(start_time + std::chrono::duration_cast<SystemTime::duration>(
     126           0 :                               *timing.lastDownstreamTxByteSent()),
     127           0 :              Tracing::Logs::get().LastDownstreamTxByteSent);
     128           0 :   }
     129           0 : }
     130             : 
     131             : void HttpTracerUtility::finalizeDownstreamSpan(Span& span,
     132             :                                                const Http::RequestHeaderMap* request_headers,
     133             :                                                const Http::ResponseHeaderMap* response_headers,
     134             :                                                const Http::ResponseTrailerMap* response_trailers,
     135             :                                                const StreamInfo::StreamInfo& stream_info,
     136           0 :                                                const Config& tracing_config) {
     137             :   // Pre response data.
     138           0 :   if (request_headers) {
     139           0 :     if (request_headers->RequestId()) {
     140           0 :       span.setTag(Tracing::Tags::get().GuidXRequestId, request_headers->getRequestIdValue());
     141           0 :     }
     142           0 :     span.setTag(
     143           0 :         Tracing::Tags::get().HttpUrl,
     144           0 :         Http::Utility::buildOriginalUri(*request_headers, tracing_config.maxPathTagLength()));
     145           0 :     span.setTag(Tracing::Tags::get().HttpMethod, request_headers->getMethodValue());
     146           0 :     span.setTag(Tracing::Tags::get().DownstreamCluster,
     147           0 :                 valueOrDefault(request_headers->EnvoyDownstreamServiceCluster(), "-"));
     148           0 :     span.setTag(Tracing::Tags::get().UserAgent, valueOrDefault(request_headers->UserAgent(), "-"));
     149           0 :     span.setTag(
     150           0 :         Tracing::Tags::get().HttpProtocol,
     151           0 :         Formatter::SubstitutionFormatUtils::protocolToStringOrDefault(stream_info.protocol()));
     152             : 
     153           0 :     const auto& remote_address = stream_info.downstreamAddressProvider().directRemoteAddress();
     154             : 
     155           0 :     if (remote_address->type() == Network::Address::Type::Ip) {
     156           0 :       const auto remote_ip = remote_address->ip();
     157           0 :       span.setTag(Tracing::Tags::get().PeerAddress, remote_ip->addressAsString());
     158           0 :     } else {
     159           0 :       span.setTag(Tracing::Tags::get().PeerAddress, remote_address->logicalName());
     160           0 :     }
     161             : 
     162           0 :     if (request_headers->ClientTraceId()) {
     163           0 :       span.setTag(Tracing::Tags::get().GuidXClientTraceId,
     164           0 :                   request_headers->getClientTraceIdValue());
     165           0 :     }
     166             : 
     167           0 :     if (Grpc::Common::isGrpcRequestHeaders(*request_headers)) {
     168           0 :       addGrpcRequestTags(span, *request_headers);
     169           0 :     }
     170           0 :   }
     171             : 
     172           0 :   span.setTag(Tracing::Tags::get().RequestSize, std::to_string(stream_info.bytesReceived()));
     173           0 :   span.setTag(Tracing::Tags::get().ResponseSize, std::to_string(stream_info.bytesSent()));
     174             : 
     175           0 :   setCommonTags(span, stream_info, tracing_config);
     176           0 :   onUpstreamResponseHeaders(span, response_headers);
     177           0 :   onUpstreamResponseTrailers(span, response_trailers);
     178             : 
     179           0 :   span.finishSpan();
     180           0 : }
     181             : 
     182             : void HttpTracerUtility::finalizeUpstreamSpan(Span& span, const StreamInfo::StreamInfo& stream_info,
     183           0 :                                              const Config& tracing_config) {
     184           0 :   span.setTag(
     185           0 :       Tracing::Tags::get().HttpProtocol,
     186           0 :       Formatter::SubstitutionFormatUtils::protocolToStringOrDefault(stream_info.protocol()));
     187             : 
     188           0 :   if (stream_info.upstreamInfo() && stream_info.upstreamInfo()->upstreamHost()) {
     189           0 :     auto upstream_address = stream_info.upstreamInfo()->upstreamHost()->address();
     190             :     // TODO(wbpcode): separated `upstream_address` may be meaningful to the downstream span.
     191             :     // But for the upstream span, `peer.address` should be used.
     192           0 :     span.setTag(Tracing::Tags::get().UpstreamAddress, upstream_address->asStringView());
     193             :     // TODO(wbpcode): may be set this tag in the setCommonTags.
     194           0 :     span.setTag(Tracing::Tags::get().PeerAddress, upstream_address->asStringView());
     195           0 :   }
     196             : 
     197           0 :   setCommonTags(span, stream_info, tracing_config);
     198             : 
     199           0 :   span.finishSpan();
     200           0 : }
     201             : 
     202             : void HttpTracerUtility::onUpstreamResponseHeaders(Span& span,
     203           0 :                                                   const Http::ResponseHeaderMap* response_headers) {
     204           0 :   if (response_headers && response_headers->GrpcStatus() != nullptr) {
     205           0 :     addGrpcResponseTags(span, *response_headers);
     206           0 :   }
     207           0 : }
     208             : 
     209             : void HttpTracerUtility::onUpstreamResponseTrailers(
     210           0 :     Span& span, const Http::ResponseTrailerMap* response_trailers) {
     211           0 :   if (response_trailers && response_trailers->GrpcStatus() != nullptr) {
     212           0 :     addGrpcResponseTags(span, *response_trailers);
     213           0 :   }
     214           0 : }
     215             : 
     216             : void HttpTracerUtility::setCommonTags(Span& span, const StreamInfo::StreamInfo& stream_info,
     217           0 :                                       const Config& tracing_config) {
     218             : 
     219           0 :   span.setTag(Tracing::Tags::get().Component, Tracing::Tags::get().Proxy);
     220             : 
     221             :   // Cluster info.
     222           0 :   if (auto cluster_info = stream_info.upstreamClusterInfo();
     223           0 :       cluster_info.has_value() && cluster_info.value() != nullptr) {
     224           0 :     span.setTag(Tracing::Tags::get().UpstreamCluster, cluster_info.value()->name());
     225           0 :     span.setTag(Tracing::Tags::get().UpstreamClusterName,
     226           0 :                 cluster_info.value()->observabilityName());
     227           0 :   }
     228             : 
     229             :   // Post response data.
     230           0 :   span.setTag(Tracing::Tags::get().HttpStatusCode, buildResponseCode(stream_info));
     231           0 :   span.setTag(Tracing::Tags::get().ResponseFlags,
     232           0 :               StreamInfo::ResponseFlagUtils::toShortString(stream_info));
     233             : 
     234           0 :   if (tracing_config.verbose()) {
     235           0 :     annotateVerbose(span, stream_info);
     236           0 :   }
     237             : 
     238           0 :   if (!stream_info.responseCode() || Http::CodeUtility::is5xx(stream_info.responseCode().value())) {
     239           0 :     span.setTag(Tracing::Tags::get().Error, Tracing::Tags::get().True);
     240           0 :   }
     241             : 
     242           0 :   ReadOnlyHttpTraceContext trace_context{stream_info.getRequestHeaders() != nullptr
     243           0 :                                              ? *stream_info.getRequestHeaders()
     244           0 :                                              : *Http::StaticEmptyHeaders::get().request_headers};
     245           0 :   CustomTagContext ctx{trace_context, stream_info};
     246           0 :   if (const CustomTagMap* custom_tag_map = tracing_config.customTags(); custom_tag_map) {
     247           0 :     for (const auto& it : *custom_tag_map) {
     248           0 :       it.second->applySpan(span, ctx);
     249           0 :     }
     250           0 :   }
     251           0 : }
     252             : 
     253             : } // namespace Tracing
     254             : } // namespace Envoy

Generated by: LCOV version 1.15