1 // Copyright The OpenTelemetry Authors
2 // SPDX-License-Identifier: Apache-2.0
22 #include "opentelemetry/nostd/shared_ptr.h"
23 #include "opentelemetry/nostd/string_view.h"
24 #include "opentelemetry/nostd/unique_ptr.h"
25 #include "opentelemetry/nostd/variant.h"
27 #include "opentelemetry/common/key_value_iterable_view.h"
29 #include "opentelemetry/trace/span.h"
30 #include "opentelemetry/trace/span_context_kv_iterable_view.h"
31 #include "opentelemetry/trace/span_id.h"
32 #include "opentelemetry/trace/trace_id.h"
33 #include "opentelemetry/trace/tracer_provider.h"
35 #include "opentelemetry/sdk/trace/exporter.h"
37 #include "opentelemetry/exporters/etw/etw_config.h"
38 #include "opentelemetry/exporters/etw/etw_fields.h"
39 #include "opentelemetry/exporters/etw/etw_properties.h"
40 #include "opentelemetry/exporters/etw/etw_provider.h"
41 #include "opentelemetry/exporters/etw/utils.h"
43 OPENTELEMETRY_BEGIN_NAMESPACE
52 * @brief Template that allows to instantiate new Span object for header-only forward-declared
55 * @tparam SpanType Expected to be etw::Span
56 * @tparam TracerType expected to be etw::Tracer
57 * @param objPtr Pointer to parent
58 * @param name Span Name
59 * @param options Span Options
60 * @return Span instance
62 template <class SpanType
, class TracerType
>
63 SpanType
*new_span(TracerType
*objPtr
,
64 nostd::string_view name
,
65 const opentelemetry::trace::StartSpanOptions
&options
)
67 return new (std::nothrow
) SpanType
{*objPtr
, name
, options
};
71 * @brief Template that allows to convert etw::Span pointer to smart shared pointer to
72 * `opentelemetry::trace::Span`
73 * @tparam SpanType Expected to be etw::Span
74 * @param ptr Pointer to etw::Span
75 * @return Smart shared pointer to `opentelemetry::trace::Span`
77 template <class SpanType
>
78 nostd::shared_ptr
<opentelemetry::trace::Span
> to_span_ptr(SpanType
*ptr
)
80 return nostd::shared_ptr
<opentelemetry::trace::Span
>{ptr
};
86 * @brief Utility template for obtaining Span Name
88 * @param t instance of etw::Span
92 std::string
GetName(T
&t
)
94 auto sV
= t
.GetName();
95 return std::string(sV
.data(), sV
.length());
99 * @brief Utility template to obtain Span start time
100 * @tparam T etw::Span
101 * @param t instance of etw::Span
102 * @return Span Start timestamp
105 common::SystemTimestamp
GetStartTime(T
&t
)
107 return t
.GetStartTime();
111 * @brief Utility template to obtain Span end time
112 * @tparam T etw::Span
113 * @param t instance of etw::Span
114 * @return Span Stop timestamp
117 common::SystemTimestamp
GetEndTime(T
&t
)
119 return t
.GetEndTime();
125 * @brief Utility template to store Attributes on Span
126 * @tparam T etw::Span
127 * @param instance instance of etw::Span
128 * @param t Properties to store as Attributes
131 void SetSpanAttributes(T
&instance
, Properties
&t
)
133 instance
.SetAttributes(t
);
137 * @brief Utility template to obtain Span Attributes
138 * @tparam T etw::Span
139 * @param instance instance of etw::Span
140 * @return ref to Span Attributes
143 Properties
&GetSpanAttributes(T
&instance
)
145 return instance
.GetAttributes();
149 void UpdateStatus(T
&t
, Properties
&props
)
151 t
.UpdateStatus(props
);
155 * @brief Tracer class that allows to send spans to ETW Provider.
157 class Tracer
: public opentelemetry::trace::Tracer
161 * @brief Parent provider of this Tracer
163 etw::TracerProvider
&tracerProvider_
;
166 * @brief ProviderId (Name or GUID)
171 * @brief Encoding (Manifest, MessagePack or XML)
173 ETWProvider::EventFormat encoding
;
176 * @brief Provider Handle
178 ETWProvider::Handle
&provHandle
;
180 opentelemetry::trace::TraceId traceId_
;
182 std::atomic
<bool> isClosed_
{true};
185 * @brief ETWProvider is a singleton that aggregates all ETW writes.
188 static ETWProvider
&etwProvider()
190 static ETWProvider instance
; // C++11 magic static
195 * @brief Internal method that allows to populate Links to other Spans.
196 * Span links are in hexadecimal representation, comma-separated in their
197 * order of appearance.
202 virtual void DecorateLinks(Properties
&attributes
,
203 const opentelemetry::trace::SpanContextKeyValueIterable
&links
) const
205 // Add `SpanLinks` attribute if the list is not empty
209 std::string linksValue
;
210 links
.ForEachKeyValue(
211 [&](opentelemetry::trace::SpanContext ctx
, const common::KeyValueIterable
&) {
212 if (!linksValue
.empty())
215 linksValue
+= ToLowerBase16(ctx
.span_id());
220 attributes
[ETW_FIELD_SPAN_LINKS
] = linksValue
;
225 * @brief Allow our friendly etw::Span to end itself on Tracer.
229 virtual void EndSpan(const Span
&span
,
230 const opentelemetry::trace::Span
*parentSpan
= nullptr,
231 const opentelemetry::trace::EndSpanOptions
& = {})
233 const auto &cfg
= GetConfiguration(tracerProvider_
);
234 const opentelemetry::trace::Span
&spanBase
=
235 reinterpret_cast<const opentelemetry::trace::Span
&>(span
);
236 auto spanContext
= spanBase
.GetContext();
238 // Populate Span with presaved attributes
239 Span
¤tSpan
= const_cast<Span
&>(span
);
240 Properties evt
= GetSpanAttributes(currentSpan
);
241 evt
[ETW_FIELD_NAME
] = GetName(span
);
243 if (cfg
.enableSpanId
)
245 evt
[ETW_FIELD_SPAN_ID
] = ToLowerBase16(spanContext
.span_id());
248 if (cfg
.enableTraceId
)
250 evt
[ETW_FIELD_TRACE_ID
] = ToLowerBase16(spanContext
.trace_id());
253 // Populate ActivityId if enabled
255 LPGUID ActivityIdPtr
= nullptr;
256 if (cfg
.enableActivityId
)
258 if (CopySpanIdToActivityId(spanBase
.GetContext().span_id(), ActivityId
))
260 ActivityIdPtr
= &ActivityId
;
264 // Populate RelatedActivityId if enabled
265 GUID RelatedActivityId
;
266 LPGUID RelatedActivityIdPtr
= nullptr;
267 if (cfg
.enableRelatedActivityId
)
269 if (parentSpan
!= nullptr)
271 if (CopySpanIdToActivityId(parentSpan
->GetContext().span_id(), RelatedActivityId
))
273 RelatedActivityIdPtr
= &RelatedActivityId
;
278 if (cfg
.enableActivityTracking
)
280 // TODO: check what EndSpanOptions should be supported for this exporter.
281 // The only option available currently (end_steady_time) does not apply.
283 // This event on Span Stop enables generation of "non-transactional"
284 // OpCode=Stop in alignment with TraceLogging Activity "EventSource"
286 etwProvider().write(provHandle
, evt
, ActivityIdPtr
, RelatedActivityIdPtr
, 2, encoding
);
290 // Now since the span has ended, we need to emit the "Span" event that
291 // contains the entire span information, attributes, time, etc. on it.
292 evt
[ETW_FIELD_NAME
] = ETW_VALUE_SPAN
;
293 evt
[ETW_FIELD_PAYLOAD_NAME
] = GetName(span
);
295 // Add timing details in ISO8601 format, which adequately represents
296 // the actual time, taking Timezone into consideration. This is NOT
297 // local time, but rather UTC time (Z=0).
298 std::chrono::system_clock::time_point startTime
= GetStartTime(currentSpan
);
299 std::chrono::system_clock::time_point endTime
= GetEndTime(currentSpan
);
300 int64_t startTimeMs
=
301 std::chrono::duration_cast
<std::chrono::milliseconds
>(startTime
.time_since_epoch())
304 std::chrono::duration_cast
<std::chrono::milliseconds
>(endTime
.time_since_epoch()).count();
306 // It may be more optimal to enable passing timestamps as UTC milliseconds
307 // since Unix epoch instead of string, but that implies additional tooling
308 // is needed to convert it, rendering it NOT human-readable.
309 evt
[ETW_FIELD_STARTTIME
] = utils::formatUtcTimestampMsAsISO8601(startTimeMs
);
310 #ifdef ETW_FIELD_ENDTTIME
311 // ETW has its own precise timestamp at envelope layer for every event.
312 // However, in some scenarios it is easier to deal with ISO8601 strings.
313 // In that case we convert the app-created timestamp and place it into
314 // Payload[$ETW_FIELD_TIME] field. The option configurable at compile-time.
315 evt
[ETW_FIELD_ENDTTIME
] = utils::formatUtcTimestampMsAsISO8601(endTimeMs
);
317 // Duration of Span in milliseconds
318 evt
[ETW_FIELD_DURATION
] = endTimeMs
- startTimeMs
;
319 // Presently we assume that all spans are server spans
320 evt
[ETW_FIELD_SPAN_KIND
] = uint32_t(opentelemetry::trace::SpanKind::kServer
);
321 UpdateStatus(currentSpan
, evt
);
322 etwProvider().write(provHandle
, evt
, ActivityIdPtr
, RelatedActivityIdPtr
, 0, encoding
);
326 const opentelemetry::trace::TraceId
&trace_id() { return traceId_
; }
331 * @brief Init a reference to etw::ProviderHandle
332 * @return Provider Handle
334 ETWProvider::Handle
&initProvHandle()
337 return etwProvider().open(provId
, encoding
);
342 * @brief Tracer constructor
343 * @param parent Parent TraceProvider
344 * @param providerId ProviderId - Name or GUID
345 * @param encoding ETW encoding format to use.
347 Tracer(etw::TracerProvider
&parent
,
348 nostd::string_view providerId
= "",
349 ETWProvider::EventFormat encoding
= ETWProvider::EventFormat::ETW_MANIFEST
)
350 : opentelemetry::trace::Tracer(),
351 tracerProvider_(parent
),
352 provId(providerId
.data(), providerId
.size()),
354 provHandle(initProvHandle())
356 // Generate random GUID
358 CoCreateGuid(&trace_id
);
359 // Populate TraceId of the Tracer with the above GUID
360 const auto *traceIdPtr
= reinterpret_cast<const uint8_t *>(std::addressof(trace_id
));
361 nostd::span
<const uint8_t, opentelemetry::trace::TraceId::kSize
> traceIdBytes(
362 traceIdPtr
, traceIdPtr
+ opentelemetry::trace::TraceId::kSize
);
363 traceId_
= opentelemetry::trace::TraceId(traceIdBytes
);
368 * @param name Span name
369 * @param attributes Span attributes
370 * @param links Span links
371 * @param options Span options
374 nostd::shared_ptr
<opentelemetry::trace::Span
> StartSpan(
375 nostd::string_view name
,
376 const common::KeyValueIterable
&attributes
,
377 const opentelemetry::trace::SpanContextKeyValueIterable
&links
,
378 const opentelemetry::trace::StartSpanOptions
&options
= {}) noexcept override
380 #ifdef OPENTELEMETRY_RTTI_ENABLED
381 common::KeyValueIterable
&attribs
= const_cast<common::KeyValueIterable
&>(attributes
);
382 Properties
*evt
= dynamic_cast<Properties
*>(&attribs
);
385 // Pass as a reference to original modifyable collection without creating a copy
386 return StartSpan(name
, *evt
, links
, options
);
389 Properties evtCopy
= attributes
;
390 return StartSpan(name
, evtCopy
, links
, options
);
395 * @param name Span name
396 * @param attributes Span attributes
397 * @param links Span links
398 * @param options Span options
401 virtual nostd::shared_ptr
<opentelemetry::trace::Span
> StartSpan(
402 nostd::string_view name
,
404 const opentelemetry::trace::SpanContextKeyValueIterable
&links
,
405 const opentelemetry::trace::StartSpanOptions
&options
= {}) noexcept
407 const auto &cfg
= GetConfiguration(tracerProvider_
);
410 // - either use current span
411 // - or attach to parent SpanContext specified in options
412 opentelemetry::trace::SpanContext parentContext
= GetCurrentSpan()->GetContext();
413 if (nostd::holds_alternative
<opentelemetry::trace::SpanContext
>(options
.parent
))
415 auto span_context
= nostd::get
<opentelemetry::trace::SpanContext
>(options
.parent
);
416 if (span_context
.IsValid())
418 parentContext
= span_context
;
422 // Populate Etw.RelatedActivityId at envelope level if enabled
423 GUID RelatedActivityId
;
424 LPCGUID RelatedActivityIdPtr
= nullptr;
425 if (cfg
.enableAutoParent
)
427 if (cfg
.enableRelatedActivityId
)
429 if (CopySpanIdToActivityId(parentContext
.span_id(), RelatedActivityId
))
431 RelatedActivityIdPtr
= &RelatedActivityId
;
436 // This template pattern allows us to forward-declare the etw::Span,
437 // create an instance of it, then assign it to tracer::Span result.
438 auto currentSpan
= new_span
<Span
, Tracer
>(this, name
, options
);
439 nostd::shared_ptr
<opentelemetry::trace::Span
> result
= to_span_ptr
<Span
>(currentSpan
);
441 auto spanContext
= result
->GetContext();
443 // Decorate with additional standard fields
444 std::string eventName
= name
.data();
446 // Populate Etw.EventName attribute at envelope level
447 evt
[ETW_FIELD_NAME
] = eventName
;
449 // Populate Payload["SpanId"] attribute
450 // Populate Payload["ParentSpanId"] attribute if parent Span is valid
451 if (cfg
.enableSpanId
)
453 if (parentContext
.IsValid())
455 evt
[ETW_FIELD_SPAN_PARENTID
] = ToLowerBase16(parentContext
.span_id());
457 evt
[ETW_FIELD_SPAN_ID
] = ToLowerBase16(spanContext
.span_id());
460 // Populate Etw.Payload["TraceId"] attribute
461 if (cfg
.enableTraceId
)
463 evt
[ETW_FIELD_TRACE_ID
] = ToLowerBase16(spanContext
.trace_id());
466 // Populate Etw.ActivityId at envelope level if enabled
468 LPCGUID ActivityIdPtr
= nullptr;
469 if (cfg
.enableActivityId
)
471 if (CopySpanIdToActivityId(result
.get()->GetContext().span_id(), ActivityId
))
473 ActivityIdPtr
= &ActivityId
;
478 DecorateLinks(evt
, links
);
480 // Remember Span attributes to be passed down to ETW on Span end
481 SetSpanAttributes(*currentSpan
, evt
);
483 if (cfg
.enableActivityTracking
)
485 // TODO: add support for options that are presently ignored :
487 // - options.start_steady_time
488 // - options.start_system_time
489 etwProvider().write(provHandle
, evt
, ActivityIdPtr
, RelatedActivityIdPtr
, 1, encoding
);
496 * @brief Force flush data to Tracer, spending up to given amount of microseconds to flush.
497 * NOTE: this method has no effect for the realtime streaming Tracer.
499 * @param timeout Allow Tracer to drop data if timeout is reached
502 void ForceFlushWithMicroseconds(uint64_t) noexcept override
{}
505 * @brief Close tracer, spending up to given amount of microseconds to flush and close.
506 * NOTE: This method decrements the reference count on current ETW Provider Handle and
507 * closes it if reference count on that provider handle is zero.
509 * @param timeout Allow Tracer to drop data if timeout is reached.
512 void CloseWithMicroseconds(uint64_t) noexcept override
515 if (!isClosed_
.exchange(true))
517 etwProvider().close(provHandle
);
522 * @brief Add event data to span associated with tracer.
523 * @param span Parent span.
524 * @param name Event name.
525 * @param timestamp Event timestamp.
526 * @param attributes Event attributes.
529 void AddEvent(opentelemetry::trace::Span
&span
,
530 nostd::string_view name
,
531 common::SystemTimestamp timestamp
,
532 const common::KeyValueIterable
&attributes
) noexcept
534 #ifdef OPENTELEMETRY_RTTI_ENABLED
535 common::KeyValueIterable
&attribs
= const_cast<common::KeyValueIterable
&>(attributes
);
536 Properties
*evt
= dynamic_cast<Properties
*>(&attribs
);
539 // Pass as a reference to original modifyable collection without creating a copy
540 return AddEvent(span
, name
, timestamp
, *evt
);
543 // Pass a copy converted to Properties object on stack
544 Properties evtCopy
= attributes
;
545 return AddEvent(span
, name
, timestamp
, evtCopy
);
549 * @brief Add event data to span associated with tracer.
550 * @param span Parent span.
551 * @param name Event name.
552 * @param timestamp Event timestamp.
553 * @param attributes Event attributes.
556 void AddEvent(opentelemetry::trace::Span
&span
,
557 nostd::string_view name
,
558 common::SystemTimestamp timestamp
,
559 Properties
&evt
) noexcept
561 // TODO: respect originating timestamp. Do we need to reserve
562 // a special 'Timestamp' field or is it an overkill? The delta
563 // between when `AddEvent` API is called and when ETW layer
564 // timestamp is appended is nanos- to micros-, thus handling
565 // the explicitly provided timestamp is only necessary in case
566 // if a process wants to submit back-dated or future-dated
567 // timestamp. Unless there is a strong ask from any ETW customer
568 // to have it, this feature (custom timestamp) remains unimplemented.
571 const auto &cfg
= GetConfiguration(tracerProvider_
);
573 evt
[ETW_FIELD_NAME
] = name
.data();
575 const auto &spanContext
= span
.GetContext();
576 if (cfg
.enableSpanId
)
578 evt
[ETW_FIELD_SPAN_ID
] = ToLowerBase16(spanContext
.span_id());
581 if (cfg
.enableTraceId
)
583 evt
[ETW_FIELD_TRACE_ID
] = ToLowerBase16(spanContext
.trace_id());
586 LPGUID ActivityIdPtr
= nullptr;
588 if (cfg
.enableActivityId
)
590 if (CopySpanIdToActivityId(spanContext
.span_id(), ActivityId
))
592 ActivityIdPtr
= &ActivityId
;
596 #ifdef HAVE_FIELD_TIME
598 auto timeNow
= std::chrono::system_clock::now().time_since_epoch();
599 auto millis
= std::chrono::duration_cast
<std::chrono::milliseconds
>(timeNow
).count();
600 evt
[ETW_FIELD_TIME
] = utils::formatUtcTimestampMsAsISO8601(millis
);
604 etwProvider().write(provHandle
, evt
, ActivityIdPtr
, nullptr, 0, encoding
);
608 * @brief Add event data to span associated with tracer.
610 * @param name Event name.
611 * @param timestamp Event timestamp.
614 void AddEvent(opentelemetry::trace::Span
&span
,
615 nostd::string_view name
,
616 common::SystemTimestamp timestamp
) noexcept
618 AddEvent(span
, name
, timestamp
, sdk::GetEmptyAttributes());
622 * @brief Add event data to span associated with tracer.
624 * @param name Event name.
626 void AddEvent(opentelemetry::trace::Span
&span
, nostd::string_view name
)
628 AddEvent(span
, name
, std::chrono::system_clock::now(), sdk::GetEmptyAttributes());
632 * @brief Tracer destructor.
634 virtual ~Tracer() { CloseWithMicroseconds(0); }
638 * @brief etw::Span allows to send event data to ETW listener.
640 class Span
: public opentelemetry::trace::Span
646 * @brief Span properties are attached on "Span" event on end of Span.
648 Properties attributes_
;
650 common::SystemTimestamp start_time_
;
651 common::SystemTimestamp end_time_
;
653 opentelemetry::trace::StatusCode status_code_
{opentelemetry::trace::StatusCode::kUnset
};
654 std::string status_description_
;
657 * @brief Owner Tracer of this Span
664 nostd::string_view name_
;
667 * @brief Attribute indicating that the span has ended.
669 std::atomic
<bool> has_ended_
{false};
672 * @brief Attribute indicating that the span has started.
674 std::atomic
<bool> has_started_
{false};
677 * @brief Parent Span of this nested Span (optional)
679 Span
*parent_
{nullptr};
682 * @brief Get Parent Span of this nested Span.
683 * @return Pointer to Parent or nullptr if no Parent.
685 Span
*GetParent() const { return parent_
; }
687 opentelemetry::trace::SpanContext context_
;
689 const opentelemetry::trace::SpanContext
CreateContext()
692 // Generate random GUID
693 CoCreateGuid(&activity_id
);
694 const auto *activityIdPtr
= reinterpret_cast<const uint8_t *>(std::addressof(activity_id
));
696 // Populate SpanId with that GUID
697 nostd::span
<const uint8_t, opentelemetry::trace::SpanId::kSize
> spanIdBytes(
698 activityIdPtr
, activityIdPtr
+ opentelemetry::trace::SpanId::kSize
);
699 const opentelemetry::trace::SpanId
spanId(spanIdBytes
);
701 // Inherit trace_id from Tracer
702 const opentelemetry::trace::TraceId traceId
{owner_
.trace_id()};
703 // TODO: TraceFlags are not supported by ETW exporter.
704 const opentelemetry::trace::TraceFlags flags
{0};
705 // TODO: Remote parent is not supported by ETW exporter.
706 const bool hasRemoteParent
= false;
707 return opentelemetry::trace::SpanContext
{traceId
, spanId
, flags
, hasRemoteParent
};
712 * @brief Update Properties object with current Span status
715 void UpdateStatus(Properties
&evt
)
717 /* Should we avoid populating this extra field if status is unset? */
718 if ((status_code_
== opentelemetry::trace::StatusCode::kUnset
) ||
719 (status_code_
== opentelemetry::trace::StatusCode::kOk
))
721 evt
[ETW_FIELD_SUCCESS
] = "True";
722 evt
[ETW_FIELD_STATUSCODE
] = uint32_t(status_code_
);
723 evt
[ETW_FIELD_STATUSMESSAGE
] = status_description_
;
727 evt
[ETW_FIELD_SUCCESS
] = "False";
728 evt
[ETW_FIELD_STATUSCODE
] = uint32_t(status_code_
);
729 evt
[ETW_FIELD_STATUSMESSAGE
] = status_description_
;
734 * @brief Get start time of this Span.
737 common::SystemTimestamp
GetStartTime() { return start_time_
; }
740 * @brief Get end time of this Span.
743 common::SystemTimestamp
GetEndTime() { return end_time_
; }
746 * @brief Get Span Name.
749 nostd::string_view
GetName() const { return name_
; }
752 * @brief Span constructor
753 * @param owner Owner Tracer
754 * @param name Span name
755 * @param options Span options
756 * @param parent Parent Span (optional)
760 nostd::string_view name
,
761 const opentelemetry::trace::StartSpanOptions
&options
,
762 Span
*parent
= nullptr) noexcept
763 : opentelemetry::trace::Span(),
764 start_time_(std::chrono::system_clock::now()),
767 context_(CreateContext())
770 UNREFERENCED_PARAMETER(options
);
774 * @brief Span Destructor
779 * @brief Add named event with no attributes.
780 * @param name Event name.
783 void AddEvent(nostd::string_view name
) noexcept override
{ owner_
.AddEvent(*this, name
); }
786 * @brief Add named event with custom timestamp.
791 void AddEvent(nostd::string_view name
, common::SystemTimestamp timestamp
) noexcept override
793 owner_
.AddEvent(*this, name
, timestamp
);
797 * @brief Add named event with custom timestamp and attributes.
798 * @param name Event name.
799 * @param timestamp Event timestamp.
800 * @param attributes Event attributes.
803 void AddEvent(nostd::string_view name
,
804 common::SystemTimestamp timestamp
,
805 const common::KeyValueIterable
&attributes
) noexcept override
807 owner_
.AddEvent(*this, name
, timestamp
, attributes
);
811 * @brief Set Span status
812 * @param code Span status code.
813 * @param description Span description.
816 void SetStatus(opentelemetry::trace::StatusCode code
,
817 nostd::string_view description
) noexcept override
820 status_description_
= description
.data();
823 void SetAttributes(Properties attributes
) { attributes_
= attributes
; }
826 * @brief Obtain span attributes specified at Span start.
827 * NOTE: please consider that this method is NOT thread-safe.
829 * @return ref to Properties collection
831 Properties
&GetAttributes() { return attributes_
; }
834 * @brief Sets an attribute on the Span. If the Span previously contained a mapping
835 * for the key, the old value is replaced.
841 void SetAttribute(nostd::string_view key
, const common::AttributeValue
&value
) noexcept override
843 // don't override fields propagated from span data.
844 if (key
== ETW_FIELD_NAME
|| key
== ETW_FIELD_SPAN_ID
|| key
== ETW_FIELD_TRACE_ID
)
848 attributes_
[std::string
{key
}].FromAttributeValue(value
);
852 * @brief Update Span name.
854 * NOTE: this method is a no-op for streaming implementation.
855 * We cannot change the Span name after it started streaming.
860 void UpdateName(nostd::string_view
) noexcept override
868 * @param EndSpanOptions
871 void End(const opentelemetry::trace::EndSpanOptions
&options
= {}) noexcept override
873 end_time_
= std::chrono::system_clock::now();
875 if (!has_ended_
.exchange(true))
877 owner_
.EndSpan(*this, parent_
, options
);
882 * @brief Obtain SpanContext
885 opentelemetry::trace::SpanContext
GetContext() const noexcept override
{ return context_
; }
888 * @brief Check if Span is recording data.
891 bool IsRecording() const noexcept override
893 // For streaming implementation this should return the state of ETW Listener.
894 // In certain unprivileged environments, ex. containers, it is impossible
895 // to determine if a listener is registered. Thus, we always return true.
899 virtual void SetToken(nostd::unique_ptr
<context::Token
> &&token
) noexcept
901 // TODO: not implemented
902 UNREFERENCED_PARAMETER(token
);
906 /// Get Owner tracer of this Span
908 /// <returns></returns>
909 opentelemetry::trace::Tracer
&tracer() const noexcept
{ return this->owner_
; }
913 * @brief ETW TracerProvider
915 class TracerProvider
: public opentelemetry::trace::TracerProvider
919 * @brief TracerProvider options supplied during initialization.
921 TelemetryProviderConfiguration config_
;
924 * @brief Construct instance of TracerProvider with given options
925 * @param options Configuration options
927 TracerProvider(TelemetryProviderOptions options
) : opentelemetry::trace::TracerProvider()
929 // By default we ensure that all events carry their with TraceId and SpanId
930 GetOption(options
, "enableTraceId", config_
.enableTraceId
, true);
931 GetOption(options
, "enableSpanId", config_
.enableSpanId
, true);
933 // Backwards-compatibility option that allows to reuse ETW-specific parenting described here:
934 // https://docs.microsoft.com/en-us/uwp/api/windows.foundation.diagnostics.loggingoptions.relatedactivityid
935 // https://docs.microsoft.com/en-us/windows/win32/api/evntprov/nf-evntprov-eventwritetransfer
937 // Emit separate events compatible with TraceLogging Activity/Start and Activity/Stop
938 // format for every Span emitted.
939 GetOption(options
, "enableActivityTracking", config_
.enableActivityTracking
, false);
941 // Map current `SpanId` to ActivityId - GUID that uniquely identifies this activity. If NULL,
942 // ETW gets the identifier from the thread local storage. For details on getting this
943 // identifier, see EventActivityIdControl.
944 GetOption(options
, "enableActivityId", config_
.enableActivityId
, false);
946 // Map parent `SpanId` to RelatedActivityId - Activity identifier from the previous
947 // component. Use this parameter to link your component's events to the previous component's
949 GetOption(options
, "enableRelatedActivityId", config_
.enableRelatedActivityId
, false);
951 // When a new Span is started, the current span automatically becomes its parent.
952 GetOption(options
, "enableAutoParent", config_
.enableAutoParent
, false);
954 // Determines what encoding to use for ETW events: TraceLogging Dynamic, MsgPack, XML, etc.
955 config_
.encoding
= GetEncoding(options
);
958 TracerProvider() : opentelemetry::trace::TracerProvider()
960 config_
.enableTraceId
= true;
961 config_
.enableSpanId
= true;
962 config_
.enableActivityId
= false;
963 config_
.enableActivityTracking
= false;
964 config_
.enableRelatedActivityId
= false;
965 config_
.enableAutoParent
= false;
966 config_
.encoding
= ETWProvider::EventFormat::ETW_MANIFEST
;
970 * @brief Obtain ETW Tracer.
971 * @param name ProviderId (instrumentation name) - Name or GUID
973 * @param args Additional arguments that controls `codec` of the provider.
974 * Possible values are:
975 * - "ETW" - 'classic' Trace Logging Dynamic manifest ETW events.
976 * - "MSGPACK" - MessagePack-encoded binary payload ETW events.
977 * - "XML" - XML events (reserved for future use)
980 nostd::shared_ptr
<opentelemetry::trace::Tracer
> GetTracer(
981 nostd::string_view name
,
982 nostd::string_view args
= "",
983 nostd::string_view schema_url
= "") noexcept override
985 UNREFERENCED_PARAMETER(args
);
986 UNREFERENCED_PARAMETER(schema_url
);
987 ETWProvider::EventFormat evtFmt
= config_
.encoding
;
988 return nostd::shared_ptr
<opentelemetry::trace::Tracer
>{new (std::nothrow
)
989 Tracer(*this, name
, evtFmt
)};
994 } // namespace exporter
995 OPENTELEMETRY_END_NAMESPACE