Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ETW Exporter]Support serialize span/log attributes into JSON #1991

Merged
merged 9 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
lalitb marked this conversation as resolved.
Show resolved Hide resolved
{
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)
lalitb marked this conversation as resolved.
Show resolved Hide resolved

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