Skip to content

Commit 021eb99

Browse files
authored
[ETW] Add configuration to export 64-bit integer as timestamp (open-telemetry#3286)
1 parent 3212b0f commit 021eb99

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

exporters/etw/include/opentelemetry/exporters/etw/etw_config.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#pragma once
55
#include <map>
66

7+
#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
8+
# include <set>
9+
#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
10+
711
#include "opentelemetry/nostd/shared_ptr.h"
812
#include "opentelemetry/nostd/string_view.h"
913
#include "opentelemetry/nostd/unique_ptr.h"
@@ -23,10 +27,23 @@ namespace etw
2327
/**
2428
* @brief TelemetryProvider Options passed via SDK API.
2529
*/
30+
31+
#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
32+
using TelemetryProviderOptions = std::map<std::string,
33+
nostd::variant<std::string,
34+
uint64_t,
35+
float,
36+
bool,
37+
std::map<std::string, std::string>,
38+
std::set<std::string>>>;
39+
40+
#else
2641
using TelemetryProviderOptions = std::map<
2742
std::string,
2843
nostd::variant<std::string, uint64_t, float, bool, std::map<std::string, std::string>>>;
2944

45+
#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
46+
3047
/**
3148
* @brief TelemetryProvider runtime configuration class. Internal representation
3249
* of TelemetryProviderOptions used by various components of SDK.
@@ -45,6 +62,13 @@ typedef struct
4562
bool enableTableNameMappings; // Map instrumentation scope name to table name with
4663
// `tableNameMappings`
4764
std::map<std::string, std::string> tableNameMappings;
65+
66+
#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
67+
68+
std::set<std::string> timestampAttributes; // Attributes to use as timestamp
69+
70+
#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
71+
4872
} TelemetryProviderConfiguration;
4973

5074
/**

exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,35 @@ class Logger : public opentelemetry::logs::Logger
323323
}
324324
evt[ETW_FIELD_LOG_SEVERITY_NUM] = static_cast<uint32_t>(severity);
325325
evt[ETW_FIELD_LOG_BODY] = std::string(body.data(), body.length());
326+
327+
#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
328+
329+
for (const auto &attr : cfg.timestampAttributes)
330+
{
331+
auto it = evt.find(attr);
332+
if (it != evt.end())
333+
{
334+
auto value_index = it->second.index();
335+
if (value_index != exporter_etw::PropertyType::kTypeInt64 &&
336+
value_index != exporter_etw::PropertyType::kTypeUInt64)
337+
{
338+
continue;
339+
}
340+
int64_t filetime = value_index == exporter_etw::PropertyType::kTypeUInt64
341+
? nostd::get<uint64_t>(it->second)
342+
: nostd::get<int64_t>(it->second);
343+
constexpr int64_t FILETIME_EPOCH_DIFF = 11644473600LL; // Seconds from 1601 to 1970
344+
constexpr int64_t HUNDRED_NANOSECONDS_PER_SECOND = 10000000LL;
345+
int64_t unix_time_seconds =
346+
(filetime / HUNDRED_NANOSECONDS_PER_SECOND) - FILETIME_EPOCH_DIFF;
347+
int64_t unix_time_nanos =
348+
unix_time_seconds * 1'000'000'000 + (filetime % HUNDRED_NANOSECONDS_PER_SECOND) * 100;
349+
it->second = utils::formatUtcTimestampNsAsISO8601(unix_time_nanos);
350+
}
351+
}
352+
353+
#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
354+
326355
etwProvider().write(provHandle, evt, nullptr, nullptr, 0, encoding);
327356
}
328357

@@ -354,6 +383,12 @@ class LoggerProvider : public opentelemetry::logs::LoggerProvider
354383
GetOption(options, "enableTableNameMappings", config_.enableTableNameMappings, false);
355384
GetOption(options, "tableNameMappings", config_.tableNameMappings, {});
356385

386+
#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
387+
388+
GetOption(options, "timestampAttributes", config_.timestampAttributes, {});
389+
390+
#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW)
391+
357392
// Determines what encoding to use for ETW events: TraceLogging Dynamic, MsgPack, XML, etc.
358393
config_.encoding = GetEncoding(options);
359394
}

exporters/etw/test/etw_logger_test.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55

66
# include <gtest/gtest.h>
77
# include <map>
8+
# include <set>
89
# include <string>
910

11+
# define OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW
12+
1013
# include "opentelemetry/exporters/etw/etw_logger_exporter.h"
1114
# include "opentelemetry/sdk/trace/simple_processor.h"
1215

@@ -146,4 +149,50 @@ TEST(ETWLogger, LoggerCheckWithTableNameMappings)
146149
logger->Debug("This is a debug log body", opentelemetry::common::MakeAttributes(attribs)));
147150
}
148151

152+
/**
153+
* @brief Logger Test with structured attributes
154+
*
155+
* Example Event for below test:
156+
* {
157+
* "Timestamp": "2024-06-02T15:04:15.4227815-07:00",
158+
* "ProviderName": "OpenTelemetry-ETW-TLD",
159+
* "Id": 1,
160+
* "Message": null,
161+
* "ProcessId": 37696,
162+
* "Level": "Always",
163+
* "Keywords": "0x0000000000000000",
164+
* "EventName": "table1",
165+
* "ActivityID": null,
166+
* "RelatedActivityID": null,
167+
* "Payload": {
168+
* "SpanId": "0000000000000000",
169+
* "Timestamp": "2021-09-30T22:04:15.066411500Z",
170+
* "TraceId": "00000000000000000000000000000000",
171+
* "_name": "table1",
172+
* "tiemstamp1": "2025-02-20T19:18:11.048166700Z",
173+
* "attrib2": "value2",
174+
* "body": "This is a debug log body",
175+
* "severityNumber": 5,
176+
* "severityText": "DEBUG"
177+
* }
178+
* }
179+
*
180+
*/
181+
182+
TEST(ETWLogger, LoggerCheckWithTimestampAttributes)
183+
{
184+
std::string providerName = kGlobalProviderName; // supply unique instrumentation name here
185+
std::set<std::string> timestampAttributes = {{"timestamp1"}};
186+
exporter::etw::TelemetryProviderOptions options = {{"timestampAttributes", timestampAttributes}};
187+
exporter::etw::LoggerProvider lp{options};
188+
189+
auto logger = lp.GetLogger(providerName, "name1");
190+
191+
// Log attributes
192+
Properties attribs = {{"timestamp1", 133845526910481667ULL}, {"attrib2", "value2"}};
193+
194+
EXPECT_NO_THROW(
195+
logger->Debug("This is a debug log body", opentelemetry::common::MakeAttributes(attribs)));
196+
}
197+
149198
#endif // _WIN32

0 commit comments

Comments
 (0)