同事给我的关于tracer 的分享:
envoy code trace
source/common/http/conn_manager_impl.cc: : 828
void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapPtr&& headers,
bool end_stream) {
....
// Check if tracing is enabled at all.
if (connection_manager_.config_.tracingConfig()) {
traceRequest();
}
}
source/common/http/conn_manager_impl.cc: 1064
active_span_ = connection_manager_.tracer().startSpan(
*this, *request_headers_, filter_manager_.streamInfo(), tracing_decision);
void ConnectionManagerImpl::ActiveStream::traceRequest() {
const Tracing::Decision tracing_decision =
Tracing::HttpTracerUtility::shouldTraceRequest(filter_manager_.streamInfo());
ConnectionManagerImpl::chargeTracingStats(tracing_decision.reason,
connection_manager_.config_.tracingStats());
active_span_ = connection_manager_.tracer().startSpan(
*this, *request_headers_, filter_manager_.streamInfo(), tracing_decision);
if (!active_span_) {
return;
}
// TODO: Need to investigate the following code based on the cached route, as may
// be broken in the case a filter changes the route.
// If a decorator has been defined, apply it to the active span.
if (hasCachedRoute() && cached_route_.value()->decorator()) {
const Router::Decorator* decorator = cached_route_.value()->decorator();
decorator->apply(*active_span_);
state_.decorated_propagate_ = decorator->propagate();
// Cache decorated operation.
if (!decorator->getOperation().empty()) {
decorated_operation_ = &decorator->getOperation();
}
}
if (connection_manager_.config_.tracingConfig()->operation_name_ ==
Tracing::OperationName::Egress) {
// For egress (outbound) requests, pass the decorator's operation name (if defined and
// propagation enabled) as a request header to enable the receiving service to use it in its
// server span.
if (decorated_operation_ && state_.decorated_propagate_) {
request_headers_->setEnvoyDecoratorOperation(*decorated_operation_);
}
} else {
const HeaderEntry* req_operation_override = request_headers_->EnvoyDecoratorOperation();
// For ingress (inbound) requests, if a decorator operation name has been provided, it
// should be used to override the active span's operation.
if (req_operation_override) {
if (!req_operation_override->value().empty()) {
active_span_->setOperation(req_operation_override->value().getStringView());
// Clear the decorated operation so won't be used in the response header, as
// it has been overridden by the inbound decorator operation request header.
decorated_operation_ = nullptr;
}
// Remove header so not propagated to service
request_headers_->removeEnvoyDecoratorOperation();
}
}
}
source/common/tracing/http_tracer_impl.h: 97
class HttpTracerImpl : public HttpTracer {
public:
HttpTracerImpl(DriverSharedPtr driver, const LocalInfo::LocalInfo& local_info);
// Tracing::HttpTracer
SpanPtr startSpan(const Config& config, Http::RequestHeaderMap& request_headers,
const StreamInfo::StreamInfo& stream_info,
const Tracing::Decision tracing_decision) override;
DriverSharedPtr driverForTest() const { return driver_; }
private:
DriverSharedPtr driver_;
const LocalInfo::LocalInfo& local_info_;
};
source/common/tracing/http_tracer_impl.cc: 259
构造中的DriverSharedPtr driver : 应该就是zipkin (default)
HttpTracerImpl::HttpTracerImpl(DriverSharedPtr driver, const LocalInfo::LocalInfo& local_info)
: driver_(std::move(driver)), local_info_(local_info) {}
SpanPtr HttpTracerImpl::startSpan(const Config& config, Http::RequestHeaderMap& request_headers,
const StreamInfo::StreamInfo& stream_info,
const Tracing::Decision tracing_decision) {
std::string span_name = HttpTracerUtility::toString(config.operationName());
if (config.operationName() == OperationName::Egress) {
span_name.append(" ");
span_name.append(std::string(request_headers.getHostValue()));
}
SpanPtr active_span = driver_->startSpan(config, request_headers, span_name,
stream_info.startTime(), tracing_decision);
// Set tags related to the local environment
if (active_span) {
active_span->setTag(Tracing::Tags::get().NodeId, local_info_.nodeName());
active_span->setTag(Tracing::Tags::get().Zone, local_info_.zoneName());
}
return active_span;
}
source/extensions/tracers/zipkin/tracer.cc : 57
两个接口:
一: 没有父节点
SpanPtr Tracer::startSpan(const Tracing::Config& config, const std::string& span_name,
SystemTime timestamp)
二: 有父节点
SpanPtr Tracer::startSpan(const Tracing::Config& config, const std::string& span_name,
SystemTime timestamp, const SpanContext& previous_context) {
SpanPtr span_ptr = std::make_unique<Span>(time_source_);
Annotation annotation;
uint64_t timestamp_micro;
timestamp_micro =
std::chrono::duration_cast<std::chrono::microseconds>(timestamp.time_since_epoch()).count();
span_ptr->setName(span_name);
// Set the span's kind (client or server)
if (config.operationName() == Tracing::OperationName::Egress) {
annotation.setValue(CLIENT_SEND);
} else {
annotation.setValue(SERVER_RECV);
}
// Set the span's id and parent id
if (config.operationName() == Tracing::OperationName::Egress || !shared_span_context_) {
// We need to create a new span that is a child of the previous span; no shared context
// Create a new span id
uint64_t random_number = random_generator_.random();
span_ptr->setId(random_number);
// Set the parent id to the id of the previous span
span_ptr->setParentId(previous_context.id());
// Set the timestamp globally for the span
span_ptr->setTimestamp(timestamp_micro);
} else if (config.operationName() == Tracing::OperationName::Ingress) {
// We need to create a new span that will share context with the previous span
// Initialize the shared context for the new span
span_ptr->setId(previous_context.id());
if (previous_context.parentId()) {
span_ptr->setParentId(previous_context.parentId());
}
} else {
return span_ptr; // return an empty span
}
// Build the endpoint
Endpoint ep(service_name_, address_);
// Add the newly-created annotation to the span
annotation.setEndpoint(std::move(ep));
annotation.setTimestamp(timestamp_micro);
span_ptr->addAnnotation(std::move(annotation));
// Keep the same trace id
span_ptr->setTraceId(previous_context.traceId());
if (previous_context.is128BitTraceId()) {
span_ptr->setTraceIdHigh(previous_context.traceIdHigh());
}
// Keep the same sampled flag
span_ptr->setSampled(previous_context.sampled());
int64_t start_time_micro = std::chrono::duration_cast<std::chrono::microseconds>(
time_source_.monotonicTime().time_since_epoch())
.count();
span_ptr->setStartTime(start_time_micro);
span_ptr->setTracer(this);
return span_ptr;
}
zipkin driver 构造函数信息
source/extensions/tracers/zipkin/zipkin_tracer_impl.cc : 72
Driver::Driver(const envoy::config::trace::v3::ZipkinConfig& zipkin_config,
Upstream::ClusterManager& cluster_manager, Stats::Scope& scope,
ThreadLocal::SlotAllocator& tls, Runtime::Loader& runtime,
const LocalInfo::LocalInfo& local_info, Random::RandomGenerator& random_generator,
TimeSource& time_source)
: cm_(cluster_manager), tracer_stats_{ZIPKIN_TRACER_STATS(
POOL_COUNTER_PREFIX(scope, "tracing.zipkin."))},
tls_(tls.allocateSlot()), runtime_(runtime), local_info_(local_info),
time_source_(time_source)
上报span信息 :
source/extensions/tracers/zipkin/zipkin_tracer_impl.cc: 165
ReporterImpl::reportSpan -> ReporterImpl::flushSpans
void ReporterImpl::reportSpan(Span&& span) {
span_buffer_->addSpan(std::move(span));
const uint64_t min_flush_spans =
driver_.runtime().snapshot().getInteger("tracing.zipkin.min_flush_spans", 5U);
if (span_buffer_->pendingSpans() == min_flush_spans) {
flushSpans();
}
}
source/extensions/tracers/zipkin/zipkin_tracer_impl.cc : 182
序列化并发送请求给 zipkin server
void ReporterImpl::flushSpans() {
if (span_buffer_->pendingSpans()) {
driver_.tracerStats().spans_sent_.add(span_buffer_->pendingSpans());
const std::string request_body = span_buffer_->serialize();
Http::RequestMessagePtr message = std::make_unique<Http::RequestMessageImpl>();
message->headers().setReferenceMethod(Http::Headers::get().MethodValues.Post);
message->headers().setPath(collector_.endpoint_);
message->headers().setHost(driver_.hostname());
message->headers().setReferenceContentType(
collector_.version_ == envoy::config::trace::v3::ZipkinConfig::HTTP_PROTO
? Http::Headers::get().ContentTypeValues.Protobuf
: Http::Headers::get().ContentTypeValues.Json);
message->body().add(request_body);
const uint64_t timeout =
driver_.runtime().snapshot().getInteger("tracing.zipkin.request_timeout", 5000U);
if (collector_cluster_.threadLocalCluster().has_value()) {
Http::AsyncClient::Request* request =
collector_cluster_.threadLocalCluster()->get().httpAsyncClient().send(
std::move(message), *this,
Http::AsyncClient::RequestOptions().setTimeout(std::chrono::milliseconds(timeout)));
if (request) {
active_requests_.add(*request);
}
} else {
ENVOY_LOG(debug, "collector cluster '{}' does not exist", driver_.cluster());
driver_.tracerStats().reports_skipped_no_cluster_.inc();
}
span_buffer_->clear();
}
}
source/extensions/tracers/zipkin/span_buffer.cc: 62 spanbuffer 序列化
zipkin_span.toJson()
std::string JsonV1Serializer::serialize(const std::vector<Span>& zipkin_spans) {
const std::string serialized_elements =
absl::StrJoin(zipkin_spans, ",", [](std::string* element, const Span& zipkin_span) {
absl::StrAppend(element, zipkin_span.toJson());
});
return absl::StrCat("[", serialized_elements, "]");
}
结束计时:
source/extensions/tracers/zipkin/zipkin_tracer_impl.cc: 24
void ZipkinSpan::finishSpan() { span_.finish(); }
Span::finish()内部:setDuration
if (monotonic_start_time_) {
const int64_t monotonic_stop_time = std::chrono::duration_cast<std::chrono::microseconds>(
time_source_.monotonicTime().time_since_epoch())
.count();
setDuration(monotonic_stop_time - monotonic_start_time_);
}
source/extensions/tracers/zipkin/zipkin_core_types.h : 415
/**
* Sets the span's duration attribute.
*/
void setDuration(const int64_t val) { duration_ = val; }
source/extensions/tracers/zipkin/zipkin_core_types.cc: 190
void Span::finish() {
// Assumption: Span will have only one annotation when this method is called.
SpanContext context(*this);
if (annotations_[0].value() == SERVER_RECV) {
// Need to set the SS annotation
Annotation ss;
ss.setEndpoint(annotations_[0].endpoint());
ss.setTimestamp(std::chrono::duration_cast<std::chrono::microseconds>(
time_source_.systemTime().time_since_epoch())
.count());
ss.setValue(SERVER_SEND);
annotations_.push_back(std::move(ss));
} else if (annotations_[0].value() == CLIENT_SEND) {
// Need to set the CR annotation.
Annotation cr;
const uint64_t stop_timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
time_source_.systemTime().time_since_epoch())
.count();
cr.setEndpoint(annotations_[0].endpoint());
cr.setTimestamp(stop_timestamp);
cr.setValue(CLIENT_RECV);
annotations_.push_back(std::move(cr));
}
if (monotonic_start_time_) {
const int64_t monotonic_stop_time = std::chrono::duration_cast<std::chrono::microseconds>(
time_source_.monotonicTime().time_since_epoch())
.count();
setDuration(monotonic_stop_time - monotonic_start_time_);
}
if (auto t = tracer()) {
t->reportSpan(std::move(*this));
}
}
source/common/http/filter_manager.cc: 1290
FilterManager::encodeTrailers -> FilterManager::maybeEndEncode -> filter_manager_callbacks_.endStream()
->connection_manager_.doEndStream(*this); ->
void FilterManager::encodeTrailers(ActiveStreamEncoderFilter* filter,
ResponseTrailerMap& trailers) {
filter_manager_callbacks_.resetIdleTimer();
// Filter iteration may start at the current filter.
std::list<ActiveStreamEncoderFilterPtr>::iterator entry =
commonEncodePrefix(filter, true, FilterIterationStartState::CanStartFromCurrent);
for (; entry != encoder_filters_.end(); entry++) {
(*entry)->maybeEvaluateMatchTreeWithNewData(
[&](auto& matching_data) { matching_data.onResponseTrailers(trailers); });
if ((*entry)->skipFilter()) {
continue;
}
// If the filter pointed by entry has stopped for all frame type, return now.
if ((*entry)->stoppedAll()) {
return;
}
ASSERT(!(state_.filter_call_state_ & FilterCallState::EncodeTrailers));
state_.filter_call_state_ |= FilterCallState::EncodeTrailers;
FilterTrailersStatus status = (*entry)->handle_->encodeTrailers(trailers);
(*entry)->handle_->encodeComplete();
(*entry)->end_stream_ = true;
state_.filter_call_state_ &= ~FilterCallState::EncodeTrailers;
ENVOY_STREAM_LOG(trace, "encode trailers called: filter={} status={}", *this,
static_cast<const void*>((*entry).get()), static_cast<uint64_t>(status));
if (!(*entry)->commonHandleAfterTrailersCallback(status)) {
return;
}
}
filter_manager_callbacks_.encodeTrailers(trailers);
maybeEndEncode(true);
}
source/common/http/filter_manager.cc: 1326:
void FilterManager::maybeEndEncode(bool end_stream) {
if (end_stream) {
filter_manager_callbacks_.endStream();
}
}
source/common/http/conn_manager_impl.h: 252:
正常关闭:
void ActiveStream :: endStream() override {
ASSERT(!state_.codec_saw_local_complete_);
state_.codec_saw_local_complete_ = true;
filter_manager_.streamInfo().onLastDownstreamTxByteSent();
request_response_timespan_->complete();
connection_manager_.doEndStream(*this);
}
source/common/http/conn_manager_impl.cc: 188
ConnectionManagerImpl::doEndStream(ActiveStream& stream) {
if (!reset_stream) {
doDeferredStreamDestroy(stream);
}
}
或者:
void ConnectionManagerImpl::ActiveStream::onResetStream(StreamResetReason reset_reason,
absl::string_view) {
connection_manager_.doDeferredStreamDestroy(*this);
}
void ConnectionManagerImpl::doDeferredStreamDestroy(ActiveStream& stream) {
stream.completeRequest();
}
ConnectionManagerImpl: http Network::Filter
source/common/http/conn_manager_impl.cc : 688
请求结束,关闭span
void ConnectionManagerImpl::ActiveStream::completeRequest() {
filter_manager_.streamInfo().onRequestComplete();
if (connection_manager_.remote_close_) {
filter_manager_.streamInfo().setResponseCodeDetails(
StreamInfo::ResponseCodeDetails::get().DownstreamRemoteDisconnect);
filter_manager_.streamInfo().setResponseFlag(
StreamInfo::ResponseFlag::DownstreamConnectionTermination);
}
// TODO(danzh) bring HTTP/3 to parity here.
if (connection_manager_.codec_->protocol() != Protocol::Http3) {
ASSERT(filter_manager_.streamInfo().responseCodeDetails().has_value());
}
connection_manager_.stats_.named_.downstream_rq_active_.dec();
if (filter_manager_.streamInfo().healthCheck()) {
connection_manager_.config_.tracingStats().health_check_.inc();
}
if (active_span_) {
Tracing::HttpTracerUtility::finalizeDownstreamSpan(
*active_span_, request_headers_.get(), response_headers_.get(), response_trailers_.get(),
filter_manager_.streamInfo(), *this);
}
if (state_.successful_upgrade_) {
connection_manager_.stats_.named_.downstream_cx_upgrades_active_.dec();
}
}
HttpTracerUtility::finalizeDownstreamSpan -> span.finishSpan()
source/common/tracing/http_tracer_impl.cc : 134
最后调用span.finishSpan();
void HttpTracerUtility::finalizeDownstreamSpan(Span& span,
const Http::RequestHeaderMap* request_headers,
const Http::ResponseHeaderMap* response_headers,
const Http::ResponseTrailerMap* response_trailers,
const StreamInfo::StreamInfo& stream_info,
const Config& tracing_config) {
// Pre response data.
if (request_headers) {
if (request_headers->RequestId()) {
span.setTag(Tracing::Tags::get().GuidXRequestId, request_headers->getRequestIdValue());
}
span.setTag(
Tracing::Tags::get().HttpUrl,
Http::Utility::buildOriginalUri(*request_headers, tracing_config.maxPathTagLength()));
span.setTag(Tracing::Tags::get().HttpMethod, request_headers->getMethodValue());
span.setTag(Tracing::Tags::get().DownstreamCluster,
valueOrDefault(request_headers->EnvoyDownstreamServiceCluster(), "-"));
span.setTag(Tracing::Tags::get().UserAgent, valueOrDefault(request_headers->UserAgent(), "-"));
span.setTag(
Tracing::Tags::get().HttpProtocol,
Formatter::SubstitutionFormatUtils::protocolToStringOrDefault(stream_info.protocol()));
const auto& remote_address = stream_info.downstreamAddressProvider().directRemoteAddress();
if (remote_address->type() == Network::Address::Type::Ip) {
const auto remote_ip = remote_address->ip();
span.setTag(Tracing::Tags::get().PeerAddress, remote_ip->addressAsString());
} else {
span.setTag(Tracing::Tags::get().PeerAddress, remote_address->logicalName());
}
if (request_headers->ClientTraceId()) {
span.setTag(Tracing::Tags::get().GuidXClientTraceId,
request_headers->getClientTraceIdValue());
}
if (Grpc::Common::isGrpcRequestHeaders(*request_headers)) {
addGrpcRequestTags(span, *request_headers);
}
}
CustomTagContext ctx{request_headers, stream_info};
const CustomTagMap* custom_tag_map = tracing_config.customTags();
if (custom_tag_map) {
for (const auto& it : *custom_tag_map) {
it.second->apply(span, ctx);
}
}
span.setTag(Tracing::Tags::get().RequestSize, std::to_string(stream_info.bytesReceived()));
span.setTag(Tracing::Tags::get().ResponseSize, std::to_string(stream_info.bytesSent()));
setCommonTags(span, response_headers, response_trailers, stream_info, tracing_config);
span.finishSpan();
}
HttpTracerUtility::finalizeUpstreamSpan() -> span.finishSpan();
source/common/tracing/http_tracer_impl.cc : 190
void HttpTracerUtility::finalizeUpstreamSpan(Span& span,
const Http::ResponseHeaderMap* response_headers,
const Http::ResponseTrailerMap* response_trailers,
const StreamInfo::StreamInfo& stream_info,
const Config& tracing_config) {
span.setTag(
Tracing::Tags::get().HttpProtocol,
Formatter::SubstitutionFormatUtils::protocolToStringOrDefault(stream_info.protocol()));
if (stream_info.upstreamHost()) {
span.setTag(Tracing::Tags::get().UpstreamAddress,
stream_info.upstreamHost()->address()->asStringView());
}
setCommonTags(span, response_headers, response_trailers, stream_info, tracing_config);
span.finishSpan();
}
source/common/http/conn_manager_impl.cc : 689
调用:Tracing::HttpTracerUtility::finalizeDownstreamSpan
void ConnectionManagerImpl::ActiveStream::completeRequest() {
filter_manager_.streamInfo().onRequestComplete();
if (connection_manager_.remote_close_) {
filter_manager_.streamInfo().setResponseCodeDetails(
StreamInfo::ResponseCodeDetails::get().DownstreamRemoteDisconnect);
filter_manager_.streamInfo().setResponseFlag(
StreamInfo::ResponseFlag::DownstreamConnectionTermination);
}
// TODO(danzh) bring HTTP/3 to parity here.
if (connection_manager_.codec_->protocol() != Protocol::Http3) {
ASSERT(filter_manager_.streamInfo().responseCodeDetails().has_value());
}
connection_manager_.stats_.named_.downstream_rq_active_.dec();
if (filter_manager_.streamInfo().healthCheck()) {
connection_manager_.config_.tracingStats().health_check_.inc();
}
if (active_span_) {
Tracing::HttpTracerUtility::finalizeDownstreamSpan(
*active_span_, request_headers_.get(), response_headers_.get(), response_trailers_.get(),
filter_manager_.streamInfo(), *this);
}
if (state_.successful_upgrade_) {
connection_manager_.stats_.named_.downstream_cx_upgrades_active_.dec();
}
}
source/common/http/async_client_impl.cc : 277
void AsyncRequestImpl::onComplete() {
callbacks_.onBeforeFinalizeUpstreamSpan(*child_span_, &response_->headers());
Tracing::HttpTracerUtility::finalizeUpstreamSpan(*child_span_, &response_->headers(),
response_->trailers(), streamInfo(),
Tracing::EgressConfig::get());
callbacks_.onSuccess(*this, std::move(response_));
}
source/common/http/async_client_impl.cc: 302
void AsyncRequestImpl::onReset() {
if (!cancelled_) {
// Set "error reason" tag related to reset. The tagging for "error true" is done inside the
// Tracing::HttpTracerUtility::finalizeUpstreamSpan.
child_span_->setTag(Tracing::Tags::get().ErrorReason, "Reset");
}
callbacks_.onBeforeFinalizeUpstreamSpan(*child_span_,
remoteClosed() ? &response_->headers() : nullptr);
// Finalize the span based on whether we received a response or not.
Tracing::HttpTracerUtility::finalizeUpstreamSpan(
*child_span_, remoteClosed() ? &response_->headers() : nullptr,
remoteClosed() ? response_->trailers() : nullptr, streamInfo(), Tracing::EgressConfig::get());
if (!cancelled_) {
// In this case we don't have a valid response so we do need to raise a failure.
callbacks_.onFailure(*this, AsyncClient::FailureReason::Reset);
}
}
source/common/router/upstream_request.cc : 67
UpstreamRequest::~UpstreamRequest() {
if (span_ != nullptr) {
Tracing::HttpTracerUtility::finalizeUpstreamSpan(*span_, upstream_headers_.get(),
upstream_trailers_.get(), stream_info_,
Tracing::EgressConfig::get());
}
if (per_try_timeout_ != nullptr) {
// Allows for testing.
per_try_timeout_->disableTimer();
}
if (max_stream_duration_timer_ != nullptr) {
max_stream_duration_timer_->disableTimer();
}
clearRequestEncoder();
source/common/router/upstream_request.cc: 44
UpstreamRequest 构造函数中根据配置是否创建子span
UpstreamRequest 的parent 应该是router filter
UpstreamRequest::UpstreamRequest(RouterFilterInterface& parent,
std::unique_ptr<GenericConnPool>&& conn_pool)
: parent_(parent), conn_pool_(std::move(conn_pool)), grpc_rq_success_deferred_(false),
stream_info_(parent_.callbacks()->dispatcher().timeSource(), nullptr),
start_time_(parent_.callbacks()->dispatcher().timeSource().monotonicTime()),
calling_encode_headers_(false), upstream_canary_(false), decode_complete_(false),
encode_complete_(false), encode_trailers_(false), retried_(false), awaiting_headers_(true),
outlier_detection_timeout_recorded_(false),
create_per_try_timeout_on_request_complete_(false), paused_for_connect_(false),
record_timeout_budget_(parent_.cluster()->timeoutBudgetStats().has_value()) {
if (parent_.config().start_child_span_) {
span_ = parent_.callbacks()->activeSpan().spawnChild(
parent_.callbacks()->tracingConfig(), "router " + parent.cluster()->name() + " egress",
parent.timeSource().systemTime());
if (parent.attemptCount() != 1) {
// This is a retry request, add this metadata to span.
span_->setTag(Tracing::Tags::get().RetryCount, std::to_string(parent.attemptCount() - 1));
}
}
stream_info_.healthCheck(parent_.callbacks()->streamInfo().healthCheck());
}
router 配置项是否开启start_child_span
api/envoy/extensions/filters/http/router/v3/router.proto :31
// Whether to start a child span for egress routed calls. This can be
// useful in scenarios where other filters (auth, ratelimit, etc.) make
// outbound calls and have child spans rooted at the same ingress
// parent. Defaults to false.
bool start_child_span = 2;