]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // Copyright The OpenTelemetry Authors |
2 | // SPDX-License-Identifier: Apache-2.0 | |
3 | ||
4 | #ifdef _WIN32 | |
5 | ||
6 | # include <gtest/gtest.h> | |
7 | # include <map> | |
8 | # include <string> | |
9 | ||
10 | # include "opentelemetry/exporters/etw/etw_tracer_exporter.h" | |
11 | # include "opentelemetry/sdk/trace/simple_processor.h" | |
12 | ||
13 | using namespace OPENTELEMETRY_NAMESPACE; | |
14 | ||
15 | using namespace opentelemetry::exporter::etw; | |
16 | ||
17 | const char *kGlobalProviderName = "OpenTelemetry-ETW-TLD"; | |
18 | ||
19 | std::string getTemporaryValue() | |
20 | { | |
21 | return std::string("Value from Temporary std::string"); | |
22 | } | |
23 | ||
24 | /* clang-format off */ | |
25 | TEST(ETWTracer, TracerCheck) | |
26 | { | |
27 | // SDK customer specifies their unique ETW ProviderName. Every component or library | |
28 | // is assumed to have its own instrumentation name. Traces are routed to dedicated | |
29 | // provider. Standard hash function maps from ProviderName to ProviderGUID. | |
30 | // | |
31 | // Prominent naming examples from `logman query providers` : | |
32 | // | |
33 | // [Docker] {a3693192-9ed6-46d2-a981-f8226c8363bd} | |
34 | // ... | |
35 | // Intel-Autologger-iclsClient {B8D7E9A0-65D5-40BE-AFEA-83593FC0164E} | |
36 | // Intel-Autologger-iclsProxy {301B773F-50F3-4C8E-83F0-53BA9590A13E} | |
37 | // Intel-Autologger-PTTEKRecertification {F33E9E07-8792-47E8-B3FA-2C92AB32C5B3} | |
38 | // ... | |
39 | // NodeJS-ETW-provider {77754E9B-264B-4D8D-B981-E4135C1ECB0C} | |
40 | // ... | |
41 | // OpenSSH {C4B57D35-0636-4BC3-A262-370F249F9802} | |
42 | // ... | |
43 | // Windows Connect Now {C100BECE-D33A-4A4B-BF23-BBEF4663D017} | |
44 | // Windows Defender Firewall API {28C9F48F-D244-45A8-842F-DC9FBC9B6E92} | |
45 | // Windows Defender Firewall API - GP {0EFF663F-8B6E-4E6D-8182-087A8EAA29CB} | |
46 | // Windows Defender Firewall Driver {D5E09122-D0B2-4235-ADC1-C89FAAAF1069} | |
47 | ||
48 | std::string providerName = kGlobalProviderName; // supply unique instrumentation name here | |
49 | exporter::etw::TracerProvider tp; | |
50 | ||
51 | auto tracer = tp.GetTracer(providerName); | |
52 | ||
53 | // Span attributes | |
54 | Properties attribs = | |
55 | { | |
56 | {"attrib1", 1}, | |
57 | {"attrib2", 2} | |
58 | }; | |
59 | { | |
60 | auto topSpan = tracer->StartSpan("MySpanTop"); | |
61 | auto topScope = tracer->WithActiveSpan(topSpan); | |
62 | { | |
63 | auto outerSpan = tracer->StartSpan("MySpanL2", attribs); | |
64 | auto outerScope = tracer->WithActiveSpan(outerSpan); | |
65 | ||
66 | // Create nested span. Note how we share the attributes here. | |
67 | // It is Okay to either reuse/share or have your own attributes. | |
68 | { | |
69 | auto innerSpan = tracer->StartSpan("MySpanL3", attribs); | |
70 | auto innerScope = tracer->WithActiveSpan(innerSpan); | |
71 | ||
72 | // Add span attribute | |
73 | EXPECT_NO_THROW(outerSpan->SetAttribute("AttrName1", "AttrValue1")); | |
74 | ||
75 | // Add first event | |
76 | std::string eventName1 = "MyEvent1"; | |
77 | Properties event1 = | |
78 | { | |
79 | {"uint32Key", (uint32_t)1234}, | |
80 | {"uint64Key", (uint64_t)1234567890}, | |
81 | {"strKey", "someValue"} | |
82 | }; | |
83 | EXPECT_NO_THROW(outerSpan->AddEvent(eventName1, event1)); | |
84 | ||
85 | // Add second event | |
86 | std::string eventName2 = "MyEvent2"; | |
87 | Properties event2 = | |
88 | { | |
89 | {"uint32Key", (uint32_t)9876}, | |
90 | {"uint64Key", (uint64_t)987654321}, | |
91 | {"strKey", "anotherValue"} | |
92 | }; | |
93 | EXPECT_NO_THROW(outerSpan->AddEvent(eventName2, event2)); | |
94 | ||
95 | std::string eventName3= "MyEvent3"; | |
96 | Properties event3 = | |
97 | { | |
98 | /* Extra metadata that allows event to flow to A.I. pipeline */ | |
99 | {"metadata", "ai_event"}, | |
100 | {"uint32Key", (uint32_t)9876}, | |
101 | {"uint64Key", (uint64_t)987654321}, | |
102 | // {"int32array", {{-1,0,1,2,3}} }, | |
103 | {"tempString", getTemporaryValue() } | |
104 | }; | |
105 | EXPECT_NO_THROW(innerSpan->AddEvent(eventName3, event3)); | |
106 | EXPECT_NO_THROW(innerSpan->End()); | |
107 | ||
108 | } | |
109 | EXPECT_NO_THROW(outerSpan->End()); | |
110 | ||
111 | } | |
112 | EXPECT_NO_THROW(topSpan->End()); | |
113 | } | |
114 | ||
115 | EXPECT_NO_THROW(tracer->CloseWithMicroseconds(0)); | |
116 | } | |
117 | ||
118 | // Lowest decoration level -> smaller ETW event size. | |
119 | // Expected output in C# listener on the other side: | |
120 | // no ActivityID GUID, no SpanId, no TraceId. | |
121 | /* | |
122 | { | |
123 | "Timestamp": "2021-03-19T21:04:38.411193-07:00", | |
124 | "ProviderName": "OpenTelemetry-ETW-TLD", | |
125 | "Id": 13, | |
126 | "Message": null, | |
127 | "ProcessId": 15120, | |
128 | "Level": "Always", | |
129 | "Keywords": "0x0000000000000000", | |
130 | "EventName": "C.min/Stop", | |
131 | "ActivityID": null, | |
132 | "RelatedActivityID": null, | |
133 | "Payload": {} | |
134 | } | |
135 | */ | |
136 | TEST(ETWTracer, TracerCheckMinDecoration) | |
137 | { | |
138 | std::string providerName = kGlobalProviderName; | |
139 | exporter::etw::TracerProvider tp | |
140 | ({ | |
141 | {"enableTraceId", false}, | |
142 | {"enableSpanId", false}, | |
143 | {"enableActivityId", false}, | |
144 | {"enableActivityTracking", true}, | |
145 | {"enableRelatedActivityId", false}, | |
146 | {"enableAutoParent", false} | |
147 | }); | |
148 | auto tracer = tp.GetTracer(providerName); | |
149 | { | |
150 | auto aSpan = tracer->StartSpan("A.min"); | |
151 | auto aScope = tracer->WithActiveSpan(aSpan); | |
152 | { | |
153 | auto bSpan = tracer->StartSpan("B.min"); | |
154 | auto bScope = tracer->WithActiveSpan(bSpan); | |
155 | { | |
156 | auto cSpan = tracer->StartSpan("C.min"); | |
157 | auto cScope = tracer->WithActiveSpan(cSpan); | |
158 | EXPECT_NO_THROW(cSpan->End()); | |
159 | } | |
160 | EXPECT_NO_THROW(bSpan->End()); | |
161 | } | |
162 | EXPECT_NO_THROW(aSpan->End()); | |
163 | } | |
164 | tracer->CloseWithMicroseconds(0); | |
165 | } | |
166 | ||
167 | // Highest decoration level -> larger ETW event size | |
168 | // Expected output in C# listener on the other side: | |
169 | // ActivityID GUID (==SpanId), SpanId, TraceId. | |
170 | /* | |
171 | { | |
172 | "Timestamp": "2021-03-19T21:04:38.4120274-07:00", | |
173 | "ProviderName": "OpenTelemetry-ETW-TLD", | |
174 | "Id": 21, | |
175 | "Message": null, | |
176 | "ProcessId": 15120, | |
177 | "Level": "Always", | |
178 | "Keywords": "0x0000000000000000", | |
179 | "EventName": "C.max/Stop", | |
180 | "ActivityID": "d55a2c25-8033-40ab-0000-000000000000", | |
181 | "RelatedActivityID": null, | |
182 | "Payload": { | |
183 | "SpanId": "252c5ad53380ab40", | |
184 | "TraceId": "4dea2a63c188894ea5ab979e5cd7ec36" | |
185 | } | |
186 | } | |
187 | */ | |
188 | TEST(ETWTracer, TracerCheckMaxDecoration) | |
189 | { | |
190 | std::string providerName = kGlobalProviderName; | |
191 | exporter::etw::TracerProvider tp | |
192 | ({ | |
193 | {"enableTraceId", true}, | |
194 | {"enableSpanId", true}, | |
195 | {"enableActivityId", true}, | |
196 | {"enableRelatedActivityId", true}, | |
197 | {"enableAutoParent", true} | |
198 | }); | |
199 | auto tracer = tp.GetTracer(providerName); | |
200 | { | |
201 | auto aSpan = tracer->StartSpan("A.max"); | |
202 | auto aScope = tracer->WithActiveSpan(aSpan); | |
203 | { | |
204 | auto bSpan = tracer->StartSpan("B.max"); | |
205 | auto bScope = tracer->WithActiveSpan(bSpan); | |
206 | { | |
207 | auto cSpan = tracer->StartSpan("C.max"); | |
208 | auto cScope = tracer->WithActiveSpan(cSpan); | |
209 | EXPECT_NO_THROW(cSpan->End()); | |
210 | } | |
211 | EXPECT_NO_THROW(bSpan->End()); | |
212 | } | |
213 | EXPECT_NO_THROW(aSpan->End()); | |
214 | } | |
215 | tracer->CloseWithMicroseconds(0); | |
216 | } | |
217 | ||
218 | TEST(ETWTracer, TracerCheckMsgPack) | |
219 | { | |
220 | std::string providerName = "OpenTelemetry-ETW-MsgPack"; | |
221 | exporter::etw::TracerProvider tp | |
222 | ({ | |
223 | {"enableTraceId", true}, | |
224 | {"enableSpanId", true}, | |
225 | {"enableActivityId", true}, | |
226 | {"enableRelatedActivityId", true}, | |
227 | {"enableAutoParent", true} | |
228 | }); | |
229 | auto tracer = tp.GetTracer(providerName); | |
230 | { | |
231 | auto aSpan = tracer->StartSpan("A.max"); | |
232 | auto aScope = tracer->WithActiveSpan(aSpan); | |
233 | { | |
234 | auto bSpan = tracer->StartSpan("B.max"); | |
235 | auto bScope = tracer->WithActiveSpan(bSpan); | |
236 | { | |
237 | auto cSpan = tracer->StartSpan("C.max"); | |
238 | auto cScope = tracer->WithActiveSpan(cSpan); | |
239 | std::string eventName = "MyMsgPackEvent"; | |
240 | Properties event = | |
241 | { | |
242 | {"uint32Key", (uint32_t)1234}, | |
243 | {"uint64Key", (uint64_t)1234567890}, | |
244 | {"strKey", "someValue"} | |
245 | }; | |
246 | cSpan->AddEvent(eventName, event); | |
247 | EXPECT_NO_THROW(cSpan->End()); | |
248 | } | |
249 | EXPECT_NO_THROW(bSpan->End()); | |
250 | } | |
251 | EXPECT_NO_THROW(aSpan->End()); | |
252 | } | |
253 | tracer->CloseWithMicroseconds(0); | |
254 | } | |
255 | ||
256 | /** | |
257 | * @brief Global Tracer singleton may be placed in .h header and | |
258 | * shared across different compilation units. All would get the | |
259 | * same object. | |
260 | * | |
261 | * @return Single global tracer instance. | |
262 | */ | |
263 | static OPENTELEMETRY_NAMESPACE::trace::TracerProvider& GetGlobalTracerProvider() | |
264 | { | |
265 | static exporter::etw::TracerProvider tp | |
266 | ({ | |
267 | {"enableTraceId", true}, | |
268 | {"enableSpanId", true}, | |
269 | {"enableActivityId", true}, | |
270 | {"enableRelatedActivityId", true}, | |
271 | {"enableAutoParent", true} | |
272 | }); | |
273 | return tp; | |
274 | } | |
275 | ||
276 | static OPENTELEMETRY_NAMESPACE::trace::Tracer& GetGlobalTracer() | |
277 | { | |
278 | static auto tracer = GetGlobalTracerProvider().GetTracer(kGlobalProviderName); | |
279 | return (*tracer.get()); | |
280 | } | |
281 | ||
282 | TEST(ETWTracer, GlobalSingletonTracer) | |
283 | { | |
284 | // Obtain a global tracer using C++11 magic static. | |
285 | auto& globalTracer = GetGlobalTracer(); | |
286 | auto s1 = globalTracer.StartSpan("Span1"); | |
287 | auto traceId1 = s1->GetContext().trace_id(); | |
288 | s1->End(); | |
289 | /* === Span 1 - "TraceId": "182a64258fb1864ca4e1a542eecbd9bf" | |
290 | { | |
291 | "Timestamp": "2021-05-10T11:45:27.028827-07:00", | |
292 | "ProviderName": "OpenTelemetry-ETW-TLD", | |
293 | "Id": 5, | |
294 | "Message": null, | |
295 | "ProcessId": 23712, | |
296 | "Level": "Always", | |
297 | "Keywords": "0x0000000000000000", | |
298 | "EventName": "Span", | |
299 | "ActivityID": "6ed94703-6b0a-4e76-0000-000000000000", | |
300 | "RelatedActivityID": null, | |
301 | "Payload": { | |
302 | "Duration": 0, | |
303 | "Kind": 1, | |
304 | "Name": "Span1", | |
305 | "SpanId": "0347d96e0a6b764e", | |
306 | "StartTime": "2021-05-10T18:45:27.028000Z", | |
307 | "StatusCode": 0, | |
308 | "StatusMessage": "", | |
309 | "Success": "True", | |
310 | "TraceId": "182a64258fb1864ca4e1a542eecbd9bf", | |
311 | "_name": "Span" | |
312 | } | |
313 | } | |
314 | */ | |
315 | ||
316 | // Obtain a different tracer withs its own trace-id. | |
317 | auto localTracer = GetGlobalTracerProvider().GetTracer(kGlobalProviderName); | |
318 | auto s2 = localTracer->StartSpan("Span2"); | |
319 | auto traceId2 = s2->GetContext().trace_id(); | |
320 | s2->End(); | |
321 | /* === Span 2 - "TraceId": "334bf9a1eed98d40a873a606295a9368" | |
322 | { | |
323 | "Timestamp": "2021-05-10T11:45:27.0289654-07:00", | |
324 | "ProviderName": "OpenTelemetry-ETW-TLD", | |
325 | "Id": 5, | |
326 | "Message": null, | |
327 | "ProcessId": 23712, | |
328 | "Level": "Always", | |
329 | "Keywords": "0x0000000000000000", | |
330 | "EventName": "Span", | |
331 | "ActivityID": "3b7b2ecb-2e84-4903-0000-000000000000", | |
332 | "RelatedActivityID": null, | |
333 | "Payload": { | |
334 | "Duration": 0, | |
335 | "Kind": 1, | |
336 | "Name": "Span2", | |
337 | "SpanId": "cb2e7b3b842e0349", | |
338 | "StartTime": "2021-05-10T18:45:27.028000Z", | |
339 | "StatusCode": 0, | |
340 | "StatusMessage": "", | |
341 | "Success": "True", | |
342 | "TraceId": "334bf9a1eed98d40a873a606295a9368", | |
343 | "_name": "Span" | |
344 | } | |
345 | } | |
346 | */ | |
347 | ||
348 | // Obtain the same global tracer with the same trace-id as before. | |
349 | auto& globalTracer2 = GetGlobalTracer(); | |
350 | auto s3 = globalTracer2.StartSpan("Span3"); | |
351 | auto traceId3 = s3->GetContext().trace_id(); | |
352 | s3->End(); | |
353 | /* === Span 3 - "TraceId": "182a64258fb1864ca4e1a542eecbd9bf" | |
354 | { | |
355 | "Timestamp": "2021-05-10T11:45:27.0290936-07:00", | |
356 | "ProviderName": "OpenTelemetry-ETW-TLD", | |
357 | "Id": 5, | |
358 | "Message": null, | |
359 | "ProcessId": 23712, | |
360 | "Level": "Always", | |
361 | "Keywords": "0x0000000000000000", | |
362 | "EventName": "Span", | |
363 | "ActivityID": "0a970247-ba0e-4d4b-0000-000000000000", | |
364 | "RelatedActivityID": null, | |
365 | "Payload": { | |
366 | "Duration": 1, | |
367 | "Kind": 1, | |
368 | "Name": "Span3", | |
369 | "SpanId": "4702970a0eba4b4d", | |
370 | "StartTime": "2021-05-10T18:45:27.028000Z", | |
371 | "StatusCode": 0, | |
372 | "StatusMessage": "", | |
373 | "Success": "True", | |
374 | "TraceId": "182a64258fb1864ca4e1a542eecbd9bf", | |
375 | "_name": "Span" | |
376 | } | |
377 | } | |
378 | */ | |
379 | EXPECT_NE(traceId1, traceId2); | |
380 | EXPECT_EQ(traceId1, traceId3); | |
381 | ||
382 | localTracer->CloseWithMicroseconds(0); | |
383 | globalTracer.CloseWithMicroseconds(0); | |
384 | } | |
385 | ||
386 | /* clang-format on */ | |
387 | ||
388 | #endif |