-
Notifications
You must be signed in to change notification settings - Fork 590
Fix: ETW span ownership lifetime #4070
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c6738ce
62446d8
005d87d
3bc2469
add9b1e
c283be1
1f76b52
7ac1f13
b8313f6
6c8b518
2f4a538
a45bad2
ca35c75
6658ccc
e55adfc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,6 @@ | |
|
|
||
| #pragma once | ||
|
|
||
| #include <algorithm> | ||
| #include <atomic> | ||
|
|
||
| #include <cstdint> | ||
|
|
@@ -17,6 +16,7 @@ | |
| #include <memory> | ||
| #include <mutex> | ||
| #include <sstream> | ||
| #include <unordered_map> | ||
| #include <vector> | ||
|
|
||
| #include "opentelemetry/nostd/shared_ptr.h" | ||
|
|
@@ -159,8 +159,7 @@ void UpdateStatus(T &t, Properties &props) | |
| /** | ||
| * @brief Tracer class that allows to send spans to ETW Provider. | ||
| */ | ||
| class Tracer : public opentelemetry::trace::Tracer, | ||
| public std::enable_shared_from_this<opentelemetry::trace::Tracer> | ||
| class Tracer : public opentelemetry::trace::Tracer | ||
| { | ||
| public: | ||
| /** | ||
|
|
@@ -169,6 +168,8 @@ class Tracer : public opentelemetry::trace::Tracer, | |
| bool IsClosed() const noexcept { return isClosed_.load(); } | ||
|
|
||
| private: | ||
| friend class TracerProvider; | ||
|
|
||
| /** | ||
| * @brief Parent provider of this Tracer | ||
| */ | ||
|
|
@@ -510,7 +511,7 @@ class Tracer : public opentelemetry::trace::Tracer, | |
| { | ||
| auto noopSpan = nostd::shared_ptr<opentelemetry::trace::Span>{ | ||
| new (std::nothrow) | ||
| opentelemetry::trace::NoopSpan(this->shared_from_this(), std::move(spanContext))}; | ||
| opentelemetry::trace::NoopSpan(std::shared_ptr<Tracer>{}, std::move(spanContext))}; | ||
| return noopSpan; | ||
| } | ||
|
|
||
|
|
@@ -1106,6 +1107,8 @@ class TracerProvider : public opentelemetry::trace::TracerProvider | |
| id_generator_{std::move(id_generator)}, | ||
| tail_sampler_{std::move(tail_sampler)} | ||
| { | ||
| (void)Tracer::etwProvider().is_registered(std::string{}); | ||
|
|
||
| // By default we ensure that all events carry their with TraceId and SpanId | ||
| GetOption(options, "enableTraceId", config_.enableTraceId, true); | ||
| GetOption(options, "enableSpanId", config_.enableSpanId, true); | ||
|
|
@@ -1143,6 +1146,8 @@ class TracerProvider : public opentelemetry::trace::TracerProvider | |
| tail_sampler_{ | ||
| std::unique_ptr<opentelemetry::exporter::etw::TailSampler>(new AlwaysOnTailSampler())} | ||
| { | ||
| (void)Tracer::etwProvider().is_registered(std::string{}); | ||
|
|
||
| config_.enableTraceId = true; | ||
| config_.enableSpanId = true; | ||
| config_.enableActivityId = false; | ||
|
|
@@ -1156,11 +1161,12 @@ class TracerProvider : public opentelemetry::trace::TracerProvider | |
| * @brief Obtain ETW Tracer. | ||
| * @param name ProviderId (instrumentation name) - Name or GUID | ||
| * | ||
| * @param args Additional arguments that controls `codec` of the provider. | ||
| * Possible values are: | ||
| * - "ETW" - 'classic' Trace Logging Dynamic manifest ETW events. | ||
| * - "MSGPACK" - MessagePack-encoded binary payload ETW events. | ||
| * - "XML" - XML events (reserved for future use) | ||
| * @param args Instrumentation version (unused by ETW). | ||
| * @param schema_url Schema URL (unused by ETW). | ||
| * | ||
| * Encoding is controlled via TelemetryProviderOptions["encoding"] passed | ||
| * to the TracerProvider constructor. Valid values: "ETW"/"TLD" (default), | ||
| * "MSGPACK", "XML". | ||
| * @return | ||
| */ | ||
| nostd::shared_ptr<opentelemetry::trace::Tracer> GetTracer( | ||
|
|
@@ -1177,10 +1183,54 @@ class TracerProvider : public opentelemetry::trace::TracerProvider | |
| UNREFERENCED_PARAMETER(args); | ||
| UNREFERENCED_PARAMETER(schema_url); | ||
| ETWProvider::EventFormat evtFmt = config_.encoding; | ||
| std::shared_ptr<opentelemetry::trace::Tracer> tracer{new (std::nothrow) | ||
| Tracer(*this, name, evtFmt)}; | ||
| return nostd::shared_ptr<opentelemetry::trace::Tracer>{tracer}; | ||
| TracerCacheKey key{name.data(), name.size(), evtFmt}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This cache key collapses distinct instrumentation scopes. Calls with the same Please compare the full instrumentation scope identity, preferably via |
||
|
|
||
| std::lock_guard<std::mutex> lock(tracers_mu_); | ||
| auto it = tracers_.find(key); | ||
| if (it != tracers_.end()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The found tracer could be closed, which should be recreated even with cache hit. Or there will be problems in the below code. auto t = tp.GetTracer("Foo");
t->Close(std::chrono::microseconds(0));
t = tp.GetTracer("Foo");
t->StartSpan("X");
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this issue still exists, and is blocker for the PR. |
||
| { | ||
| return nostd::shared_ptr<opentelemetry::trace::Tracer>{ | ||
| std::static_pointer_cast<opentelemetry::trace::Tracer>(it->second)}; | ||
| } | ||
|
|
||
| std::shared_ptr<Tracer> tracer{new (std::nothrow) Tracer(*this, name, evtFmt)}; | ||
| tracers_.emplace(std::move(key), tracer); | ||
| return nostd::shared_ptr<opentelemetry::trace::Tracer>{ | ||
| std::static_pointer_cast<opentelemetry::trace::Tracer>(tracer)}; | ||
| } | ||
|
|
||
| private: | ||
| struct TracerCacheKey | ||
| { | ||
| std::string name; | ||
| ETWProvider::EventFormat encoding; | ||
|
|
||
| TracerCacheKey(std::string value, ETWProvider::EventFormat format) | ||
| : name(std::move(value)), encoding(format) | ||
| {} | ||
|
|
||
| TracerCacheKey(const char *value, size_t size, ETWProvider::EventFormat format) | ||
| : name(value, size), encoding(format) | ||
| {} | ||
|
|
||
| bool operator==(const TracerCacheKey &other) const | ||
| { | ||
| return encoding == other.encoding && name == other.name; | ||
| } | ||
| }; | ||
|
|
||
| struct TracerCacheKeyHash | ||
| { | ||
| size_t operator()(const TracerCacheKey &key) const noexcept | ||
| { | ||
| size_t name_hash = std::hash<std::string>{}(key.name); | ||
| size_t fmt_hash = static_cast<size_t>(key.encoding); | ||
| return name_hash ^ (fmt_hash + 0x9e3779b97f4a7c15ULL + (name_hash << 6) + (name_hash >> 2)); | ||
| } | ||
| }; | ||
|
|
||
| std::mutex tracers_mu_; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding this mutex makes the public ETW Please preserve source compatibility by placing the mutex and cache behind movable, address-stable state. |
||
| std::unordered_map<TracerCacheKey, std::shared_ptr<Tracer>, TracerCacheKeyHash> tracers_; | ||
| }; | ||
|
|
||
| } // namespace etw | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still wondering if this is dead code.