| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- #ifdef _WIN32
- # include <gtest/gtest.h>
- # include <map>
- # include <string>
- # include "opentelemetry//sdk/trace/sampler.h"
- # include "opentelemetry/exporters/etw/etw_tracer_exporter.h"
- # include "opentelemetry/sdk/trace/samplers/always_off.h"
- # include "opentelemetry/sdk/trace/simple_processor.h"
- using namespace OPENTELEMETRY_NAMESPACE;
- using namespace opentelemetry::exporter::etw;
- using namespace opentelemetry::sdk::trace;
- const char *kGlobalProviderName = "OpenTelemetry-ETW-TLD";
- std::string getTemporaryValue()
- {
- return std::string("Value from Temporary std::string");
- }
- /**
- * A Mock Custom Id Generator
- */
- class MockIdGenerator : public sdk::trace::IdGenerator
- {
- public:
- MockIdGenerator() : sdk::trace::IdGenerator(false) {}
- opentelemetry::trace::SpanId GenerateSpanId() noexcept override
- {
- return opentelemetry::trace::SpanId(buf_span);
- }
- opentelemetry::trace::TraceId GenerateTraceId() noexcept override
- {
- return opentelemetry::trace::TraceId(buf_trace);
- }
- uint8_t buf_span[8] = {1, 2, 3, 4, 5, 6, 7, 8};
- uint8_t buf_trace[16] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1};
- };
- /* A Custom Sampler, implementing parent based sampler*/
- class MockSampler : public sdk::trace::Sampler
- {
- public:
- MockSampler(std::shared_ptr<Sampler> delegate_sampler) noexcept
- : delegate_sampler_(delegate_sampler)
- {}
- sdk::trace::SamplingResult ShouldSample(
- const trace_api::SpanContext &parent_context,
- trace_api::TraceId trace_id,
- nostd::string_view name,
- trace_api::SpanKind span_kind,
- const opentelemetry::common::KeyValueIterable &attributes,
- const trace_api::SpanContextKeyValueIterable &links) noexcept
- {
- if (!parent_context.IsValid())
- {
- // If no parent (root span) exists returns the result of the delegateSampler
- return delegate_sampler_->ShouldSample(parent_context, trace_id, name, span_kind, attributes,
- links);
- }
- // If parent exists:
- if (parent_context.IsSampled())
- {
- return {Decision::RECORD_AND_SAMPLE, nullptr, parent_context.trace_state()};
- }
- return {Decision::DROP, nullptr, parent_context.trace_state()};
- }
- nostd::string_view GetDescription() const noexcept { return "Custom Sampler"; }
- private:
- std::shared_ptr<Sampler> delegate_sampler_;
- };
- class AlwaysOffTailSampler : public TailSampler
- {
- public:
- opentelemetry::sdk::trace::SamplingResult ShouldSample(
- const opentelemetry::trace::Span &span) noexcept override
- {
- return {opentelemetry::sdk::trace::Decision::DROP};
- }
- };
- /* clang-format off */
- TEST(ETWTracer, TracerCheck)
- {
- // SDK customer specifies their unique ETW ProviderName. Every component or library
- // is assumed to have its own instrumentation name. Traces are routed to dedicated
- // provider. Standard hash function maps from ProviderName to ProviderGUID.
- //
- // Prominent naming examples from `logman query providers` :
- //
- // [Docker] {a3693192-9ed6-46d2-a981-f8226c8363bd}
- // ...
- // Intel-Autologger-iclsClient {B8D7E9A0-65D5-40BE-AFEA-83593FC0164E}
- // Intel-Autologger-iclsProxy {301B773F-50F3-4C8E-83F0-53BA9590A13E}
- // Intel-Autologger-PTTEKRecertification {F33E9E07-8792-47E8-B3FA-2C92AB32C5B3}
- // ...
- // NodeJS-ETW-provider {77754E9B-264B-4D8D-B981-E4135C1ECB0C}
- // ...
- // OpenSSH {C4B57D35-0636-4BC3-A262-370F249F9802}
- // ...
- // Windows Connect Now {C100BECE-D33A-4A4B-BF23-BBEF4663D017}
- // Windows Defender Firewall API {28C9F48F-D244-45A8-842F-DC9FBC9B6E92}
- // Windows Defender Firewall API - GP {0EFF663F-8B6E-4E6D-8182-087A8EAA29CB}
- // Windows Defender Firewall Driver {D5E09122-D0B2-4235-ADC1-C89FAAAF1069}
- std::string providerName = kGlobalProviderName; // supply unique instrumentation name here
- exporter::etw::TracerProvider tp;
- auto tracer = tp.GetTracer(providerName);
- // Span attributes
- Properties outer_attribs =
- {
- {"attrib1", 1},
- {"attrib2", 2}
- };
- // copy the outer attributes
- Properties inner_attribs = outer_attribs;
- {
- auto topSpan = tracer->StartSpan("MySpanTop");
- auto topScope = tracer->WithActiveSpan(topSpan);
- {
- auto outerSpan = tracer->StartSpan("MySpanL2", outer_attribs);
- auto outerScope = tracer->WithActiveSpan(outerSpan);
- // Create nested span. Note how we share the attributes here.
- // It is Okay to either reuse/share or have your own attributes.
- {
- auto innerSpan = tracer->StartSpan("MySpanL3", inner_attribs);
- auto innerScope = tracer->WithActiveSpan(innerSpan);
- // Add span attribute
- EXPECT_NO_THROW(outerSpan->SetAttribute("AttrName1", "AttrValue1"));
- // Add first event
- std::string eventName1 = "MyEvent1";
- Properties event1 =
- {
- {"uint32Key", (uint32_t)1234},
- {"uint64Key", (uint64_t)1234567890},
- {"strKey", "someValue"}
- };
- EXPECT_NO_THROW(outerSpan->AddEvent(eventName1, event1));
- // Add second event
- std::string eventName2 = "MyEvent2";
- Properties event2 =
- {
- {"uint32Key", (uint32_t)9876},
- {"uint64Key", (uint64_t)987654321},
- {"strKey", "anotherValue"}
- };
- EXPECT_NO_THROW(outerSpan->AddEvent(eventName2, event2));
- std::string eventName3= "MyEvent3";
- Properties event3 =
- {
- /* Extra metadata that allows event to flow to A.I. pipeline */
- {"metadata", "ai_event"},
- {"uint32Key", (uint32_t)9876},
- {"uint64Key", (uint64_t)987654321},
- // {"int32array", {{-1,0,1,2,3}} },
- {"tempString", getTemporaryValue() }
- };
- EXPECT_NO_THROW(innerSpan->AddEvent(eventName3, event3));
- EXPECT_NO_THROW(innerSpan->End());
- }
- EXPECT_NO_THROW(outerSpan->End());
- }
- EXPECT_NO_THROW(topSpan->End());
- }
- # if OPENTELEMETRY_ABI_VERSION_NO == 1
- EXPECT_NO_THROW(tracer->CloseWithMicroseconds(0));
- # endif
- }
- // Lowest decoration level -> smaller ETW event size.
- // Expected output in C# listener on the other side:
- // no ActivityID GUID, no SpanId, no TraceId.
- /*
- {
- "Timestamp": "2021-03-19T21:04:38.411193-07:00",
- "ProviderName": "OpenTelemetry-ETW-TLD",
- "Id": 13,
- "Message": null,
- "ProcessId": 15120,
- "Level": "Always",
- "Keywords": "0x0000000000000000",
- "EventName": "C.min/Stop",
- "ActivityID": null,
- "RelatedActivityID": null,
- "Payload": {}
- }
- */
- TEST(ETWTracer, TracerCheckMinDecoration)
- {
- std::string providerName = kGlobalProviderName;
- exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", false},
- {"enableSpanId", false},
- {"enableActivityId", false},
- {"enableActivityTracking", true},
- {"enableRelatedActivityId", false},
- {"enableAutoParent", false}
- });
- auto tracer = tp.GetTracer(providerName);
- {
- auto aSpan = tracer->StartSpan("A.min");
- auto aScope = tracer->WithActiveSpan(aSpan);
- {
- auto bSpan = tracer->StartSpan("B.min");
- auto bScope = tracer->WithActiveSpan(bSpan);
- {
- auto cSpan = tracer->StartSpan("C.min");
- auto cScope = tracer->WithActiveSpan(cSpan);
- EXPECT_NO_THROW(cSpan->End());
- }
- EXPECT_NO_THROW(bSpan->End());
- }
- EXPECT_NO_THROW(aSpan->End());
- }
- # if OPENTELEMETRY_ABI_VERSION_NO == 1
- tracer->CloseWithMicroseconds(0);
- # endif
- }
- // Highest decoration level -> larger ETW event size
- // Expected output in C# listener on the other side:
- // ActivityID GUID (==SpanId), SpanId, TraceId.
- /*
- {
- "Timestamp": "2021-03-19T21:04:38.4120274-07:00",
- "ProviderName": "OpenTelemetry-ETW-TLD",
- "Id": 21,
- "Message": null,
- "ProcessId": 15120,
- "Level": "Always",
- "Keywords": "0x0000000000000000",
- "EventName": "C.max/Stop",
- "ActivityID": "d55a2c25-8033-40ab-0000-000000000000",
- "RelatedActivityID": null,
- "Payload": {
- "SpanId": "252c5ad53380ab40",
- "TraceId": "4dea2a63c188894ea5ab979e5cd7ec36"
- }
- }
- */
- TEST(ETWTracer, TracerCheckMaxDecoration)
- {
- std::string providerName = kGlobalProviderName;
- exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", true},
- {"enableSpanId", true},
- {"enableActivityId", true},
- {"enableRelatedActivityId", true},
- {"enableAutoParent", true}
- });
- auto tracer = tp.GetTracer(providerName);
- {
- auto aSpan = tracer->StartSpan("A.max");
- auto aScope = tracer->WithActiveSpan(aSpan);
- {
- auto bSpan = tracer->StartSpan("B.max");
- auto bScope = tracer->WithActiveSpan(bSpan);
- {
- auto cSpan = tracer->StartSpan("C.max");
- auto cScope = tracer->WithActiveSpan(cSpan);
- EXPECT_NO_THROW(cSpan->End());
- }
- EXPECT_NO_THROW(bSpan->End());
- }
- EXPECT_NO_THROW(aSpan->End());
- }
- # if OPENTELEMETRY_ABI_VERSION_NO == 1
- tracer->CloseWithMicroseconds(0);
- # endif
- }
- TEST(ETWTracer, TracerCheckMsgPack)
- {
- std::string providerName = "OpenTelemetry-ETW-MsgPack";
- exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", true},
- {"enableSpanId", true},
- {"enableActivityId", true},
- {"enableRelatedActivityId", true},
- {"enableAutoParent", true}
- });
- auto tracer = tp.GetTracer(providerName);
- {
- auto aSpan = tracer->StartSpan("A.max");
- auto aScope = tracer->WithActiveSpan(aSpan);
- {
- auto bSpan = tracer->StartSpan("B.max");
- auto bScope = tracer->WithActiveSpan(bSpan);
- {
- auto cSpan = tracer->StartSpan("C.max");
- auto cScope = tracer->WithActiveSpan(cSpan);
- std::string eventName = "MyMsgPackEvent";
- Properties event =
- {
- {"uint32Key", (uint32_t)1234},
- {"uint64Key", (uint64_t)1234567890},
- {"strKey", "someValue"}
- };
- cSpan->AddEvent(eventName, event);
- EXPECT_NO_THROW(cSpan->End());
- }
- EXPECT_NO_THROW(bSpan->End());
- }
- EXPECT_NO_THROW(aSpan->End());
- }
- # if OPENTELEMETRY_ABI_VERSION_NO == 1
- tracer->CloseWithMicroseconds(0);
- # endif
- }
- /**
- * @brief Global Tracer singleton may be placed in .h header and
- * shared across different compilation units. All would get the
- * same object.
- *
- * @return Single global tracer instance.
- */
- static OPENTELEMETRY_NAMESPACE::trace::TracerProvider& GetGlobalTracerProvider()
- {
- static exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", true},
- {"enableSpanId", true},
- {"enableActivityId", true},
- {"enableRelatedActivityId", true},
- {"enableAutoParent", true}
- });
- return tp;
- }
- static OPENTELEMETRY_NAMESPACE::trace::Tracer& GetGlobalTracer()
- {
- static auto tracer = GetGlobalTracerProvider().GetTracer(kGlobalProviderName);
- return (*tracer.get());
- }
- TEST(ETWTracer, GlobalSingletonTracer)
- {
- // Obtain a global tracer using C++11 magic static.
- auto& globalTracer = GetGlobalTracer();
- auto s1 = globalTracer.StartSpan("Span1");
- auto traceId1 = s1->GetContext().trace_id();
- s1->End();
- /* === Span 1 - "TraceId": "182a64258fb1864ca4e1a542eecbd9bf"
- {
- "Timestamp": "2021-05-10T11:45:27.028827-07:00",
- "ProviderName": "OpenTelemetry-ETW-TLD",
- "Id": 5,
- "Message": null,
- "ProcessId": 23712,
- "Level": "Always",
- "Keywords": "0x0000000000000000",
- "EventName": "Span",
- "ActivityID": "6ed94703-6b0a-4e76-0000-000000000000",
- "RelatedActivityID": null,
- "Payload": {
- "Duration": 23456,
- "Kind": 1,
- "Name": "Span1",
- "SpanId": "0347d96e0a6b764e",
- "StartTime": "2021-05-10T18:45:27.066411500Z",
- "StatusCode": 0,
- "StatusMessage": "",
- "Success": "True",
- "TraceId": "182a64258fb1864ca4e1a542eecbd9bf",
- "_name": "Span"
- }
- }
- */
- // Obtain a different tracer withs its own trace-id.
- auto localTracer = GetGlobalTracerProvider().GetTracer(kGlobalProviderName);
- auto s2 = localTracer->StartSpan("Span2");
- auto traceId2 = s2->GetContext().trace_id();
- s2->End();
- /* === Span 2 - "TraceId": "334bf9a1eed98d40a873a606295a9368"
- {
- "Timestamp": "2021-05-10T11:45:27.0289654-07:00",
- "ProviderName": "OpenTelemetry-ETW-TLD",
- "Id": 5,
- "Message": null,
- "ProcessId": 23712,
- "Level": "Always",
- "Keywords": "0x0000000000000000",
- "EventName": "Span",
- "ActivityID": "3b7b2ecb-2e84-4903-0000-000000000000",
- "RelatedActivityID": null,
- "Payload": {
- "Duration": 03434,
- "Kind": 1,
- "Name": "Span2",
- "SpanId": "cb2e7b3b842e0349",
- "StartTime": "2021-05-10T18:45:27.066411500Z",
- "StatusCode": 0,
- "StatusMessage": "",
- "Success": "True",
- "TraceId": "334bf9a1eed98d40a873a606295a9368",
- "_name": "Span"
- }
- }
- */
- // Obtain the same global tracer with the same trace-id as before.
- auto& globalTracer2 = GetGlobalTracer();
- auto s3 = globalTracer2.StartSpan("Span3");
- auto traceId3 = s3->GetContext().trace_id();
- s3->End();
- /* === Span 3 - "TraceId": "182a64258fb1864ca4e1a542eecbd9bf"
- {
- "Timestamp": "2021-05-10T11:45:27.0290936-07:00",
- "ProviderName": "OpenTelemetry-ETW-TLD",
- "Id": 5,
- "Message": null,
- "ProcessId": 23712,
- "Level": "Always",
- "Keywords": "0x0000000000000000",
- "EventName": "Span",
- "ActivityID": "0a970247-ba0e-4d4b-0000-000000000000",
- "RelatedActivityID": null,
- "Payload": {
- "Duration": 12323,
- "Kind": 1,
- "Name": "Span3",
- "SpanId": "4702970a0eba4b4d",
- "StartTime": "2021-05-10T18:45:27.066411500Z",
- "StatusCode": 0,
- "StatusMessage": "",
- "Success": "True",
- "TraceId": "182a64258fb1864ca4e1a542eecbd9bf",
- "_name": "Span"
- }
- }
- */
- EXPECT_NE(traceId1, traceId2);
- EXPECT_EQ(traceId1, traceId3);
- # if OPENTELEMETRY_ABI_VERSION_NO == 1
- localTracer->CloseWithMicroseconds(0);
- globalTracer.CloseWithMicroseconds(0);
- # endif
- }
- TEST(ETWTracer, AlwayOffSampler)
- {
- std::string providerName = kGlobalProviderName; // supply unique instrumentation name here
- std::unique_ptr<sdk::trace::Sampler> always_off{new sdk::trace::AlwaysOffSampler()};
- exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", true},
- {"enableSpanId", true},
- {"enableActivityId", true},
- {"enableRelatedActivityId", true},
- {"enableAutoParent", true}
- },
- std::move(always_off));
- auto tracer = tp.GetTracer(providerName);
- auto span = tracer->StartSpan("span_off");
- EXPECT_EQ(span->GetContext().IsValid(), true);
- EXPECT_EQ(span->GetContext().IsSampled(), false);
- }
- TEST(ETWTracer, AlwayOffTailSampler)
- {
- std::string providerName = kGlobalProviderName; // supply unique instrumentation name here
- std::unique_ptr<sdk::trace::Sampler> always_on{new sdk::trace::AlwaysOnSampler()};
- sdk::trace::IdGenerator *id_generator = new MockIdGenerator();
- std::unique_ptr<TailSampler> always_off_tail{new AlwaysOffTailSampler()};
- exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", true},
- {"enableSpanId", true},
- {"enableActivityId", true},
- {"enableRelatedActivityId", true},
- {"enableAutoParent", true}
- },
- std::move(always_on),
- std::unique_ptr<sdk::trace::IdGenerator>(id_generator),
- std::move(always_off_tail));
- auto tracer = tp.GetTracer(providerName);
- }
- TEST(ETWTracer, CustomIdGenerator)
- {
- std::string providerName = kGlobalProviderName; // supply unique instrumentation name here
- sdk::trace::IdGenerator *id_generator = new MockIdGenerator();
- std::unique_ptr<sdk::trace::Sampler> always_on{new sdk::trace::AlwaysOnSampler()};
- exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", true},
- {"enableSpanId", true},
- {"enableActivityId", true},
- {"enableRelatedActivityId", true},
- {"enableAutoParent", true}
- },
- std::move(always_on),
- std::unique_ptr<sdk::trace::IdGenerator>(id_generator));
- auto tracer = tp.GetTracer(providerName);
- auto span = tracer->StartSpan("span_on");
- EXPECT_EQ(span->GetContext().trace_id(), id_generator->GenerateTraceId());
- }
- TEST(ETWTracer, CustomSampler)
- {
- std::string providerName = kGlobalProviderName; // supply unique instrumentation name here
- auto parent_off = std::unique_ptr<Sampler>(new MockSampler(std::make_shared<AlwaysOnSampler>()));
- exporter::etw::TracerProvider tp
- ({
- {"enableTraceId", true},
- {"enableSpanId", true},
- {"enableActivityId", true},
- {"enableRelatedActivityId", true},
- {"enableAutoParent", true}
- },
- std::move(parent_off));
- auto tracer = tp.GetTracer(providerName);
- {
- auto span = tracer->StartSpan("span_off");
- EXPECT_EQ(span->GetContext().IsValid(), true);
- EXPECT_EQ(span->GetContext().IsSampled(), true);
- auto scope = tracer->WithActiveSpan(span);
- auto trace_id = span->GetContext().trace_id();
- {
- auto child_span = tracer->StartSpan("span on");
- EXPECT_EQ(child_span->GetContext().IsValid(), true);
- EXPECT_EQ(child_span->GetContext().IsSampled(), true);
- EXPECT_EQ(child_span->GetContext().trace_id(), trace_id);
- }
- }
- }
- TEST(ETWTracer, EndWithCustomTime)
- {
- // Obtain a global tracer using C++11 magic static.
- auto& globalTracer = GetGlobalTracer();
- auto s1 = globalTracer.StartSpan("Span1");
- auto traceId1 = s1->GetContext().trace_id();
- opentelemetry::trace::EndSpanOptions end;
- end.end_steady_time = opentelemetry::common::SteadyTimestamp(std::chrono::nanoseconds(40));
- s1->End(end);
- auto end_time = static_cast<opentelemetry::exporter::etw::Span *>(s1.get())->GetEndTime();
- EXPECT_EQ(end.end_steady_time.time_since_epoch(), end_time.time_since_epoch());
- }
- /* clang-format on */
- #endif
|