Skip to content

Commit

Permalink
[ETW Exporter]Support serialize span/log attributes into JSON (#1991)
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomsonTan authored Feb 22, 2023
1 parent eed6572 commit 5c121cf
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Increment the:

## [Unreleased]

* [ETW Exporter]Support serialize span/log attributes into JSON
[#1991](https://github.com/open-telemetry/opentelemetry-cpp/pull/1991)
* ETW Exporter]Do not overwrite ParentId when setting attribute on Span
[#1989](https://github.com/open-telemetry/opentelemetry-cpp/pull/1989)
* Convert Prometheus Exporter to Pull MetricReader [#1953](https://github.com/open-telemetry/opentelemetry-cpp/pull/1953)
Expand Down
22 changes: 22 additions & 0 deletions exporters/etw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ if(BUILD_TESTING)
add_executable(etw_provider_test test/etw_provider_test.cc)
add_executable(etw_tracer_test test/etw_tracer_test.cc)
add_executable(etw_logger_test test/etw_logger_test.cc)
add_executable(etw_tracer_test_enable_env_properties test/etw_tracer_test.cc)
add_executable(etw_logger_test_enable_env_properties test/etw_logger_test.cc)

target_link_libraries(etw_provider_test ${GTEST_BOTH_LIBRARIES}
opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT})
Expand All @@ -44,6 +46,18 @@ if(BUILD_TESTING)
target_link_libraries(etw_logger_test ${GTEST_BOTH_LIBRARIES}
opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT})

target_link_libraries(
etw_tracer_test_enable_env_properties ${GTEST_BOTH_LIBRARIES}
opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT})
target_compile_definitions(etw_tracer_test_enable_env_properties
PRIVATE ENABLE_ENV_PROPERTIES)

target_link_libraries(
etw_logger_test_enable_env_properties ${GTEST_BOTH_LIBRARIES}
opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT})
target_compile_definitions(etw_logger_test_enable_env_properties
PRIVATE ENABLE_ENV_PROPERTIES)

if(WITH_BENCHMARK)
add_executable(etw_perf_test test/etw_perf_test.cc)
target_link_libraries(
Expand All @@ -63,5 +77,13 @@ if(BUILD_TESTING)
TARGET etw_logger_test
TEST_PREFIX exporter.
TEST_LIST etw_logger_test)
gtest_add_tests(
TARGET etw_tracer_test_enable_env_properties
TEST_PREFIX exporter.with_env_properties.
TEST_LIST etw_tracer_test_enable_env_properties)
gtest_add_tests(
TARGET etw_logger_test_enable_env_properties
TEST_PREFIX exporter.with_env_properties.
TEST_LIST etw_logger_test_enable_env_properties)

endif() # BUILD_TESTING
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,13 @@
# define ETW_VALUE_SPAN_END "SpanEnd" /* ETW for Span Start */


# define ETW_FIELD_ENV_PROPERTIES "env_properties" /* ETW event_properties with JSON string */

/* Log specific */
# define ETW_FIELD_LOG_BODY "body" /* Log body */
# define ETW_FIELD_LOG_SEVERITY_TEXT "severityText" /* Sev text */
# define ETW_FIELD_LOG_SEVERITY_NUM "severityNumber" /* Sev num */


#endif

/* clang-format on */
39 changes: 38 additions & 1 deletion exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,49 @@ class Logger : public opentelemetry::logs::Logger
virtual void Log(opentelemetry::logs::Severity severity,
nostd::string_view name,
nostd::string_view body,
Properties &evt,
Properties &input_evt,
opentelemetry::trace::TraceId trace_id,
opentelemetry::trace::SpanId span_id,
opentelemetry::trace::TraceFlags trace_flags,
common::SystemTimestamp timestamp) noexcept
{
# if defined(ENABLE_ENV_PROPERTIES)

Properties env_properties_env = {};
bool has_customer_attribute = false;
if (input_evt.size() > 0)
{
nlohmann::json env_properties_json = nlohmann::json::object();
for (auto &kv : input_evt)
{
nostd::string_view key = kv.first.data();

// don't serialize fields propagated from span data.
if (key == ETW_FIELD_NAME || key == ETW_FIELD_SPAN_ID || key == ETW_FIELD_TRACE_ID ||
key == ETW_FIELD_SPAN_PARENTID)
{
env_properties_env[key.data()] = kv.second;
}
else
{
utils::PopulateAttribute(env_properties_json, key, kv.second);
has_customer_attribute = true;
}
}
if (has_customer_attribute)
{
env_properties_env[ETW_FIELD_ENV_PROPERTIES] = env_properties_json.dump();
}
}

Properties &evt = has_customer_attribute ? env_properties_env : input_evt;

# else

Properties &evt = input_evt;

# endif // defined(ENABLE_ENV_PROPERTIES)

// Populate Etw.EventName attribute at envelope level
evt[ETW_FIELD_NAME] = ETW_VALUE_LOG;

Expand Down
37 changes: 35 additions & 2 deletions exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,41 @@ class Tracer : public opentelemetry::trace::Tracer,
auto spanContext = spanBase.GetContext();

// Populate Span with presaved attributes
Span &currentSpan = const_cast<Span &>(span);
Properties evt = GetSpanAttributes(currentSpan);
Span &currentSpan = const_cast<Span &>(span);
Properties evt = GetSpanAttributes(currentSpan);

#if defined(ENABLE_ENV_PROPERTIES)

Properties env_properties_env = {};
if (evt.size() > 0)
{
bool has_customer_attribute = false;
nlohmann::json env_properties_json = nlohmann::json::object();
for (auto &kv : evt)
{
nostd::string_view key = kv.first.data();

// don't serialize fields propagated from span data.
if (key == ETW_FIELD_NAME || key == ETW_FIELD_SPAN_ID || key == ETW_FIELD_TRACE_ID ||
key == ETW_FIELD_SPAN_PARENTID)
{
env_properties_env[key.data()] = kv.second;
}
else
{
utils::PopulateAttribute(env_properties_json, key, kv.second);
has_customer_attribute = true;
}
}
if (has_customer_attribute)
{
env_properties_env[ETW_FIELD_ENV_PROPERTIES] = env_properties_json.dump();
evt = std::move(env_properties_env);
}
}

#endif // defined(ENABLE_ENV_PROPERTIES)

evt[ETW_FIELD_NAME] = GetName(span);

if (cfg.enableSpanId)
Expand Down
113 changes: 113 additions & 0 deletions exporters/etw/include/opentelemetry/exporters/etw/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
# include <codecvt>
#endif

#if defined(ENABLE_ENV_PROPERTIES)

# include <nlohmann/json.hpp>
# include "etw_properties.h"

#endif

OPENTELEMETRY_BEGIN_NAMESPACE

namespace utils
Expand Down Expand Up @@ -270,6 +277,112 @@ static inline std::string formatUtcTimestampNsAsISO8601(int64_t timestampNs)
return buf;
}

#if defined(ENABLE_ENV_PROPERTIES)

static inline void PopulateAttribute(nlohmann::json &attribute,
nostd::string_view key,
const exporter::etw::PropertyValue &value)
{
if (nostd::holds_alternative<bool>(value))
{
attribute[key.data()] = nostd::get<bool>(value);
}
else if (nostd::holds_alternative<int>(value))
{
attribute[key.data()] = nostd::get<int>(value);
}
else if (nostd::holds_alternative<int64_t>(value))
{
attribute[key.data()] = nostd::get<int64_t>(value);
}
else if (nostd::holds_alternative<unsigned int>(value))
{
attribute[key.data()] = nostd::get<unsigned int>(value);
}
else if (nostd::holds_alternative<uint64_t>(value))
{
attribute[key.data()] = nostd::get<uint64_t>(value);
}
else if (nostd::holds_alternative<double>(value))
{
attribute[key.data()] = nostd::get<double>(value);
}
else if (nostd::holds_alternative<const char *>(value))
{
attribute[key.data()] = std::string(nostd::get<const char *>(value));
}
else if (nostd::holds_alternative<std::string>(value))
{
attribute[key.data()] = nostd::get<std::string>(value);
}
else if (nostd::holds_alternative<std::vector<uint8_t>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<uint8_t>>(value))
{
attribute[key.data()].push_back(val);
}
}
else if (nostd::holds_alternative<std::vector<bool>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<bool>>(value))
{
attribute[key.data()].push_back(val);
}
}
else if (nostd::holds_alternative<std::vector<int>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<int>>(value))
{
attribute[key.data()].push_back(val);
}
}
else if (nostd::holds_alternative<std::vector<int64_t>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<int64_t>>(value))
{
attribute[key.data()].push_back(val);
}
}
else if (nostd::holds_alternative<std::vector<unsigned int>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<unsigned int>>(value))
{
attribute[key.data()].push_back(val);
}
}
else if (nostd::holds_alternative<std::vector<uint64_t>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<uint64_t>>(value))
{
attribute[key.data()].push_back(val);
}
}
else if (nostd::holds_alternative<std::vector<double>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<double>>(value))
{
attribute[key.data()].push_back(val);
}
}
else if (nostd::holds_alternative<std::vector<std::string>>(value))
{
attribute[key.data()] = {};
for (const auto &val : nostd::get<std::vector<std::string>>(value))
{
attribute[key.data()].push_back(val);
}
}
}

#endif // defined(ENABLE_ENV_PROPERTIES)

}; // namespace utils

OPENTELEMETRY_END_NAMESPACE
9 changes: 6 additions & 3 deletions exporters/etw/test/etw_tracer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,22 +117,25 @@ TEST(ETWTracer, TracerCheck)
auto tracer = tp.GetTracer(providerName);

// Span attributes
Properties attribs =
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", attribs);
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", attribs);
auto innerSpan = tracer->StartSpan("MySpanL3", inner_attribs);
auto innerScope = tracer->WithActiveSpan(innerSpan);

// Add span attribute
Expand Down

0 comments on commit 5c121cf

Please sign in to comment.