From 71e32407c896423e06f06fdeec26543bc307d34d Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Thu, 20 Feb 2025 11:21:44 -0800 Subject: [PATCH 1/3] [ETW] Add configuration to export 64-bit integer as timestamp --- .../opentelemetry/exporters/etw/etw_config.h | 20 ++++++++ .../opentelemetry/exporters/etw/etw_logger.h | 33 +++++++++++++ exporters/etw/test/etw_logger_test.cc | 49 +++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h index d343589699..cef0d4357c 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h @@ -4,6 +4,10 @@ #pragma once #include +#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) +#include +#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" @@ -23,10 +27,19 @@ namespace etw /** * @brief TelemetryProvider Options passed via SDK API. */ + +#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) +using TelemetryProviderOptions = std::map< + std::string, + nostd::variant, std::set>>; + +#else using TelemetryProviderOptions = std::map< std::string, nostd::variant>>; +#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + /** * @brief TelemetryProvider runtime configuration class. Internal representation * of TelemetryProviderOptions used by various components of SDK. @@ -45,6 +58,13 @@ typedef struct bool enableTableNameMappings; // Map instrumentation scope name to table name with // `tableNameMappings` std::map tableNameMappings; + +#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + + std::set timestampAttributes; // Attributes to use as timestamp + +#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + } TelemetryProviderConfiguration; /** diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h index c464d572d5..1455e96f97 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h @@ -323,6 +323,33 @@ class Logger : public opentelemetry::logs::Logger } evt[ETW_FIELD_LOG_SEVERITY_NUM] = static_cast(severity); evt[ETW_FIELD_LOG_BODY] = std::string(body.data(), body.length()); + +#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + + for (const auto &attr : cfg.timestampAttributes) + { + auto it = evt.find(attr); + if (it != evt.end()) + { + auto value_index = it->second.index(); + if (value_index != exporter_etw::PropertyType::kTypeInt64 && + value_index != exporter_etw::PropertyType::kTypeUInt64) + { + continue; + } + int64_t filetime = value_index == exporter_etw::PropertyType::kTypeUInt64 + ? nostd::get(it->second) + : nostd::get(it->second); + constexpr int64_t FILETIME_EPOCH_DIFF = 11644473600LL; // Seconds from 1601 to 1970 + constexpr int64_t HUNDRED_NANOSECONDS_PER_SECOND = 10000000LL; + int64_t unix_time_seconds = (filetime / HUNDRED_NANOSECONDS_PER_SECOND) - FILETIME_EPOCH_DIFF; + int64_t unix_time_nanos = unix_time_seconds * 1'000'000'000 + (filetime % HUNDRED_NANOSECONDS_PER_SECOND) * 100; + it->second = utils::formatUtcTimestampNsAsISO8601(unix_time_nanos); + } + } + +#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + etwProvider().write(provHandle, evt, nullptr, nullptr, 0, encoding); } @@ -354,6 +381,12 @@ class LoggerProvider : public opentelemetry::logs::LoggerProvider GetOption(options, "enableTableNameMappings", config_.enableTableNameMappings, false); GetOption(options, "tableNameMappings", config_.tableNameMappings, {}); +#if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + + GetOption(options, "timestampAttributes", config_.timestampAttributes, {}); + +#endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) + // Determines what encoding to use for ETW events: TraceLogging Dynamic, MsgPack, XML, etc. config_.encoding = GetEncoding(options); } diff --git a/exporters/etw/test/etw_logger_test.cc b/exporters/etw/test/etw_logger_test.cc index c64769d6ee..59427de40e 100644 --- a/exporters/etw/test/etw_logger_test.cc +++ b/exporters/etw/test/etw_logger_test.cc @@ -5,8 +5,11 @@ # include # include +# include # include +# define OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW + # include "opentelemetry/exporters/etw/etw_logger_exporter.h" # include "opentelemetry/sdk/trace/simple_processor.h" @@ -146,4 +149,50 @@ TEST(ETWLogger, LoggerCheckWithTableNameMappings) logger->Debug("This is a debug log body", opentelemetry::common::MakeAttributes(attribs))); } +/** + * @brief Logger Test with structured attributes + * + * Example Event for below test: + * { + * "Timestamp": "2024-06-02T15:04:15.4227815-07:00", + * "ProviderName": "OpenTelemetry-ETW-TLD", + * "Id": 1, + * "Message": null, + * "ProcessId": 37696, + * "Level": "Always", + * "Keywords": "0x0000000000000000", + * "EventName": "table1", + * "ActivityID": null, + * "RelatedActivityID": null, + * "Payload": { + * "SpanId": "0000000000000000", + * "Timestamp": "2021-09-30T22:04:15.066411500Z", + * "TraceId": "00000000000000000000000000000000", + * "_name": "table1", + * "attrib1": 1, + * "attrib2": "value2", + * "body": "This is a debug log body", + * "severityNumber": 5, + * "severityText": "DEBUG" + * } + * } + * + */ + +TEST(ETWLogger, LoggerCheckWithTimestampAttributes) +{ + std::string providerName = kGlobalProviderName; // supply unique instrumentation name here + std::set timestampAttributes = {{"attrib1"}}; + exporter::etw::TelemetryProviderOptions options = {{"timestampAttributes", timestampAttributes}}; + exporter::etw::LoggerProvider lp{options}; + + auto logger = lp.GetLogger(providerName, "name1"); + + // Log attributes + Properties attribs = {{"attrib1", 133845526910481667ULL}, {"attrib2", "value2"}}; + + EXPECT_NO_THROW( + logger->Debug("This is a debug log body", opentelemetry::common::MakeAttributes(attribs))); +} + #endif // _WIN32 From 9b679ee9a04866cfa9327f140d418d8dc9aab8c7 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Fri, 21 Feb 2025 13:33:45 -0800 Subject: [PATCH 2/3] Fix test value --- exporters/etw/test/etw_logger_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exporters/etw/test/etw_logger_test.cc b/exporters/etw/test/etw_logger_test.cc index 59427de40e..d11deb29fd 100644 --- a/exporters/etw/test/etw_logger_test.cc +++ b/exporters/etw/test/etw_logger_test.cc @@ -169,7 +169,7 @@ TEST(ETWLogger, LoggerCheckWithTableNameMappings) * "Timestamp": "2021-09-30T22:04:15.066411500Z", * "TraceId": "00000000000000000000000000000000", * "_name": "table1", - * "attrib1": 1, + * "tiemstamp1": "2025-02-20T19:18:11.048166700Z", * "attrib2": "value2", * "body": "This is a debug log body", * "severityNumber": 5, @@ -182,14 +182,14 @@ TEST(ETWLogger, LoggerCheckWithTableNameMappings) TEST(ETWLogger, LoggerCheckWithTimestampAttributes) { std::string providerName = kGlobalProviderName; // supply unique instrumentation name here - std::set timestampAttributes = {{"attrib1"}}; + std::set timestampAttributes = {{"timestamp1"}}; exporter::etw::TelemetryProviderOptions options = {{"timestampAttributes", timestampAttributes}}; exporter::etw::LoggerProvider lp{options}; auto logger = lp.GetLogger(providerName, "name1"); // Log attributes - Properties attribs = {{"attrib1", 133845526910481667ULL}, {"attrib2", "value2"}}; + Properties attribs = {{"timestamp1", 133845526910481667ULL}, {"attrib2", "value2"}}; EXPECT_NO_THROW( logger->Debug("This is a debug log body", opentelemetry::common::MakeAttributes(attribs))); From 70d036642ebc7d7dd2fa0ddd9b2a2a4fec8cd002 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Fri, 21 Feb 2025 17:06:17 -0800 Subject: [PATCH 3/3] Format --- .../include/opentelemetry/exporters/etw/etw_config.h | 12 ++++++++---- .../include/opentelemetry/exporters/etw/etw_logger.h | 12 +++++++----- exporters/etw/test/etw_logger_test.cc | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h index cef0d4357c..29e411ce61 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_config.h @@ -5,7 +5,7 @@ #include #if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) -#include +# include #endif // defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) #include "opentelemetry/nostd/shared_ptr.h" @@ -29,9 +29,13 @@ namespace etw */ #if defined(OPENTELEMETRY_ATTRIBUTE_TIMESTAMP_PREVIEW) -using TelemetryProviderOptions = std::map< - std::string, - nostd::variant, std::set>>; +using TelemetryProviderOptions = std::map, + std::set>>; #else using TelemetryProviderOptions = std::map< diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h index 1455e96f97..d0aff9324a 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h @@ -338,12 +338,14 @@ class Logger : public opentelemetry::logs::Logger continue; } int64_t filetime = value_index == exporter_etw::PropertyType::kTypeUInt64 - ? nostd::get(it->second) - : nostd::get(it->second); - constexpr int64_t FILETIME_EPOCH_DIFF = 11644473600LL; // Seconds from 1601 to 1970 + ? nostd::get(it->second) + : nostd::get(it->second); + constexpr int64_t FILETIME_EPOCH_DIFF = 11644473600LL; // Seconds from 1601 to 1970 constexpr int64_t HUNDRED_NANOSECONDS_PER_SECOND = 10000000LL; - int64_t unix_time_seconds = (filetime / HUNDRED_NANOSECONDS_PER_SECOND) - FILETIME_EPOCH_DIFF; - int64_t unix_time_nanos = unix_time_seconds * 1'000'000'000 + (filetime % HUNDRED_NANOSECONDS_PER_SECOND) * 100; + int64_t unix_time_seconds = + (filetime / HUNDRED_NANOSECONDS_PER_SECOND) - FILETIME_EPOCH_DIFF; + int64_t unix_time_nanos = + unix_time_seconds * 1'000'000'000 + (filetime % HUNDRED_NANOSECONDS_PER_SECOND) * 100; it->second = utils::formatUtcTimestampNsAsISO8601(unix_time_nanos); } } diff --git a/exporters/etw/test/etw_logger_test.cc b/exporters/etw/test/etw_logger_test.cc index d11deb29fd..f901d784b3 100644 --- a/exporters/etw/test/etw_logger_test.cc +++ b/exporters/etw/test/etw_logger_test.cc @@ -182,7 +182,7 @@ TEST(ETWLogger, LoggerCheckWithTableNameMappings) TEST(ETWLogger, LoggerCheckWithTimestampAttributes) { std::string providerName = kGlobalProviderName; // supply unique instrumentation name here - std::set timestampAttributes = {{"timestamp1"}}; + std::set timestampAttributes = {{"timestamp1"}}; exporter::etw::TelemetryProviderOptions options = {{"timestampAttributes", timestampAttributes}}; exporter::etw::LoggerProvider lp{options};