From 1af25dcfebf34240cca67689dabf765f81b0082e Mon Sep 17 00:00:00 2001 From: mishal23 Date: Sat, 14 Nov 2020 18:35:48 +0530 Subject: [PATCH 01/20] [Issue #326] ETW Tracer Exporter The initial files with the dummy classes added for ETW Exporter as per the specification. Updated the code to use span links which was recently introduced in the repository. Added StartSpan method and export function with tracerprovider. --- CMakeLists.txt | 4 + .../opentelemetry/trace/span_context.h | 4 + api/include/opentelemetry/trace/tracer.h | 6 + exporters/CMakeLists.txt | 4 + exporters/etw/BUILD | 54 ++ exporters/etw/CMakeLists.txt | 22 + .../exporters/etw/etw_provider_exporter.h | 644 ++++++++++++++++++ .../exporters/etw/etw_tracer_exporter.h | 469 +++++++++++++ .../opentelemetry/exporters/etw/utils.h | 209 ++++++ .../opentelemetry/exporters/etw/uuid.hpp | 423 ++++++++++++ exporters/etw/src/etw_provider_exporter.cc | 3 + exporters/etw/src/etw_tracer_exporter.cc | 3 + exporters/etw/test/etw_provider_test.cc | 71 ++ exporters/etw/test/etw_tracer_test.cc | 41 ++ 14 files changed, 1957 insertions(+) create mode 100644 exporters/etw/BUILD create mode 100644 exporters/etw/CMakeLists.txt create mode 100644 exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h create mode 100644 exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h create mode 100644 exporters/etw/include/opentelemetry/exporters/etw/utils.h create mode 100644 exporters/etw/include/opentelemetry/exporters/etw/uuid.hpp create mode 100644 exporters/etw/src/etw_provider_exporter.cc create mode 100644 exporters/etw/src/etw_tracer_exporter.cc create mode 100644 exporters/etw/test/etw_provider_test.cc create mode 100644 exporters/etw/test/etw_tracer_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index afd4dafc66..be8e6acf96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,10 @@ option(WITH_ELASTICSEARCH "Whether to include the Elasticsearch Client in the SDK" OFF) option(BUILD_TESTING "Whether to enable tests" ON) +if(WIN32) + option(WITH_ETW_EXPORTER "Whether to include the ETW Exporter in the SDK" ON) +endif(WIN32) + option(WITH_EXAMPLES "Whether to build examples" ON) find_package(Threads) diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h index 6add265eed..6cf125bb15 100644 --- a/api/include/opentelemetry/trace/span_context.h +++ b/api/include/opentelemetry/trace/span_context.h @@ -33,6 +33,10 @@ namespace trace_api = opentelemetry::trace; class SpanContext final { public: + // An invalid SpanContext. + SpanContext() noexcept + : trace_flags_(trace::TraceFlags((uint8_t) false)), remote_parent_(false){}; + /* A temporary constructor for an invalid SpanContext. * Trace id and span id are set to invalid (all zeros). * diff --git a/api/include/opentelemetry/trace/tracer.h b/api/include/opentelemetry/trace/tracer.h index 09cf389d8b..e6a252f4a5 100644 --- a/api/include/opentelemetry/trace/tracer.h +++ b/api/include/opentelemetry/trace/tracer.h @@ -179,6 +179,12 @@ class Tracer static_cast(std::chrono::duration_cast(timeout))); } + void Close() noexcept + { + /* TODO: respect timeout from TracerOptions? */ + CloseWithMicroseconds(0); + } + virtual void CloseWithMicroseconds(uint64_t timeout) noexcept = 0; }; } // namespace trace diff --git a/exporters/CMakeLists.txt b/exporters/CMakeLists.txt index 68ea177c38..9141686ab1 100644 --- a/exporters/CMakeLists.txt +++ b/exporters/CMakeLists.txt @@ -12,3 +12,7 @@ endif() if(WITH_ELASTICSEARCH) add_subdirectory(elasticsearch) endif() + +if(WITH_ETW_EXPORTER) + add_subdirectory(etw) +endif() diff --git a/exporters/etw/BUILD b/exporters/etw/BUILD new file mode 100644 index 0000000000..0d86bc1e45 --- /dev/null +++ b/exporters/etw/BUILD @@ -0,0 +1,54 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "etw_provider_exporter", + srcs = [ + "src/etw_provider_exporter.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/etw/etw_provider_exporter.h", + "include/opentelemetry/exporters/etw/utils.h", + "include/opentelemetry/exporters/etw/uuid.hpp", + ], + strip_include_prefix = "include", + deps = [ + "//api", + "//sdk/src/trace", + ], +) + +cc_test( + name = "etw_provider_test", + srcs = ["test/etw_provider_test.cc"], + deps = [ + ":etw_provider_exporter", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "etw_tracer_exporter", + srcs = [ + "src/etw_tracer_exporter.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/etw/etw_tracer_exporter.h", + "include/opentelemetry/exporters/etw/utils.h", + "include/opentelemetry/exporters/etw/uuid.hpp", + ], + strip_include_prefix = "include", + deps = [ + ":etw_provider_exporter", + "//api", + "//sdk/src/trace", + ], +) + +cc_test( + name = "etw_tracer_test", + srcs = ["test/etw_tracer_test.cc"], + deps = [ + ":etw_tracer_exporter", + "@com_google_googletest//:gtest_main", + ], +) \ No newline at end of file diff --git a/exporters/etw/CMakeLists.txt b/exporters/etw/CMakeLists.txt new file mode 100644 index 0000000000..8432f06131 --- /dev/null +++ b/exporters/etw/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories(include) + +add_library(opentelemetry_exporter_etw_provider src/etw_provider_exporter.cc) +add_library(opentelemetry_exporter_etw_tracer src/etw_tracer_exporter.cc) + +if(BUILD_TESTING) + add_executable(etw_provider_test test/etw_provider_test.cc) + add_executable(etw_tracer_test test/etw_tracer_test.cc) + + target_link_libraries( + etw_provider_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_etw_provider) + + target_link_libraries( + etw_tracer_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_etw_tracer) + + gtest_add_tests(TARGET etw_provider_test TEST_PREFIX exporter. TEST_LIST + etw_provider_test) + gtest_add_tests(TARGET etw_tracer_test TEST_PREFIX exporter. TEST_LIST + etw_tracer_test) +endif() # BUILD_TESTING diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h new file mode 100644 index 0000000000..3bd517946d --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -0,0 +1,644 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef _MSC_VER +// evntprov.h(838) : warning C4459 : declaration of 'Version' hides global declaration +# pragma warning(disable : 4459) +// needed for Unit Testing with krabs.hpp +# pragma warning(disable : 4018) +#endif + +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/exporters/etw/uuid.hpp" +#include "opentelemetry/version.h" + +#include "opentelemetry/exporters/etw/utils.h" + +#ifdef HAVE_MSGPACK +// This option requires INCLUDE_DIR=$(ProjectDir)\..\..\third_party\json\include;... +# include "nlohmann/json.hpp" +#endif + +#ifndef HAVE_NO_TLD +// Allow to opt-out from `TraceLoggingDynamic.h` header usage +# define HAVE_TLD +# include "TraceLoggingDynamic.h" +#endif + +#include +#include +#include +#include + +#ifdef HAVE_KRABS_TESTS +// krabs.hpp requires this definition of min macro from Windows.h +# ifndef min +# define min(a, b) (((a) < (b)) ? (a) : (b)) +# endif +#endif + +#define MICROSOFT_EVENTTAG_NORMAL_PERSISTENCE 0x01000000 + +OPENTELEMETRY_BEGIN_NAMESPACE + +class ETWProvider +{ + +public: + const unsigned long STATUS_OK = 0; + const unsigned long STATUS_ERROR = ULONG_MAX; + const unsigned long STATUS_EFBIG = ULONG_MAX - 1; + + enum EventFormat + { + ETW_MANIFEST = 0, + ETW_MSGPACK = 1, + ETW_XML = 2 + }; + + /// + /// Entry that contains Provider Handle, Provider MetaData and Provider GUID + /// + struct Handle + { + REGHANDLE providerHandle; + std::vector providerMetaVector; + GUID providerGuid; + }; + + /// + /// Check if given provider is registered. + /// + /// + /// + bool is_registered(const std::string &providerId) + { + std::lock_guard lock(m_providerMapLock); + auto it = providers().find(providerId); + if (it != providers().end()) + { + if (it->second.providerHandle != INVALID_HANDLE) + { + return true; + } + } + return false; + } + + /// + /// Get Provider by Name or string representation of GUID + /// + /// + /// + Handle &open(const std::string &providerId, EventFormat format = EventFormat::ETW_MANIFEST) + { + std::lock_guard lock(m_providerMapLock); + +#ifdef HAVE_NO_TLD + // Fallback to MessagePack-encoded ETW events + format = EventFormat::ETW_MSGPACK; +#endif + + // Check and return if provider is already registered + auto it = providers().find(providerId); + if (it != providers().end()) + { + if (it->second.providerHandle != INVALID_HANDLE) + { + return it->second; + } + } + + // Register provider if necessary + auto &data = providers()[providerId]; + data.providerMetaVector.clear(); + + event::UUID guid = (providerId.rfind("{", 0) == 0) ? event::UUID(providerId.c_str()) + : // It's a ProviderGUID + utils::GetProviderGuid(providerId.c_str()); // It's a ProviderName + + data.providerGuid = guid.to_GUID(); + + // TODO: currently we do not allow to specify a custom group GUID + GUID providerGroupGuid = NULL_GUID; + + switch (format) + { +#ifdef HAVE_TLD + // Register with TraceLoggingDynamic facility - dynamic manifest ETW events. + case EventFormat::ETW_MANIFEST: { + tld::ProviderMetadataBuilder> providerMetaBuilder( + data.providerMetaVector); + + // Use Tenant ID as provider Name + providerMetaBuilder.Begin(providerId.c_str()); + providerMetaBuilder.AddTrait(tld::ProviderTraitType::ProviderTraitGroupGuid, + (void *)&providerGroupGuid, sizeof(GUID)); + providerMetaBuilder.End(); + + REGHANDLE hProvider = 0; + if (0 != + tld::RegisterProvider(&hProvider, &data.providerGuid, data.providerMetaVector.data())) + { + // There was an error registering the ETW provider + data.providerHandle = INVALID_HANDLE; + } + else + { + data.providerHandle = hProvider; + }; + }; + break; +#endif + +#ifdef HAVE_MSGPACK + // Register for MsgPack payload ETW events. + case EventFormat::ETW_MSGPACK: { + REGHANDLE hProvider = 0; + if (EventRegister(&data.providerGuid, NULL, NULL, &hProvider) != ERROR_SUCCESS) + { + // There was an error registering the ETW provider + data.providerHandle = INVALID_HANDLE; + } + else + { + data.providerHandle = hProvider; + } + }; + break; +#endif + + default: + // TODO: other protocols, e.g. XML events - not supported yet + break; + } + + // We always return an entry even if we failed to register. + // Caller should check whether the hProvider handle is valid. + return data; + } + + /// + /// Unregister Provider + /// + /// + /// + unsigned long close(Handle data) + { + std::lock_guard lock(m_providerMapLock); + + auto m = providers(); + auto it = m.begin(); + while (it != m.end()) + { + if (it->second.providerHandle == data.providerHandle) + { + auto result = EventUnregister(data.providerHandle); + m.erase(it); + return result; + } + }; + return STATUS_ERROR; + } + +#ifdef HAVE_MSGPACK + template + unsigned long writeMsgPack(Handle &providerData, T eventData) + { + + // Make sure you stop sending event before register unregistering providerData + if (providerData.providerHandle == INVALID_HANDLE) + { + // Provider not registered! + return STATUS_ERROR; + }; + + const std::string EVENT_NAME = "name"; + std::string eventName = "NoName"; + auto nameField = eventData[EVENT_NAME]; + switch (nameField.index()) + { + case common::AttributeType::TYPE_STRING: + eventName = + (char *)(nostd::get(nameField).data()); // must be 0-terminated! + break; + case common::AttributeType::TYPE_CSTRING: + eventName = (char *)(nostd::get(nameField)); + break; + default: + // This is user error. Invalid event name! + // We supply default 'NoName' event name in this case. + break; + } + + /* clang-format off */ + nlohmann::json jObj = + { + { "env_name", "Span" }, + { "env_ver", "4.0" }, + + // TODO: remove these fields. Provided for illustrative purposes only. + { "env_cloud_role", "BusyWorker" }, + { "env_cloud_roleInstance", "CY1SCH030021417" }, + { "env_cloud_roleVer", "9.0.15289.2" }, + // + + // TODO: compute time in MessagePack-friendly format + // TODO: should we consider uint64_t format with Unix timestamps for ELK stack? + { "env_time", + { + { "TypeCode", 255 }, + { "Body","0xFFFFFC60000000005F752C2C" } + } + }, + // + + // TODO: follow JSON implementation of OTLP or place protobuf for non-Microsoft flows + { "env_dt_traceId", "6dcdae7b9b0c7643967d74ee54056178" }, + { "env_dt_spanId", "5866c4322919e641" }, + // + + { "name", eventName }, + { "kind", 0 }, + { "startTime", + { + // TODO: timestamp + { "TypeCode", 255 }, + { "Body", "0xFFFF87CC000000005F752C2C" } + } + } + }; + /* clang-format on */ + + for (auto &kv : eventData) + { + const char *name = kv.first.data(); + // Don't include event name field in the payload + if (EVENT_NAME == name) + continue; + auto &value = kv.second; + switch (value.index()) + { + case common::AttributeType::TYPE_BOOL: { + UINT8 temp = static_cast(nostd::get(value)); + jObj[name] = temp; + break; + } + case common::AttributeType::TYPE_INT: { + auto temp = nostd::get(value); + jObj[name] = temp; + break; + } + case common::AttributeType::TYPE_INT64: { + auto temp = nostd::get(value); + jObj[name] = temp; + break; + } + case common::AttributeType::TYPE_UINT: { + auto temp = nostd::get(value); + jObj[name] = temp; + break; + } + case common::AttributeType::TYPE_UINT64: { + auto temp = nostd::get(value); + jObj[name] = temp; + break; + } + case common::AttributeType::TYPE_DOUBLE: { + auto temp = nostd::get(value); + jObj[name] = temp; + break; + } + case common::AttributeType::TYPE_STRING: { + auto temp = nostd::get(value); + jObj[name] = temp; + break; + } + case common::AttributeType::TYPE_CSTRING: { + auto temp = nostd::get(value); + jObj[name] = temp; + break; + } +# if HAVE_TYPE_GUID + // TODO: consider adding UUID/GUID to spec + case common::AttributeType::TYPE_GUID: { + auto temp = nostd::get(value); + // TODO: add transform from GUID type to string? + jObj[name] = temp; + break; + } +# endif + // TODO: arrays are not supported yet +# if 0 + // TODO: array of uint8_t is not supported by OT spec + case common::AttributeType::TYPE_SPAN_BYTE: +# endif + case common::AttributeType::TYPE_SPAN_BOOL: + case common::AttributeType::TYPE_SPAN_INT: + case common::AttributeType::TYPE_SPAN_INT64: + case common::AttributeType::TYPE_SPAN_UINT: + case common::AttributeType::TYPE_SPAN_UINT64: + case common::AttributeType::TYPE_SPAN_DOUBLE: + case common::AttributeType::TYPE_SPAN_STRING: + default: + // TODO: unsupported type + break; + } + }; + + // Layer 1 + nlohmann::json l1 = nlohmann::json::array(); + // Layer 2 + nlohmann::json l2 = nlohmann::json::array(); + // Layer 3 + nlohmann::json l3 = nlohmann::json::array(); + + l1.push_back("Span"); + + { + // TODO: clarify why this is needed + // TODO: fix time here + nlohmann::json j; + j["TypeCode"] = 255; + j["Body"] = "0xFFFFFC60000000005F752C2C"; + l3.push_back(j); + }; + + // Actual value object goes here + l3.push_back(jObj); + + l2.push_back(l3); + l1.push_back(l2); + + { + // Another time field again, but at the top + // TODO: fix time here + nlohmann::json j; + j["TypeCode"] = 255; + j["Body"] = "0xFFFFFC60000000005F752C2C"; + l1.push_back(j); + }; + + std::vector v = nlohmann::json::to_msgpack(l1); + + // NUL-terminator and padding for odd-sized buffers + v.push_back(0); + v.push_back(0); + if (v.size() % 2) + { + v.push_back(0); + }; + void *buff = v.data(); + + UCHAR level = 0; // LogAlways + auto writeResponse = EventWriteString(providerData.providerHandle, level, 0, (PCWSTR)buff); + + switch (writeResponse) + { + case ERROR_INVALID_PARAMETER: + break; + case ERROR_INVALID_HANDLE: + break; + case ERROR_ARITHMETIC_OVERFLOW: + break; + case ERROR_MORE_DATA: + break; + case ERROR_NOT_ENOUGH_MEMORY: + break; + default: + break; + }; + + if (writeResponse == ERROR_ARITHMETIC_OVERFLOW) + { + return STATUS_EFBIG; + }; + return (unsigned long)(writeResponse); + } +#endif + + /// + /// Send event to Provider Id + /// + /// + /// + /// + template + unsigned long writeTld(Handle &providerData, T eventData) + { +#ifdef HAVE_TLD + // Make sure you stop sending event before register unregistering providerData + if (providerData.providerHandle == INVALID_HANDLE) + { + // Provider not registered! + return STATUS_ERROR; + }; + + UINT32 eventTags = MICROSOFT_EVENTTAG_NORMAL_PERSISTENCE; + + std::vector byteVector; + std::vector byteDataVector; + tld::EventMetadataBuilder> builder(byteVector); + tld::EventDataBuilder> dbuilder(byteDataVector); + + const std::string EVENT_NAME = "name"; + std::string eventName = "NoName"; + auto nameField = eventData[EVENT_NAME]; + switch (nameField.index()) + { + case common::AttributeType::TYPE_STRING: + eventName = + (char *)(nostd::get(nameField).data()); // must be 0-terminated! + break; + case common::AttributeType::TYPE_CSTRING: + eventName = (char *)(nostd::get(nameField)); + break; + default: + // This is user error. Invalid event name! + // We supply default 'NoName' event name in this case. + break; + } + + builder.Begin(eventName.c_str(), eventTags); + + for (auto &kv : eventData) + { + const char *name = kv.first.data(); + // Don't include event name field in the payload + if (EVENT_NAME == name) + continue; + auto &value = kv.second; + switch (value.index()) + { + case common::AttributeType::TYPE_BOOL: { + builder.AddField(name, tld::TypeBool8); + UINT8 temp = static_cast(nostd::get(value)); + dbuilder.AddByte(temp); + break; + } + case common::AttributeType::TYPE_INT: { + builder.AddField(name, tld::TypeInt32); + auto temp = nostd::get(value); + dbuilder.AddValue(temp); + break; + } + case common::AttributeType::TYPE_INT64: { + builder.AddField(name, tld::TypeInt64); + auto temp = nostd::get(value); + dbuilder.AddValue(temp); + break; + } + case common::AttributeType::TYPE_UINT: { + builder.AddField(name, tld::TypeUInt32); + auto temp = nostd::get(value); + dbuilder.AddValue(temp); + break; + } + case common::AttributeType::TYPE_UINT64: { + builder.AddField(name, tld::TypeUInt64); + auto temp = nostd::get(value); + dbuilder.AddValue(temp); + break; + } + case common::AttributeType::TYPE_DOUBLE: { + builder.AddField(name, tld::TypeDouble); + auto temp = nostd::get(value); + dbuilder.AddValue(temp); + break; + } + case common::AttributeType::TYPE_STRING: { + builder.AddField(name, tld::TypeUtf8String); + auto temp = nostd::get(value); + dbuilder.AddString(temp.data()); + break; + } + case common::AttributeType::TYPE_CSTRING: { + builder.AddField(name, tld::TypeUtf8String); + auto temp = nostd::get(value); + dbuilder.AddString(temp); + break; + } + +# if HAVE_TYPE_GUID + // TODO: consider adding UUID/GUID to spec + case common::AttributeType::TYPE_GUID: { + builder.AddField(name.c_str(), TypeGuid); + auto temp = nostd::get(value); + dbuilder.AddBytes(&temp, sizeof(GUID)); + break; + } +# endif + + // TODO: arrays are not supported +# if 0 + case common::AttributeType::TYPE_SPAN_BYTE: +# endif + case common::AttributeType::TYPE_SPAN_BOOL: + case common::AttributeType::TYPE_SPAN_INT: + case common::AttributeType::TYPE_SPAN_INT64: + case common::AttributeType::TYPE_SPAN_UINT: + case common::AttributeType::TYPE_SPAN_UINT64: + case common::AttributeType::TYPE_SPAN_DOUBLE: + case common::AttributeType::TYPE_SPAN_STRING: + default: + // TODO: unsupported type + break; + } + }; + + if (!builder.End()) // Returns false if the metadata is too large. + { + return STATUS_EFBIG; // if event is too big for UTC to handle + } + + tld::EventDescriptor eventDescriptor; + // eventDescriptor.Keyword = MICROSOFT_KEYWORD_CRITICAL_DATA; + // eventDescriptor.Keyword = MICROSOFT_KEYWORD_TELEMETRY; + // eventDescriptor.Keyword = MICROSOFT_KEYWORD_MEASURES; + + EVENT_DATA_DESCRIPTOR pDataDescriptors[3]; + + EventDataDescCreate(&pDataDescriptors[2], byteDataVector.data(), + static_cast(byteDataVector.size())); + + // Event size detection is needed + int64_t eventByteSize = byteDataVector.size() + byteVector.size(); + int64_t eventKBSize = (eventByteSize + 1024 - 1) / 1024; + // bool isLargeEvent = eventKBSize >= LargeEventSizeKB; + + // TODO: extract + // - GUID ActivityId + // - GUID RelatedActivityId + + HRESULT writeResponse = tld::WriteEvent(providerData.providerHandle, eventDescriptor, + providerData.providerMetaVector.data(), + byteVector.data(), 3, pDataDescriptors); + + if (writeResponse == HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)) + { + return STATUS_EFBIG; + }; + + return (unsigned long)(writeResponse); +#else + return STATUS_ERROR; +#endif + } + + template + unsigned long write(Handle &providerData, + T eventData, + ETWProvider::EventFormat format = ETWProvider::EventFormat::ETW_MANIFEST) + { + if (format == ETWProvider::EventFormat::ETW_MANIFEST) + { + return writeTld(providerData, eventData); + } + if (format == ETWProvider::EventFormat::ETW_MSGPACK) + { + return writeMsgPack(providerData, eventData); + } + if (format == ETWProvider::EventFormat::ETW_XML) + { + // TODO: not implemented + return STATUS_ERROR; + } + return STATUS_ERROR; + }; + + static const REGHANDLE INVALID_HANDLE = _UI64_MAX; + +protected: + const unsigned int LargeEventSizeKB = 62; + + const GUID NULL_GUID = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; + + mutable std::mutex m_providerMapLock; + + using ProviderMap = std::map; + + ProviderMap &providers() + { + static std::map providers; + return providers; + }; +}; + +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h new file mode 100644 index 0000000000..364c3ad914 --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -0,0 +1,469 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/unique_ptr.h" + +#include "opentelemetry/common/key_value_iterable_view.h" +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/trace_id.h" +#include "opentelemetry/trace/tracer_provider.h" +#include "opentelemetry/trace/span_context_kv_iterable_view.h" + +#include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/sdk/trace/recordable.h" +#include "opentelemetry/sdk/trace/span_data.h" + +#include +#include +#include +#include +#include +#include + +#include "opentelemetry/exporters/etw/etw_provider_exporter.h" + +#include "opentelemetry/exporters/etw/utils.h" + +namespace core = opentelemetry::core; +namespace trace = opentelemetry::trace; + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace ETW +{ + +class Span; + +/// +/// stream::Tracer class that allows to send spans to ETW +/// +class Tracer : public trace::Tracer +{ + /// + /// Parent provider of this Tracer + /// + trace::TracerProvider &parent; + + /// + /// Provider Id (Name or GUID) + /// + std::string provId; + + /// + /// Provider Handle + /// + ETWProvider::Handle provHandle; + + /// + /// Encoding (Manifest, MessagePack or XML) + /// + ETWProvider::EventFormat encoding; + + /// + /// ETWProvider is a singleton that aggregates all ETW writes. + /// + /// + static ETWProvider &etwProvider() + { + static ETWProvider instance; // C++11 magic static + return instance; + }; + +public: + /// + /// Tracer constructor + /// + /// Parent TraceProvider + /// providerId + /// Tracer instance + Tracer(trace::TracerProvider &parent, + nostd::string_view providerId = "", + ETWProvider::EventFormat encoding = ETWProvider::EventFormat::ETW_MANIFEST) + : trace::Tracer(), + parent(parent), + provId(providerId.data(), providerId.size()), + encoding(encoding) + { + provHandle = etwProvider().open(provId, encoding); + }; + + /// + /// Start Span + /// + /// Span name + /// Span options + /// Span + virtual nostd::shared_ptr StartSpan( + nostd::string_view name, + const common::KeyValueIterable &attributes, + const trace::SpanContextKeyValueIterable &links, + const trace::StartSpanOptions &options = {}) noexcept override + { + // TODO: support attributes + UNREFERENCED_PARAMETER(attributes); + UNREFERENCED_PARAMETER(links); + return trace::to_span_ptr(this, name, options); + }; + + /// + /// Force flush data to Tracer, spending up to given amount of microseconds to flush. + /// + /// Allow Tracer to drop data if timeout is reached + /// void + virtual void ForceFlushWithMicroseconds(uint64_t) noexcept override{}; + + /// + /// Close tracer, spending up to given amount of microseconds to flush and close. + /// + /// Allow Tracer to drop data if timeout is reached + /// + virtual void CloseWithMicroseconds(uint64_t) noexcept override + { + etwProvider().close(provHandle); + }; + + /// + /// Add event data to span associated with tracer + /// + /// + /// + /// + /// + /// + void AddEvent(Span &span, + nostd::string_view name, + core::SystemTimestamp timestamp, + const common::KeyValueIterable &attributes) noexcept + { + // TODO: associate events with span + (void)span; + // TODO: respect original timestamp + (void)timestamp; + + // Unfortunately we copy right now since we don't have the knowledge of original map object :-( + std::map m; + attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { + m[key] = value; + return true; + }); + m["name"] = name.data(); + +#ifdef HAVE_TLD + if (encoding == ETWProvider::ETW_MANIFEST) + { + etwProvider().writeTld(provHandle, m); + return; + } +#endif + +#ifdef HAVE_MSGPACK + if (encoding == ETWProvider::ETW_MSGPACK) + { + etwProvider().writeMsgPack(provHandle, m); + return; + } +#endif + }; + + /// + /// Add event data to span associated with tracer + /// + /// + /// + /// + /// + void AddEvent(Span &span, nostd::string_view name, core::SystemTimestamp timestamp) noexcept + { + AddEvent(span, name, timestamp, common::NullKeyValueIterable()); + }; + + /// + /// Add event data to span associated with tracer + /// + /// + /// + void AddEvent(Span &span, nostd::string_view name) + { + AddEvent(span, name, std::chrono::system_clock::now(), common::NullKeyValueIterable()); + }; + + virtual ~Tracer() { CloseWithMicroseconds(0); }; +}; + +/// +/// stream::Span allows to send event data to stream +/// +class Span : public trace::Span +{ + +protected: + /// + /// Parent (Owner) Tracer of this Span + /// + Tracer &owner; + +public: + /// + /// Span constructor + /// + /// Owner Tracer + /// Span name + /// Span options + /// Span + Span(Tracer &owner, nostd::string_view name, const trace::StartSpanOptions &options) noexcept + : trace::Span(), owner(owner) + { + UNREFERENCED_PARAMETER(name); + UNREFERENCED_PARAMETER(options); + }; + + ~Span() { End(); } + + /// + /// Add named event with no attributes + /// + /// + /// + virtual void AddEvent(nostd::string_view name) noexcept override { owner.AddEvent(*this, name); } + + /// + /// Add named event with custom timestamp + /// + /// + /// + /// + virtual void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override + { + owner.AddEvent(*this, name, timestamp); + } + + /// + /// Add named event with custom timestamp and attributes + /// + /// + /// + /// + /// + void AddEvent(nostd::string_view name, + core::SystemTimestamp timestamp, + const common::KeyValueIterable &attributes) noexcept override + { + owner.AddEvent(*this, name, timestamp, attributes); + } + + /// + /// Set Span status + /// + /// + /// + /// + virtual void SetStatus(trace::CanonicalCode code, + nostd::string_view description) noexcept override + { + // TODO: not implemented + UNREFERENCED_PARAMETER(code); + UNREFERENCED_PARAMETER(description); + }; + + // Sets an attribute on the Span. If the Span previously contained a mapping for + // the key, the old value is replaced. + virtual void SetAttribute(nostd::string_view key, + const common::AttributeValue &value) noexcept override + { + // TODO: not implemented + UNREFERENCED_PARAMETER(key); + UNREFERENCED_PARAMETER(value); + }; + + /// + /// Update Span name + /// + /// + /// + virtual void UpdateName(nostd::string_view name) noexcept override + { + // TODO: not implemented + UNREFERENCED_PARAMETER(name); + } + + /// + /// End Span + /// + /// + virtual void End(const trace::EndSpanOptions & = {}) noexcept override + { + // TODO: signal this to owner + } + + virtual trace::SpanContext GetContext() const noexcept + { + // TODO: not implemented + static trace::SpanContext nullContext; + return nullContext; + } + + /// + /// Check if Span is recording data + /// + /// + virtual bool IsRecording() const noexcept override + { + // TODO: not implemented + return true; + } + + virtual void SetToken(nostd::unique_ptr &&token) noexcept + { + // TODO: not implemented + UNREFERENCED_PARAMETER(token); + } + + /// + /// Get Owner tracer of this Span + /// + /// + trace::Tracer &tracer() const noexcept { return this->owner; }; +}; + + +/// +/// stream::TraceProvider +/// +class TracerProvider : public trace::TracerProvider +{ +public: + /// + /// Obtain a Tracer of given type (name) and supply extra argument arg2 to it. + /// + /// Tracer Type + /// Tracer arguments + /// + virtual nostd::shared_ptr GetTracer(nostd::string_view name, + nostd::string_view args = "") + { + // TODO: describe possible args. Currently supported: + // "MSGPACK" - use MessagePack + // "XML" - use XML + // "ETW" - use 'classic' Trace Logging Dynamic manifest ETW event + // +#if defined(HAVE_NO_TLD) && defined(HAVE_MSGPACK) + ETWProvider::EventFormat evtFmt = ETWProvider::EventFormat::ETW_MSGPACK; +#else + ETWProvider::EventFormat evtFmt = ETWProvider::EventFormat::ETW_MANIFEST; +#endif + +#pragma warning(push) +#pragma warning(disable : 4307) /* Integral constant overflow - OK while computing hash */ + auto h = utils::hashCode(args.data()); + switch (h) + { + case CONST_HASHCODE(MSGPACK): + // nobrk + case CONST_HASHCODE(MsgPack): + // nobrk + case CONST_HASHCODE(MessagePack): + evtFmt = ETWProvider::EventFormat::ETW_MSGPACK; + break; + + case CONST_HASHCODE(XML): + // nobrk + case CONST_HASHCODE(xml): + evtFmt = ETWProvider::EventFormat::ETW_XML; + break; + + case CONST_HASHCODE(TLD): + // nobrk + case CONST_HASHCODE(tld): + // nobrk + evtFmt = ETWProvider::EventFormat::ETW_MANIFEST; + break; + + default: + break; + } +#pragma warning(pop) + return nostd::shared_ptr{new (std::nothrow) Tracer(*this, name, evtFmt)}; + } +}; + +class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter +{ +public: + /** + * @param providerName + * @param eventName + */ + ETWTracerExporter(std::string providerName, std::string eventName): providerName_(providerName), eventName_(eventName) + { + } + + /** + * @return Returns a unique pointer to an empty recordable object + */ + std::unique_ptr MakeRecordable() noexcept override + { + // TODO: Discuss how we want to make the Recordable + //return std::unique_ptr(new TracerProvider()); + } + + /** + * @param recordables a required span containing unique pointers to the data + * to add to the ETWTracerExporter + * @return Returns the result of the operation + */ + sdk::trace::ExportResult Export( + const nostd::span> &recordables) noexcept override + { + for (auto &recordable : recordables) + { + auto tp = std::unique_ptr( + dynamic_cast(recordable.release())); + if (tp != nullptr) + { + auto tracer = tp->GetTracer(providerName_); + auto span = tracer->StartSpan("MySpan"); + + // do whatever is needed + } + } + + return sdk::trace::ExportResult::kSuccess; + } + + /** + * @param timeout an optional value containing the timeout of the exporter + * note: passing custom timeout values is not currently supported for this exporter + */ + void Shutdown( + std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override{}; + +private: + std::string providerName_; + std::string eventName_; +}; + +} // namespace ETW + +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/include/opentelemetry/exporters/etw/utils.h b/exporters/etw/include/opentelemetry/exporters/etw/utils.h new file mode 100644 index 0000000000..63f81f569e --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -0,0 +1,209 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "opentelemetry/exporters/etw/uuid.hpp" +#include "opentelemetry/version.h" + +#ifdef _WIN32 +# include +# include +# include +# pragma comment(lib, "Advapi32.lib") +# pragma comment(lib, "Rpcrt4.lib") +#endif + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace utils +{ + +/// +/// Compile-time constexpr djb2 hash function for strings +/// +static constexpr uint32_t hashCode(const char *str, uint32_t h = 0) +{ + return (uint32_t)(!str[h] ? 5381 : ((uint32_t)hashCode(str, h + 1) * (uint32_t)33) ^ str[h]); +} + +#define CONST_UINT32_T(x) std::integral_constant::value + +#define CONST_HASHCODE(name) CONST_UINT32_T(OPENTELEMETRY_NAMESPACE::utils::hashCode(#name)) + +#ifdef _WIN32 + +/// +/// Compute SHA-1 hash of input buffer and save to output +/// +/// Input buffer +/// Input buffer size +/// Output buffer +/// Output buffer size +/// +static inline bool sha1(const BYTE *pData, DWORD nData, BYTE *pHashedData, DWORD &nHashedData) +{ + bool bRet = false; + HCRYPTPROV hProv = NULL; + HCRYPTHASH hHash = NULL; + + if (!CryptAcquireContext(&hProv, // handle of the CSP + NULL, // key container name + NULL, // CSP name + PROV_RSA_FULL, // provider type + CRYPT_VERIFYCONTEXT)) // no key access is requested + { + bRet = false; + goto CleanUp; + } + + if (!CryptCreateHash(hProv, // handle of the CSP + CALG_SHA1, // hash algorithm to use + 0, // hash key + 0, // reserved + &hHash)) // + { + bRet = false; + goto CleanUp; + } + + if (!CryptHashData(hHash, // handle of the HMAC hash object + pData, // message to hash + nData, // number of bytes of data to add + 0)) // flags + { + bRet = false; + goto CleanUp; + } + + if (!CryptGetHashParam(hHash, // handle of the HMAC hash object + HP_HASHVAL, // query on the hash value + pHashedData, // filled on second call + &nHashedData, // length, in bytes,of the hash + 0)) + { + bRet = false; + goto CleanUp; + } + + bRet = true; + +CleanUp: + + if (hHash) + { + CryptDestroyHash(hHash); + } + + if (hProv) + { + CryptReleaseContext(hProv, 0); + } + return bRet; +} + +/// +/// Convert UTF-8 string to UTF-16 wide string. +/// +/// FIXME: this conversion is marked deprecated after C++17: +/// https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16 +/// It works well with Visual C++, but may not work with clang. +/// Best long-term solution is to use Win32 API instead. +/// +/// +/// +/// +static inline std::wstring to_utf16_string(const std::string &in) +{ + std::wstring_convert, wchar_t> converter; + return converter.from_bytes(in); +} + +/// +/// Transform ETW provider name to provider GUID as described here: +/// https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/ +/// +/// +/// +static inline GUID GetProviderGuid(const char *providerName) +{ + std::string name(providerName); + std::transform(name.begin(), name.end(), name.begin(), + [](unsigned char c) { return (char)::toupper(c); }); + + size_t len = name.length() * 2 + 0x10; + uint8_t *buffer = new uint8_t[len]; + uint32_t num = 0x482c2db2; + uint32_t num2 = 0xc39047c8; + uint32_t num3 = 0x87f81a15; + uint32_t num4 = 0xbfc130fb; + + for (int i = 3; i >= 0; i--) + { + buffer[i] = (uint8_t)num; + num = num >> 8; + buffer[i + 4] = (uint8_t)num2; + num2 = num2 >> 8; + buffer[i + 8] = (uint8_t)num3; + num3 = num3 >> 8; + buffer[i + 12] = (uint8_t)num4; + num4 = num4 >> 8; + } + + for (size_t j = 0; j < name.length(); j++) + { + buffer[((2 * j) + 0x10) + 1] = (uint8_t)name[j]; + buffer[(2 * j) + 0x10] = (uint8_t)(name[j] >> 8); + } + + const size_t sha1_hash_size = 21; + uint8_t *buffer2 = new uint8_t[sha1_hash_size]; + DWORD len2 = sha1_hash_size; + sha1((const BYTE *)buffer, (DWORD)len, (BYTE *)buffer2, len2); + + unsigned long a = (((((buffer2[3] << 8) + buffer2[2]) << 8) + buffer2[1]) << 8) + buffer2[0]; + unsigned short b = (unsigned short)((buffer2[5] << 8) + buffer2[4]); + unsigned short num9 = (unsigned short)((buffer2[7] << 8) + buffer2[6]); + + GUID guid; + guid.Data1 = a; + guid.Data2 = b; + guid.Data3 = (unsigned short)((num9 & 0xfff) | 0x5000); + guid.Data4[0] = buffer2[8]; + guid.Data4[1] = buffer2[9]; + guid.Data4[2] = buffer2[10]; + guid.Data4[3] = buffer2[11]; + guid.Data4[4] = buffer2[12]; + guid.Data4[5] = buffer2[13]; + guid.Data4[6] = buffer2[14]; + guid.Data4[7] = buffer2[15]; + + delete buffer; + delete buffer2; + + return guid; +} +#endif + +}; // namespace utils + +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/exporters/etw/include/opentelemetry/exporters/etw/uuid.hpp b/exporters/etw/include/opentelemetry/exporters/etw/uuid.hpp new file mode 100644 index 0000000000..6c9e6bdc98 --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/uuid.hpp @@ -0,0 +1,423 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "opentelemetry/version.h" + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include "Windows.h" +#endif + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace event +{ + +/// +/// The UUID structure represents the portable cross-platform implementation of a GUID (Globally +/// Unique ID). +/// +/// +/// UUIDs identify objects such as interfaces, manager entry-point vectors (EPVs), and class +/// objects. A UUID is a 128-bit value consisting of one group of eight hexadecimal digits, followed +/// by three groups of four hexadecimal digits, each followed by one group of 12 hexadecimal digits. +/// +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary */ +struct UUID +{ + /// + /// Specifies the first eight hexadecimal digits of the GUID. + /// + uint32_t Data1; + + /// + /// Specifies the first group of four hexadecimal digits. + /// + uint16_t Data2; + + /// + /// Specifies the second group of four hexadecimal digits. + /// + uint16_t Data3; + + /// + /// An array of eight bytes. + /// The first two bytes contain the third group of four hexadecimal digits. + /// The remaining six bytes contain the final 12 hexadecimal digits. + /// + uint8_t Data4[8]; + + /// + /// The default UUID constructor. + /// Creates a null instance of the UUID object (initialized to all zeros). + /// {00000000-0000-0000-0000-000000000000}. + /// + UUID() : Data1(0), Data2(0), Data3(0) + { + for (size_t i = 0; i < 8; i++) + { + Data4[i] = 0; + } + }; + + /// + /// A constructor that creates a UUID object from a hyphenated string as defined by + /// https://tools.ietf.org/html/rfc4122#page-4 + /// + /// A hyphenated string that contains the UUID (curly braces + /// optional). + UUID(const char *uuid_string) + { + const char *str = uuid_string; + // Skip curly brace + if (str[0] == '{') + { + str++; + } + // Convert to set of integer values + unsigned long p0; + unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10; + if ( + // Parse input with dashes + (11 == sscanf(str, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", &p0, &p1, &p2, &p3, + &p4, &p5, &p6, &p7, &p8, &p9, &p10)) || + // Parse input without dashes + (11 == sscanf(str, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", &p0, &p1, &p2, &p3, &p4, + &p5, &p6, &p7, &p8, &p9, &p10))) + { + Data1 = static_cast(p0); + Data2 = static_cast(p1); + Data3 = static_cast(p2); + Data4[0] = static_cast(p3); + Data4[1] = static_cast(p4); + Data4[2] = static_cast(p5); + Data4[3] = static_cast(p6); + Data4[4] = static_cast(p7); + Data4[5] = static_cast(p8); + Data4[6] = static_cast(p9); + Data4[7] = static_cast(p10); + } + else // Invalid input--use a safe default value + { + Data1 = 0; + Data2 = 0; + Data3 = 0; + Data4[0] = 0; + Data4[1] = 0; + Data4[2] = 0; + Data4[3] = 0; + Data4[4] = 0; + Data4[5] = 0; + Data4[6] = 0; + Data4[7] = 0; + } + } + + /// + /// A constructor that creates a UUID object from a byte array. + /// + /// A byte array. + /// + /// A boolean value that specifies the byte order.
+ /// A value of true specifies the more natural human-readable order.
+ /// A value of false (the default) specifies the same order as the .NET GUID constructor. + /// + UUID(const uint8_t guid_bytes[16], bool bigEndian = false) + { + if (bigEndian) + { + /* Use big endian - human-readable */ + // Part 1 + Data1 = guid_bytes[3]; + Data1 |= ((uint32_t)(guid_bytes[2])) << 8; + Data1 |= ((uint32_t)(guid_bytes[1])) << 16; + Data1 |= ((uint32_t)(guid_bytes[0])) << 24; + // Part 2 + Data2 = guid_bytes[5]; + Data2 |= ((uint16_t)(guid_bytes[4])) << 8; + // Part 3 + Data3 = guid_bytes[7]; + Data3 |= ((uint16_t)(guid_bytes[6])) << 8; + } + else + { + /* Use little endian - the same order as .NET C# Guid() class uses */ + // Part 1 + Data1 = guid_bytes[0]; + Data1 |= ((uint32_t)(guid_bytes[1])) << 8; + Data1 |= ((uint32_t)(guid_bytes[2])) << 16; + Data1 |= ((uint32_t)(guid_bytes[3])) << 24; + // Part 2 + Data2 = guid_bytes[4]; + Data2 |= ((uint16_t)(guid_bytes[5])) << 8; + // Part 3 + Data3 = guid_bytes[6]; + Data3 |= ((uint16_t)(guid_bytes[7])) << 8; + } + // Part 4 + for (size_t i = 0; i < 8; i++) + { + Data4[i] = guid_bytes[8 + i]; + } + } + + /// + /// A constructor that creates a UUID object from three integers and a byte array. + /// + /// An integer that specifies the first eight hexadecimal digits of the + /// UUID. An integer that specifies the first group of four hexadecimal + /// digits. An integer that specifies the second group of four + /// hexadecimal digits. A reference to an array of eight bytes. The first + /// two bytes contain the third group of four hexadecimal digits. The remaining six bytes contain + /// the final 12 hexadecimal digits. + UUID(int d1, int d2, int d3, const std::initializer_list &v) + : Data1((uint32_t)d1), Data2((uint16_t)d2), Data3((uint16_t)d3) + { + size_t i = 0; + for (auto val : v) + { + Data4[i] = val; + i++; + } + } + + /// + /// The UUID copy constructor. + /// + /// A UUID object. + UUID(const UUID &uuid) + { + this->Data1 = uuid.Data1; + this->Data2 = uuid.Data2; + this->Data3 = uuid.Data3; + memcpy(&(this->Data4[0]), &(uuid.Data4[0]), sizeof(uuid.Data4)); + } + +#ifdef _WIN32 + + /// + /// A constructor that creates a UUID object from a Windows GUID object. + /// + /// A Windows GUID object. + UUID(GUID guid) + { + this->Data1 = guid.Data1; + this->Data2 = guid.Data2; + this->Data3 = guid.Data3; + std::memcpy(&(this->Data4[0]), &(guid.Data4[0]), sizeof(guid.Data4)); + } + + /// + /// Converts a standard vector of bytes into a Windows GUID object. + /// + /// A standard vector of bytes. + /// A GUID. + static GUID to_GUID(std::vector const &bytes) + { + UUID temp_t = UUID(bytes.data()); + GUID temp; + temp.Data1 = temp_t.Data1; + temp.Data2 = temp_t.Data2; + temp.Data3 = temp_t.Data3; + for (size_t i = 0; i < 8; i++) + { + temp.Data4[i] = temp_t.Data4[i]; + } + return temp; + } + + GUID to_GUID() + { + GUID temp; + temp.Data1 = Data1; + temp.Data2 = Data2; + temp.Data3 = Data3; + for (size_t i = 0; i < 8; i++) + { + temp.Data4[i] = Data4[i]; + } + return temp; + } + +#endif + + /// + /// Converts this UUID to an array of bytes. + /// + /// A uint8_t array of 16 bytes. + void to_bytes(uint8_t (&guid_bytes)[16]) const + { + // Part 1 + guid_bytes[0] = (uint8_t)((Data1)&0xFF); + guid_bytes[1] = (uint8_t)((Data1 >> 8) & 0xFF); + guid_bytes[2] = (uint8_t)((Data1 >> 16) & 0xFF); + guid_bytes[3] = (uint8_t)((Data1 >> 24) & 0xFF); + // Part 2 + guid_bytes[4] = (uint8_t)((Data2)&0xFF); + guid_bytes[5] = (uint8_t)((Data2 >> 8) & 0xFF); + // Part 3 + guid_bytes[6] = (uint8_t)((Data3)&0xFF); + guid_bytes[7] = (uint8_t)((Data3 >> 8) & 0xFF); + // Part 4 + for (size_t i = 0; i < 8; i++) + { + guid_bytes[8 + i] = Data4[i]; + } + } + + /// + /// Convert this UUID object to a string. + /// + /// This UUID object in a string. + std::string to_string() const + { + static char inttoHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + const unsigned buffSize = 36 + 1; // 36 + null-terminator + char buf[buffSize] = {0}; + + int test = (Data1 >> 28 & 0x0000000F); + buf[0] = inttoHex[test]; + test = (int)(Data1 >> 24 & 0x0000000F); + buf[1] = inttoHex[test]; + test = (int)(Data1 >> 20 & 0x0000000F); + buf[2] = inttoHex[test]; + test = (int)(Data1 >> 16 & 0x0000000F); + buf[3] = inttoHex[test]; + test = (int)(Data1 >> 12 & 0x0000000F); + buf[4] = inttoHex[test]; + test = (int)(Data1 >> 8 & 0x0000000F); + buf[5] = inttoHex[test]; + test = (int)(Data1 >> 4 & 0x0000000F); + buf[6] = inttoHex[test]; + test = (int)(Data1 & 0x0000000F); + buf[7] = inttoHex[test]; + buf[8] = '-'; + test = (int)(Data2 >> 12 & 0x000F); + buf[9] = inttoHex[test]; + test = (int)(Data2 >> 8 & 0x000F); + buf[10] = inttoHex[test]; + test = (int)(Data2 >> 4 & 0x000F); + buf[11] = inttoHex[test]; + test = (int)(Data2 & 0x000F); + buf[12] = inttoHex[test]; + buf[13] = '-'; + test = (int)(Data3 >> 12 & 0x000F); + buf[14] = inttoHex[test]; + test = (int)(Data3 >> 8 & 0x000F); + buf[15] = inttoHex[test]; + test = (int)(Data3 >> 4 & 0x000F); + buf[16] = inttoHex[test]; + test = (int)(Data3 & 0x000F); + buf[17] = inttoHex[test]; + buf[18] = '-'; + test = (int)(Data4[0] >> 4 & 0x0F); + buf[19] = inttoHex[test]; + test = (int)(Data4[0] & 0x0F); + buf[20] = inttoHex[test]; + test = (int)(Data4[1] >> 4 & 0x0F); + buf[21] = inttoHex[test]; + test = (int)(Data4[1] & 0x0F); + buf[22] = inttoHex[test]; + buf[23] = '-'; + test = (int)(Data4[2] >> 4 & 0x0F); + buf[24] = inttoHex[test]; + test = (int)(Data4[2] & 0x0F); + buf[25] = inttoHex[test]; + test = (int)(Data4[3] >> 4 & 0x0F); + buf[26] = inttoHex[test]; + test = (int)(Data4[3] & 0x0F); + buf[27] = inttoHex[test]; + test = (int)(Data4[4] >> 4 & 0x0F); + buf[28] = inttoHex[test]; + test = (int)(Data4[4] & 0x0F); + buf[29] = inttoHex[test]; + test = (int)(Data4[5] >> 4 & 0x0F); + buf[30] = inttoHex[test]; + test = (int)(Data4[5] & 0x0F); + buf[31] = inttoHex[test]; + test = (int)(Data4[6] >> 4 & 0x0F); + buf[32] = inttoHex[test]; + test = (int)(Data4[6] & 0x0F); + buf[33] = inttoHex[test]; + test = (int)(Data4[7] >> 4 & 0x0F); + buf[34] = inttoHex[test]; + test = (int)(Data4[7] & 0x0F); + buf[35] = inttoHex[test]; + buf[36] = 0; + + return std::string(buf); + } + + /// + /// Calculates the size of this UUID object. + /// The output from this method is compatible with std::unordered_map. + /// + /// The size of the UUID object in bytes. + size_t Hash() const + { + // Compute individual hash values for Data1, Data2, Data3, and parts of Data4 + size_t res = 17; + res = res * 31 + Data1; + res = res * 31 + Data2; + res = res * 31 + Data3; + res = res * 31 + (Data4[0] << 24 | Data4[1] << 16 | Data4[6] << 8 | Data4[7]); + return res; + } + + /// + /// Tests to determine whether two UUID objects are equivalent (needed for maps). + /// + /// A boolean value that indicates success or failure. + bool operator==(UUID const &other) const + { + return Data1 == other.Data1 && Data2 == other.Data2 && Data3 == other.Data3 && + (0 == memcmp(Data4, other.Data4, sizeof(Data4))); + } + + /// + /// Tests to determine how to sort 2 UUID objects + /// + /// A boolean value that indicates success or failure. + bool operator<(UUID const &other) const + { + return Data1 < other.Data1 || Data2 < other.Data2 || Data3 == other.Data3 || + (memcmp(Data4, other.Data4, sizeof(Data4)) < 0); + } +}; +#pragma pack(pop) /* restore original alignment from stack */ + +/// +/// Declare UUIDComparer as the Comparer when using UUID as a key in a map or set +/// +struct UUIDComparer : std::less +{ + inline size_t operator()(UUID const &key) const { return key.Hash(); } + + inline bool operator()(UUID const &lhs, UUID const &rhs) const { return lhs.Hash() < rhs.Hash(); } +}; + +} // namespace event + +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/src/etw_provider_exporter.cc b/exporters/etw/src/etw_provider_exporter.cc new file mode 100644 index 0000000000..124f775d70 --- /dev/null +++ b/exporters/etw/src/etw_provider_exporter.cc @@ -0,0 +1,3 @@ +#define HAVE_NO_TLD + +#include "opentelemetry/exporters/etw/etw_provider_exporter.h" \ No newline at end of file diff --git a/exporters/etw/src/etw_tracer_exporter.cc b/exporters/etw/src/etw_tracer_exporter.cc new file mode 100644 index 0000000000..9045731a94 --- /dev/null +++ b/exporters/etw/src/etw_tracer_exporter.cc @@ -0,0 +1,3 @@ +#define HAVE_NO_TLD + +#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" \ No newline at end of file diff --git a/exporters/etw/test/etw_provider_test.cc b/exporters/etw/test/etw_provider_test.cc new file mode 100644 index 0000000000..99fb88a638 --- /dev/null +++ b/exporters/etw/test/etw_provider_test.cc @@ -0,0 +1,71 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#define HAVE_NO_TLD + +#include "opentelemetry/exporters/etw/etw_provider_exporter.h" + +using namespace OPENTELEMETRY_NAMESPACE; + +TEST(ETWProvider, ProviderIsRegisteredSuccessfully) +{ + std::string providerName = "OpenTelemetry"; + static ETWProvider etw; + auto handle = etw.open(providerName.c_str()); + + bool registered = etw.is_registered(providerName); + ASSERT_TRUE(registered); +} + +TEST(ETWProvider, ProviderIsNotRegisteredSuccessfully) +{ + std::string providerName = "Telemetry"; + static ETWProvider etw; + + bool registered = etw.is_registered(providerName); + ASSERT_FALSE(registered); +} + +TEST(ETWProvider, CheckOpenGUIDDataSuccessfully) +{ + std::string providerName = "OpenTelemetry"; + + // get GUID from the handle returned + static ETWProvider etw; + auto handle = etw.open(providerName.c_str()); + + event::UUID uuid_handle(handle.providerGuid); + auto guidStrHandle = uuid_handle.to_string(); + + // get GUID from the providerName + auto guid = utils::GetProviderGuid(providerName.c_str()); + event::UUID uuid_name(guid); + auto guidStrName = uuid_name.to_string(); + + ASSERT_STREQ(guidStrHandle.c_str(), guidStrName.c_str()); +} + +TEST(ETWProvider, CheckCloseSuccess) +{ + std::string providerName = "OpenTelemetry"; + + static ETWProvider etw; + auto handle = etw.open(providerName.c_str()); + + auto result = etw.close(handle); + ASSERT_NE(result, etw.STATUS_ERROR); +} diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc new file mode 100644 index 0000000000..aa526c4e28 --- /dev/null +++ b/exporters/etw/test/etw_tracer_test.cc @@ -0,0 +1,41 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#define HAVE_NO_TLD + +#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" + +using namespace OPENTELEMETRY_NAMESPACE; + +using ETWEvent = std::map; + +TEST(ETWTracer, TracerCheck) +{ + std::string providerName = "OpenTelemetry"; + std::string eventName = "MyEvent"; + + ETW::TracerProvider tp; + auto tracer = tp.GetTracer(providerName); + auto span = tracer->StartSpan("MySpan"); + + ETWEvent event = { + {"uint32Key", (uint32_t)123456}, {"uint64Key", (uint64_t)123456}, {"strKey", "someValue"}}; + + EXPECT_NO_THROW(span->AddEvent(eventName, event)); + EXPECT_NO_THROW(span->End()); + EXPECT_NO_THROW(tracer->Close()); +} From 84834dd22c0d5ccd8e5d1bac6b18519ef1d43a23 Mon Sep 17 00:00:00 2001 From: mishal23 Date: Wed, 18 Nov 2020 00:22:31 +0530 Subject: [PATCH 02/20] add etwData class to use for recordable --- .../opentelemetry/sdk/trace/etw_data.h | 532 ++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100644 sdk/include/opentelemetry/sdk/trace/etw_data.h diff --git a/sdk/include/opentelemetry/sdk/trace/etw_data.h b/sdk/include/opentelemetry/sdk/trace/etw_data.h new file mode 100644 index 0000000000..555bfd6e7c --- /dev/null +++ b/sdk/include/opentelemetry/sdk/trace/etw_data.h @@ -0,0 +1,532 @@ +#pragma once + +#include +#include +#include + +#include + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/unique_ptr.h" + +#include "opentelemetry/common/key_value_iterable_view.h" +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context_kv_iterable_view.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/trace_id.h" +#include "opentelemetry/trace/tracer_provider.h" + +#include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/sdk/trace/recordable.h" +#include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/sdk/trace/recordable.h" + +#include +#include +#include +#include +#include +#include + +#include "opentelemetry/exporters/etw/etw_provider_exporter.h" + +#include "opentelemetry/exporters/etw/utils.h" + +namespace core = opentelemetry::core; +namespace trace = opentelemetry::trace; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ + +class Span; + +/// +/// stream::Tracer class that allows to send spans to ETW +/// +class Tracer : public trace::Tracer +{ + /// + /// Parent provider of this Tracer + /// + trace::TracerProvider &parent; + + /// + /// Provider Id (Name or GUID) + /// + std::string provId; + + /// + /// Provider Handle + /// + ETWProvider::Handle provHandle; + + /// + /// Encoding (Manifest, MessagePack or XML) + /// + ETWProvider::EventFormat encoding; + + /// + /// ETWProvider is a singleton that aggregates all ETW writes. + /// + /// + static ETWProvider &etwProvider() + { + static ETWProvider instance; // C++11 magic static + return instance; + }; + +public: + /// + /// Tracer constructor + /// + /// Parent TraceProvider + /// providerId + /// Tracer instance + Tracer(trace::TracerProvider &parent, + nostd::string_view providerId = "", + ETWProvider::EventFormat encoding = ETWProvider::EventFormat::ETW_MANIFEST) + : trace::Tracer(), + parent(parent), + provId(providerId.data(), providerId.size()), + encoding(encoding) + { + provHandle = etwProvider().open(provId, encoding); + }; + + /// + /// Start Span + /// + /// Span name + /// Span options + /// Span + virtual nostd::shared_ptr StartSpan( + nostd::string_view name, + const common::KeyValueIterable &attributes, + const trace::SpanContextKeyValueIterable &links, + const trace::StartSpanOptions &options = {}) noexcept override + { + // TODO: support attributes + UNREFERENCED_PARAMETER(attributes); + UNREFERENCED_PARAMETER(links); + return trace::to_span_ptr(this, name, options); + }; + + /// + /// Force flush data to Tracer, spending up to given amount of microseconds to flush. + /// + /// Allow Tracer to drop data if timeout is reached + /// void + virtual void ForceFlushWithMicroseconds(uint64_t) noexcept override{}; + + /// + /// Close tracer, spending up to given amount of microseconds to flush and close. + /// + /// Allow Tracer to drop data if timeout is reached + /// + virtual void CloseWithMicroseconds(uint64_t) noexcept override + { + etwProvider().close(provHandle); + }; + + /// + /// Add event data to span associated with tracer + /// + /// + /// + /// + /// + /// + void AddEvent(Span &span, + nostd::string_view name, + core::SystemTimestamp timestamp, + const common::KeyValueIterable &attributes) noexcept + { + // TODO: associate events with span + (void)span; + // TODO: respect original timestamp + (void)timestamp; + + // Unfortunately we copy right now since we don't have the knowledge of original map object :-( + std::map m; + attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { + m[key] = value; + return true; + }); + m["name"] = name.data(); + +#ifdef HAVE_TLD + if (encoding == ETWProvider::ETW_MANIFEST) + { + etwProvider().writeTld(provHandle, m); + return; + } +#endif + +#ifdef HAVE_MSGPACK + if (encoding == ETWProvider::ETW_MSGPACK) + { + etwProvider().writeMsgPack(provHandle, m); + return; + } +#endif + }; + + /// + /// Add event data to span associated with tracer + /// + /// + /// + /// + /// + void AddEvent(Span &span, nostd::string_view name, core::SystemTimestamp timestamp) noexcept + { + AddEvent(span, name, timestamp, common::NullKeyValueIterable()); + }; + + /// + /// Add event data to span associated with tracer + /// + /// + /// + void AddEvent(Span &span, nostd::string_view name) + { + AddEvent(span, name, std::chrono::system_clock::now(), common::NullKeyValueIterable()); + }; + + virtual ~Tracer() { CloseWithMicroseconds(0); }; +}; + +/// +/// stream::Span allows to send event data to stream +/// +class Span : public trace::Span +{ + +protected: + /// + /// Parent (Owner) Tracer of this Span + /// + Tracer &owner; + +public: + /// + /// Span constructor + /// + /// Owner Tracer + /// Span name + /// Span options + /// Span + Span(Tracer &owner, nostd::string_view name, const trace::StartSpanOptions &options) noexcept + : trace::Span(), owner(owner) + { + UNREFERENCED_PARAMETER(name); + UNREFERENCED_PARAMETER(options); + }; + + ~Span() { End(); } + + /// + /// Add named event with no attributes + /// + /// + /// + virtual void AddEvent(nostd::string_view name) noexcept override { owner.AddEvent(*this, name); } + + /// + /// Add named event with custom timestamp + /// + /// + /// + /// + virtual void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override + { + owner.AddEvent(*this, name, timestamp); + } + + /// + /// Add named event with custom timestamp and attributes + /// + /// + /// + /// + /// + void AddEvent(nostd::string_view name, + core::SystemTimestamp timestamp, + const common::KeyValueIterable &attributes) noexcept override + { + owner.AddEvent(*this, name, timestamp, attributes); + } + + /// + /// Set Span status + /// + /// + /// + /// + virtual void SetStatus(trace::CanonicalCode code, + nostd::string_view description) noexcept override + { + // TODO: not implemented + UNREFERENCED_PARAMETER(code); + UNREFERENCED_PARAMETER(description); + }; + + // Sets an attribute on the Span. If the Span previously contained a mapping for + // the key, the old value is replaced. + virtual void SetAttribute(nostd::string_view key, + const common::AttributeValue &value) noexcept override + { + // TODO: not implemented + UNREFERENCED_PARAMETER(key); + UNREFERENCED_PARAMETER(value); + }; + + /// + /// Update Span name + /// + /// + /// + virtual void UpdateName(nostd::string_view name) noexcept override + { + // TODO: not implemented + UNREFERENCED_PARAMETER(name); + } + + /// + /// End Span + /// + /// + virtual void End(const trace::EndSpanOptions & = {}) noexcept override + { + // TODO: signal this to owner + } + + virtual trace::SpanContext GetContext() const noexcept + { + // TODO: not implemented + static trace::SpanContext nullContext; + return nullContext; + } + + /// + /// Check if Span is recording data + /// + /// + virtual bool IsRecording() const noexcept override + { + // TODO: not implemented + return true; + } + + virtual void SetToken(nostd::unique_ptr &&token) noexcept + { + // TODO: not implemented + UNREFERENCED_PARAMETER(token); + } + + /// + /// Get Owner tracer of this Span + /// + /// + trace::Tracer &tracer() const noexcept { return this->owner; }; +}; + +/// +/// stream::TraceProvider +/// +class TracerProvider : public trace::TracerProvider +{ +public: + /// + /// Obtain a Tracer of given type (name) and supply extra argument arg2 to it. + /// + /// Tracer Type + /// Tracer arguments + /// + virtual nostd::shared_ptr GetTracer(nostd::string_view name, + nostd::string_view args = "") + { + // TODO: describe possible args. Currently supported: + // "MSGPACK" - use MessagePack + // "XML" - use XML + // "ETW" - use 'classic' Trace Logging Dynamic manifest ETW event + // +#if defined(HAVE_NO_TLD) && defined(HAVE_MSGPACK) + ETWProvider::EventFormat evtFmt = ETWProvider::EventFormat::ETW_MSGPACK; +#else + ETWProvider::EventFormat evtFmt = ETWProvider::EventFormat::ETW_MANIFEST; +#endif + +#pragma warning(push) +#pragma warning(disable : 4307) /* Integral constant overflow - OK while computing hash */ + auto h = utils::hashCode(args.data()); + switch (h) + { + case CONST_HASHCODE(MSGPACK): + // nobrk + case CONST_HASHCODE(MsgPack): + // nobrk + case CONST_HASHCODE(MessagePack): + evtFmt = ETWProvider::EventFormat::ETW_MSGPACK; + break; + + case CONST_HASHCODE(XML): + // nobrk + case CONST_HASHCODE(xml): + evtFmt = ETWProvider::EventFormat::ETW_XML; + break; + + case CONST_HASHCODE(TLD): + // nobrk + case CONST_HASHCODE(tld): + // nobrk + evtFmt = ETWProvider::EventFormat::ETW_MANIFEST; + break; + + default: + break; + } +#pragma warning(pop) + return nostd::shared_ptr{new (std::nothrow) Tracer(*this, name, evtFmt)}; + } +}; + +class ETWSpanData final : public Recordable +{ + /** + * Get the trace id for this span + * @return the trace id for this span + */ + opentelemetry::trace::TraceId GetTraceId() const noexcept { return trace_id_; } + + /** + * Get the span id for this span + * @return the span id for this span + */ + opentelemetry::trace::SpanId GetSpanId() const noexcept { return span_id_; } + + /** + * Get the parent span id for this span + * @return the span id for this span's parent + */ + opentelemetry::trace::SpanId GetParentSpanId() const noexcept { return parent_span_id_; } + + /** + * Get the name for this span + * @return the name for this span + */ + opentelemetry::nostd::string_view GetName() const noexcept { return name_; } + + /** + * Get the status for this span + * @return the status for this span + */ + opentelemetry::trace::CanonicalCode GetStatus() const noexcept { return status_code_; } + + /** + * Get the status description for this span + * @return the description of the the status of this span + */ + opentelemetry::nostd::string_view GetDescription() const noexcept { return status_desc_; } + + /** + * Get the start time for this span + * @return the start time for this span + */ + opentelemetry::core::SystemTimestamp GetStartTime() const noexcept { return start_time_; } + + /** + * Get the duration for this span + * @return the duration for this span + */ + std::chrono::nanoseconds GetDuration() const noexcept { return duration_; } + + /** + * Get the attributes for this span + * @return the attributes for this span + */ + const std::unordered_map &GetAttributes() const noexcept + { + return attribute_map_.GetAttributes(); + } + + /** + * Get the events associated with this span + * @return the events associated with this span + */ + const std::vector &GetEvents() const noexcept { return events_; } + + /** + * Get the links associated with this span + * @return the links associated with this span + */ + const std::vector &GetLinks() const noexcept { return links_; } + + void SetIds(opentelemetry::trace::TraceId trace_id, + opentelemetry::trace::SpanId span_id, + opentelemetry::trace::SpanId parent_span_id) noexcept override + { + trace_id_ = trace_id; + span_id_ = span_id; + parent_span_id_ = parent_span_id; + } + + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept override + { + attribute_map_.SetAttribute(key, value); + } + + void AddEvent(nostd::string_view name, + core::SystemTimestamp timestamp, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override + { + // change as per ETW need + /*SpanDataEvent event(std::string(name), timestamp, attributes); + events_.push_back(event);*/ + } + + /*void AddLink(const opentelemetry::trace::SpanContext &span_context, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override + { + SpanDataLink link(span_context, attributes); + links_.push_back(link); + }*/ + + void SetStatus(opentelemetry::trace::CanonicalCode code, + nostd::string_view description) noexcept override + { + status_code_ = code; + status_desc_ = std::string(description); + } + + void SetName(nostd::string_view name) noexcept override { name_ = std::string(name); } + + void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept override + { + start_time_ = start_time; + } + + void SetDuration(std::chrono::nanoseconds duration) noexcept override { duration_ = duration; } + +private: + opentelemetry::trace::TraceId trace_id_; + opentelemetry::trace::SpanId span_id_; + opentelemetry::trace::SpanId parent_span_id_; + core::SystemTimestamp start_time_; + std::chrono::nanoseconds duration_{0}; + std::string name_; + opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; + std::string status_desc_; + AttributeMap attribute_map_; + TracerProvider tracer_provider_; + //std::vector events_; + //std::vector links_; +}; +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE From 697865817c7362ba9f624e9d5cbd3541f19213e4 Mon Sep 17 00:00:00 2001 From: mishal23 Date: Wed, 18 Nov 2020 21:48:45 +0530 Subject: [PATCH 03/20] Added ETWSpan child from Recordable and defined MakeRecordable function and added some tests adds unit tests and addresses the following review comments: - remove benchmark from gitmodules - fix formatter CI - fix bazel valgrind failing - remove prometheus from the PR - fix build --- ci/do_ci.sh | 20 +- exporters/etw/BUILD | 2 +- .../exporters/etw/etw_provider_exporter.h | 67 ++-- .../exporters/etw/etw_tracer_exporter.h | 375 +----------------- .../opentelemetry/exporters/etw/utils.h | 2 +- exporters/etw/src/etw_provider_exporter.cc | 2 +- exporters/etw/src/etw_tracer_exporter.cc | 2 +- exporters/etw/test/etw_tracer_test.cc | 44 ++ .../opentelemetry/sdk/trace/etw_data.h | 55 +-- 9 files changed, 138 insertions(+), 431 deletions(-) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 36708021ec..f4323ed5bc 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -112,30 +112,30 @@ EOF examples/plugin/load/load_plugin_example ${PLUGIN_DIR}/libexample_plugin.so /dev/null exit 0 elif [[ "$1" == "bazel.test" ]]; then - bazel build $BAZEL_OPTIONS //... - bazel test $BAZEL_TEST_OPTIONS //... + bazel build $BAZEL_OPTIONS -- //... -//exporters/etw/... + bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... exit 0 elif [[ "$1" == "bazel.legacy.test" ]]; then # we uses C++ future and async() function to test the Prometheus Exporter functionality, # that make this test always fail. ignore Prometheus exporter here. - bazel build $BAZEL_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... - bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... + bazel build $BAZEL_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... -//exporters/etw/... + bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... -//exporters/etw/... exit 0 elif [[ "$1" == "bazel.noexcept" ]]; then # there are some exceptions and error handling code from the Prometheus Client # that make this test always fail. ignore Prometheus exporter in the noexcept here. - bazel build --copt=-fno-exceptions $BAZEL_OPTIONS -- //... -//exporters/prometheus/... - bazel test --copt=-fno-exceptions $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... + bazel build --copt=-fno-exceptions $BAZEL_OPTIONS -- //... -//exporters/prometheus/... -//exporters/etw/... + bazel test --copt=-fno-exceptions $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... -//exporters/etw/... exit 0 elif [[ "$1" == "bazel.asan" ]]; then - bazel test --config=asan $BAZEL_TEST_OPTIONS //... + bazel test --config=asan $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... exit 0 elif [[ "$1" == "bazel.tsan" ]]; then - bazel test --config=tsan $BAZEL_TEST_OPTIONS //... + bazel test --config=tsan $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... exit 0 elif [[ "$1" == "bazel.valgrind" ]]; then - bazel build $BAZEL_OPTIONS //... - bazel test --run_under="/usr/bin/valgrind --leak-check=full --error-exitcode=1 --suppressions=\"${SRC_DIR}/ci/valgrind-suppressions\"" $BAZEL_TEST_OPTIONS //... + bazel build $BAZEL_OPTIONS -- //... -//exporters/etw/... + bazel test --run_under="/usr/bin/valgrind --leak-check=full --error-exitcode=1 --suppressions=\"${SRC_DIR}/ci/valgrind-suppressions\"" $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... exit 0 elif [[ "$1" == "benchmark" ]]; then [ -z "${BENCHMARK_DIR}" ] && export BENCHMARK_DIR=$HOME/benchmark diff --git a/exporters/etw/BUILD b/exporters/etw/BUILD index 0d86bc1e45..d67768c7b9 100644 --- a/exporters/etw/BUILD +++ b/exporters/etw/BUILD @@ -51,4 +51,4 @@ cc_test( ":etw_tracer_exporter", "@com_google_googletest//:gtest_main", ], -) \ No newline at end of file +) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h index 3bd517946d..0512ecc1d4 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -143,7 +143,8 @@ class ETWProvider { #ifdef HAVE_TLD // Register with TraceLoggingDynamic facility - dynamic manifest ETW events. - case EventFormat::ETW_MANIFEST: { + case EventFormat::ETW_MANIFEST: + { tld::ProviderMetadataBuilder> providerMetaBuilder( data.providerMetaVector); @@ -170,7 +171,8 @@ class ETWProvider #ifdef HAVE_MSGPACK // Register for MsgPack payload ETW events. - case EventFormat::ETW_MSGPACK: { + case EventFormat::ETW_MSGPACK: + { REGHANDLE hProvider = 0; if (EventRegister(&data.providerGuid, NULL, NULL, &hProvider) != ERROR_SUCCESS) { @@ -253,13 +255,15 @@ class ETWProvider { { "env_name", "Span" }, { "env_ver", "4.0" }, +<<<<<<< HEAD +======= +>>>>>>> 7afe098... adds unit tests and addresses the following review comments: // TODO: remove these fields. Provided for illustrative purposes only. { "env_cloud_role", "BusyWorker" }, { "env_cloud_roleInstance", "CY1SCH030021417" }, { "env_cloud_roleVer", "9.0.15289.2" }, // - // TODO: compute time in MessagePack-friendly format // TODO: should we consider uint64_t format with Unix timestamps for ELK stack? { "env_time", @@ -274,7 +278,6 @@ class ETWProvider { "env_dt_traceId", "6dcdae7b9b0c7643967d74ee54056178" }, { "env_dt_spanId", "5866c4322919e641" }, // - { "name", eventName }, { "kind", 0 }, { "startTime", @@ -296,49 +299,58 @@ class ETWProvider auto &value = kv.second; switch (value.index()) { - case common::AttributeType::TYPE_BOOL: { + case common::AttributeType::TYPE_BOOL: + { UINT8 temp = static_cast(nostd::get(value)); jObj[name] = temp; break; } - case common::AttributeType::TYPE_INT: { + case common::AttributeType::TYPE_INT: + { auto temp = nostd::get(value); jObj[name] = temp; break; } - case common::AttributeType::TYPE_INT64: { + case common::AttributeType::TYPE_INT64: + { auto temp = nostd::get(value); jObj[name] = temp; break; } - case common::AttributeType::TYPE_UINT: { + case common::AttributeType::TYPE_UINT: + { auto temp = nostd::get(value); jObj[name] = temp; break; } - case common::AttributeType::TYPE_UINT64: { + case common::AttributeType::TYPE_UINT64: + { auto temp = nostd::get(value); jObj[name] = temp; break; } - case common::AttributeType::TYPE_DOUBLE: { + case common::AttributeType::TYPE_DOUBLE: + { auto temp = nostd::get(value); jObj[name] = temp; break; } - case common::AttributeType::TYPE_STRING: { + case common::AttributeType::TYPE_STRING: + { auto temp = nostd::get(value); jObj[name] = temp; break; } - case common::AttributeType::TYPE_CSTRING: { + case common::AttributeType::TYPE_CSTRING: + { auto temp = nostd::get(value); jObj[name] = temp; break; } # if HAVE_TYPE_GUID // TODO: consider adding UUID/GUID to spec - case common::AttributeType::TYPE_GUID: { + case common::AttributeType::TYPE_GUID: + { auto temp = nostd::get(value); // TODO: add transform from GUID type to string? jObj[name] = temp; @@ -487,49 +499,57 @@ class ETWProvider auto &value = kv.second; switch (value.index()) { - case common::AttributeType::TYPE_BOOL: { + case common::AttributeType::TYPE_BOOL: + { builder.AddField(name, tld::TypeBool8); UINT8 temp = static_cast(nostd::get(value)); dbuilder.AddByte(temp); break; } - case common::AttributeType::TYPE_INT: { + case common::AttributeType::TYPE_INT: + { builder.AddField(name, tld::TypeInt32); auto temp = nostd::get(value); dbuilder.AddValue(temp); break; } - case common::AttributeType::TYPE_INT64: { + case common::AttributeType::TYPE_INT64: + { builder.AddField(name, tld::TypeInt64); auto temp = nostd::get(value); dbuilder.AddValue(temp); break; } - case common::AttributeType::TYPE_UINT: { + case common::AttributeType::TYPE_UINT: + { builder.AddField(name, tld::TypeUInt32); auto temp = nostd::get(value); dbuilder.AddValue(temp); break; } - case common::AttributeType::TYPE_UINT64: { + case common::AttributeType::TYPE_UINT64: + { builder.AddField(name, tld::TypeUInt64); auto temp = nostd::get(value); dbuilder.AddValue(temp); break; } - case common::AttributeType::TYPE_DOUBLE: { + case common::AttributeType::TYPE_DOUBLE: + { builder.AddField(name, tld::TypeDouble); auto temp = nostd::get(value); dbuilder.AddValue(temp); break; } - case common::AttributeType::TYPE_STRING: { + case common::AttributeType::TYPE_STRING: + { builder.AddField(name, tld::TypeUtf8String); auto temp = nostd::get(value); dbuilder.AddString(temp.data()); break; } - case common::AttributeType::TYPE_CSTRING: { + case common::AttributeType::TYPE_CSTRING: + { builder.AddField(name, tld::TypeUtf8String); auto temp = nostd::get(value); dbuilder.AddString(temp); @@ -538,7 +558,8 @@ class ETWProvider # if HAVE_TYPE_GUID // TODO: consider adding UUID/GUID to spec - case common::AttributeType::TYPE_GUID: { + case common::AttributeType::TYPE_GUID: + { builder.AddField(name.c_str(), TypeGuid); auto temp = nostd::get(value); dbuilder.AddBytes(&temp, sizeof(GUID)); @@ -641,4 +662,4 @@ class ETWProvider }; }; -OPENTELEMETRY_END_NAMESPACE \ No newline at end of file +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h index 364c3ad914..5b3f35ac6a 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -11,7 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - #pragma once #include @@ -33,7 +32,7 @@ #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/recordable.h" -#include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/sdk/trace/etw_data.h" #include #include @@ -54,360 +53,6 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace ETW { -class Span; - -/// -/// stream::Tracer class that allows to send spans to ETW -/// -class Tracer : public trace::Tracer -{ - /// - /// Parent provider of this Tracer - /// - trace::TracerProvider &parent; - - /// - /// Provider Id (Name or GUID) - /// - std::string provId; - - /// - /// Provider Handle - /// - ETWProvider::Handle provHandle; - - /// - /// Encoding (Manifest, MessagePack or XML) - /// - ETWProvider::EventFormat encoding; - - /// - /// ETWProvider is a singleton that aggregates all ETW writes. - /// - /// - static ETWProvider &etwProvider() - { - static ETWProvider instance; // C++11 magic static - return instance; - }; - -public: - /// - /// Tracer constructor - /// - /// Parent TraceProvider - /// providerId - /// Tracer instance - Tracer(trace::TracerProvider &parent, - nostd::string_view providerId = "", - ETWProvider::EventFormat encoding = ETWProvider::EventFormat::ETW_MANIFEST) - : trace::Tracer(), - parent(parent), - provId(providerId.data(), providerId.size()), - encoding(encoding) - { - provHandle = etwProvider().open(provId, encoding); - }; - - /// - /// Start Span - /// - /// Span name - /// Span options - /// Span - virtual nostd::shared_ptr StartSpan( - nostd::string_view name, - const common::KeyValueIterable &attributes, - const trace::SpanContextKeyValueIterable &links, - const trace::StartSpanOptions &options = {}) noexcept override - { - // TODO: support attributes - UNREFERENCED_PARAMETER(attributes); - UNREFERENCED_PARAMETER(links); - return trace::to_span_ptr(this, name, options); - }; - - /// - /// Force flush data to Tracer, spending up to given amount of microseconds to flush. - /// - /// Allow Tracer to drop data if timeout is reached - /// void - virtual void ForceFlushWithMicroseconds(uint64_t) noexcept override{}; - - /// - /// Close tracer, spending up to given amount of microseconds to flush and close. - /// - /// Allow Tracer to drop data if timeout is reached - /// - virtual void CloseWithMicroseconds(uint64_t) noexcept override - { - etwProvider().close(provHandle); - }; - - /// - /// Add event data to span associated with tracer - /// - /// - /// - /// - /// - /// - void AddEvent(Span &span, - nostd::string_view name, - core::SystemTimestamp timestamp, - const common::KeyValueIterable &attributes) noexcept - { - // TODO: associate events with span - (void)span; - // TODO: respect original timestamp - (void)timestamp; - - // Unfortunately we copy right now since we don't have the knowledge of original map object :-( - std::map m; - attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { - m[key] = value; - return true; - }); - m["name"] = name.data(); - -#ifdef HAVE_TLD - if (encoding == ETWProvider::ETW_MANIFEST) - { - etwProvider().writeTld(provHandle, m); - return; - } -#endif - -#ifdef HAVE_MSGPACK - if (encoding == ETWProvider::ETW_MSGPACK) - { - etwProvider().writeMsgPack(provHandle, m); - return; - } -#endif - }; - - /// - /// Add event data to span associated with tracer - /// - /// - /// - /// - /// - void AddEvent(Span &span, nostd::string_view name, core::SystemTimestamp timestamp) noexcept - { - AddEvent(span, name, timestamp, common::NullKeyValueIterable()); - }; - - /// - /// Add event data to span associated with tracer - /// - /// - /// - void AddEvent(Span &span, nostd::string_view name) - { - AddEvent(span, name, std::chrono::system_clock::now(), common::NullKeyValueIterable()); - }; - - virtual ~Tracer() { CloseWithMicroseconds(0); }; -}; - -/// -/// stream::Span allows to send event data to stream -/// -class Span : public trace::Span -{ - -protected: - /// - /// Parent (Owner) Tracer of this Span - /// - Tracer &owner; - -public: - /// - /// Span constructor - /// - /// Owner Tracer - /// Span name - /// Span options - /// Span - Span(Tracer &owner, nostd::string_view name, const trace::StartSpanOptions &options) noexcept - : trace::Span(), owner(owner) - { - UNREFERENCED_PARAMETER(name); - UNREFERENCED_PARAMETER(options); - }; - - ~Span() { End(); } - - /// - /// Add named event with no attributes - /// - /// - /// - virtual void AddEvent(nostd::string_view name) noexcept override { owner.AddEvent(*this, name); } - - /// - /// Add named event with custom timestamp - /// - /// - /// - /// - virtual void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override - { - owner.AddEvent(*this, name, timestamp); - } - - /// - /// Add named event with custom timestamp and attributes - /// - /// - /// - /// - /// - void AddEvent(nostd::string_view name, - core::SystemTimestamp timestamp, - const common::KeyValueIterable &attributes) noexcept override - { - owner.AddEvent(*this, name, timestamp, attributes); - } - - /// - /// Set Span status - /// - /// - /// - /// - virtual void SetStatus(trace::CanonicalCode code, - nostd::string_view description) noexcept override - { - // TODO: not implemented - UNREFERENCED_PARAMETER(code); - UNREFERENCED_PARAMETER(description); - }; - - // Sets an attribute on the Span. If the Span previously contained a mapping for - // the key, the old value is replaced. - virtual void SetAttribute(nostd::string_view key, - const common::AttributeValue &value) noexcept override - { - // TODO: not implemented - UNREFERENCED_PARAMETER(key); - UNREFERENCED_PARAMETER(value); - }; - - /// - /// Update Span name - /// - /// - /// - virtual void UpdateName(nostd::string_view name) noexcept override - { - // TODO: not implemented - UNREFERENCED_PARAMETER(name); - } - - /// - /// End Span - /// - /// - virtual void End(const trace::EndSpanOptions & = {}) noexcept override - { - // TODO: signal this to owner - } - - virtual trace::SpanContext GetContext() const noexcept - { - // TODO: not implemented - static trace::SpanContext nullContext; - return nullContext; - } - - /// - /// Check if Span is recording data - /// - /// - virtual bool IsRecording() const noexcept override - { - // TODO: not implemented - return true; - } - - virtual void SetToken(nostd::unique_ptr &&token) noexcept - { - // TODO: not implemented - UNREFERENCED_PARAMETER(token); - } - - /// - /// Get Owner tracer of this Span - /// - /// - trace::Tracer &tracer() const noexcept { return this->owner; }; -}; - - -/// -/// stream::TraceProvider -/// -class TracerProvider : public trace::TracerProvider -{ -public: - /// - /// Obtain a Tracer of given type (name) and supply extra argument arg2 to it. - /// - /// Tracer Type - /// Tracer arguments - /// - virtual nostd::shared_ptr GetTracer(nostd::string_view name, - nostd::string_view args = "") - { - // TODO: describe possible args. Currently supported: - // "MSGPACK" - use MessagePack - // "XML" - use XML - // "ETW" - use 'classic' Trace Logging Dynamic manifest ETW event - // -#if defined(HAVE_NO_TLD) && defined(HAVE_MSGPACK) - ETWProvider::EventFormat evtFmt = ETWProvider::EventFormat::ETW_MSGPACK; -#else - ETWProvider::EventFormat evtFmt = ETWProvider::EventFormat::ETW_MANIFEST; -#endif - -#pragma warning(push) -#pragma warning(disable : 4307) /* Integral constant overflow - OK while computing hash */ - auto h = utils::hashCode(args.data()); - switch (h) - { - case CONST_HASHCODE(MSGPACK): - // nobrk - case CONST_HASHCODE(MsgPack): - // nobrk - case CONST_HASHCODE(MessagePack): - evtFmt = ETWProvider::EventFormat::ETW_MSGPACK; - break; - - case CONST_HASHCODE(XML): - // nobrk - case CONST_HASHCODE(xml): - evtFmt = ETWProvider::EventFormat::ETW_XML; - break; - - case CONST_HASHCODE(TLD): - // nobrk - case CONST_HASHCODE(tld): - // nobrk - evtFmt = ETWProvider::EventFormat::ETW_MANIFEST; - break; - - default: - break; - } -#pragma warning(pop) - return nostd::shared_ptr{new (std::nothrow) Tracer(*this, name, evtFmt)}; - } -}; - class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter { public: @@ -415,7 +60,7 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter * @param providerName * @param eventName */ - ETWTracerExporter(std::string providerName, std::string eventName): providerName_(providerName), eventName_(eventName) + ETWTracerExporter(std::string providerName): providerName_(providerName) { } @@ -424,8 +69,7 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter */ std::unique_ptr MakeRecordable() noexcept override { - // TODO: Discuss how we want to make the Recordable - //return std::unique_ptr(new TracerProvider()); + return std::unique_ptr(new sdk::trace::ETWSpanData(providerName_)); } /** @@ -438,14 +82,11 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter { for (auto &recordable : recordables) { - auto tp = std::unique_ptr( - dynamic_cast(recordable.release())); - if (tp != nullptr) + auto span = std::unique_ptr( + dynamic_cast(recordable.release())); + if (span != nullptr) { - auto tracer = tp->GetTracer(providerName_); - auto span = tracer->StartSpan("MySpan"); - - // do whatever is needed + std::cout << span->GetName() << std::endl; } } @@ -461,7 +102,7 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter private: std::string providerName_; - std::string eventName_; + std::shared_ptr data_; }; } // namespace ETW diff --git a/exporters/etw/include/opentelemetry/exporters/etw/utils.h b/exporters/etw/include/opentelemetry/exporters/etw/utils.h index 63f81f569e..3238245e09 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/utils.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -206,4 +206,4 @@ static inline GUID GetProviderGuid(const char *providerName) }; // namespace utils -OPENTELEMETRY_END_NAMESPACE \ No newline at end of file +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/src/etw_provider_exporter.cc b/exporters/etw/src/etw_provider_exporter.cc index 124f775d70..f14d64df79 100644 --- a/exporters/etw/src/etw_provider_exporter.cc +++ b/exporters/etw/src/etw_provider_exporter.cc @@ -1,3 +1,3 @@ #define HAVE_NO_TLD -#include "opentelemetry/exporters/etw/etw_provider_exporter.h" \ No newline at end of file +#include "opentelemetry/exporters/etw/etw_provider_exporter.h" diff --git a/exporters/etw/src/etw_tracer_exporter.cc b/exporters/etw/src/etw_tracer_exporter.cc index 9045731a94..3861ae3638 100644 --- a/exporters/etw/src/etw_tracer_exporter.cc +++ b/exporters/etw/src/etw_tracer_exporter.cc @@ -1,3 +1,3 @@ #define HAVE_NO_TLD -#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" \ No newline at end of file +#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index aa526c4e28..8529143b85 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -18,6 +18,7 @@ #define HAVE_NO_TLD #include "opentelemetry/exporters/etw/etw_tracer_exporter.h" +#include "opentelemetry/sdk/trace/simple_processor.h" using namespace OPENTELEMETRY_NAMESPACE; @@ -39,3 +40,46 @@ TEST(ETWTracer, TracerCheck) EXPECT_NO_THROW(span->End()); EXPECT_NO_THROW(tracer->Close()); } + +TEST(ETWTracer, ETWTracerTest) +{ + std::string providerName = "OpenTelemetry"; + + auto exporter = std::unique_ptr(new ETW::ETWTracerExporter(providerName)); + + auto processor = std::shared_ptr(new sdk::trace::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + recordable->SetName("MySpan"); + + // Create stringstream to redirect to + std::stringstream stdoutOutput; + + // Save cout's buffer here + std::streambuf *sbuf = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::cout.rdbuf(stdoutOutput.rdbuf()); + + processor->OnEnd(std::move(recordable)); + + std::cout.rdbuf(sbuf); + + std::string expectedOutput = "MySpan\n"; + + ASSERT_EQ(stdoutOutput.str(), expectedOutput); +} + +TEST(ETWTracer, ExportUnitTest) +{ + std::string providerName = "OpenTelemetry"; + + auto exporter = std::unique_ptr(new ETW::ETWTracerExporter(providerName)); + + auto recordable = exporter->MakeRecordable(); + recordable->SetName("MySpan"); + + nostd::span> batch(&recordable, 1); + auto result = exporter->Export(batch); + EXPECT_EQ(sdk::trace::ExportResult::kSuccess, result); +} diff --git a/sdk/include/opentelemetry/sdk/trace/etw_data.h b/sdk/include/opentelemetry/sdk/trace/etw_data.h index 555bfd6e7c..fa08c16710 100644 --- a/sdk/include/opentelemetry/sdk/trace/etw_data.h +++ b/sdk/include/opentelemetry/sdk/trace/etw_data.h @@ -37,11 +37,9 @@ namespace core = opentelemetry::core; namespace trace = opentelemetry::trace; OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace trace -{ +namespace ETW +{ class Span; /// @@ -394,9 +392,20 @@ class TracerProvider : public trace::TracerProvider return nostd::shared_ptr{new (std::nothrow) Tracer(*this, name, evtFmt)}; } }; - +} + +namespace sdk +{ +namespace trace +{ + class ETWSpanData final : public Recordable { +public: + ETWSpanData(std::string providerName) + { + InitTracerProvider(providerName); + } /** * Get the trace id for this span * @return the trace id for this span @@ -454,18 +463,6 @@ class ETWSpanData final : public Recordable return attribute_map_.GetAttributes(); } - /** - * Get the events associated with this span - * @return the events associated with this span - */ - const std::vector &GetEvents() const noexcept { return events_; } - - /** - * Get the links associated with this span - * @return the links associated with this span - */ - const std::vector &GetLinks() const noexcept { return links_; } - void SetIds(opentelemetry::trace::TraceId trace_id, opentelemetry::trace::SpanId span_id, opentelemetry::trace::SpanId parent_span_id) noexcept override @@ -485,17 +482,14 @@ class ETWSpanData final : public Recordable core::SystemTimestamp timestamp, const opentelemetry::common::KeyValueIterable &attributes) noexcept override { - // change as per ETW need - /*SpanDataEvent event(std::string(name), timestamp, attributes); - events_.push_back(event);*/ + span_->AddEvent(name, timestamp, attributes); } - /*void AddLink(const opentelemetry::trace::SpanContext &span_context, + void AddLink(const opentelemetry::trace::SpanContext &span_context, const opentelemetry::common::KeyValueIterable &attributes) noexcept override { - SpanDataLink link(span_context, attributes); - links_.push_back(link); - }*/ + // TODO: Link Implementation for the Span to be implemented + } void SetStatus(opentelemetry::trace::CanonicalCode code, nostd::string_view description) noexcept override @@ -513,6 +507,14 @@ class ETWSpanData final : public Recordable void SetDuration(std::chrono::nanoseconds duration) noexcept override { duration_ = duration; } + void InitTracerProvider(std::string providerName) + { + ETW::TracerProvider tracer_provider_; + + tracer_ = tracer_provider_.GetTracer(providerName); + span_ = tracer_->StartSpan(name_); + } + private: opentelemetry::trace::TraceId trace_id_; opentelemetry::trace::SpanId span_id_; @@ -523,9 +525,8 @@ class ETWSpanData final : public Recordable opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; AttributeMap attribute_map_; - TracerProvider tracer_provider_; - //std::vector events_; - //std::vector links_; + nostd::shared_ptr tracer_; + nostd::shared_ptr span_; }; } // namespace trace } // namespace sdk From 3787b6afba81301f68d3f25288aec474a8c7229c Mon Sep 17 00:00:00 2001 From: mishal23 Date: Sun, 29 Nov 2020 15:35:03 +0530 Subject: [PATCH 04/20] replace NullKeyValueIterable with GetEmptyAttributes, use existing Close method, address some review comments --- api/include/opentelemetry/trace/tracer.h | 6 ------ .../opentelemetry/exporters/etw/etw_provider_exporter.h | 8 -------- exporters/etw/test/etw_tracer_test.cc | 2 +- sdk/include/opentelemetry/sdk/trace/etw_data.h | 4 ++-- 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/api/include/opentelemetry/trace/tracer.h b/api/include/opentelemetry/trace/tracer.h index e6a252f4a5..09cf389d8b 100644 --- a/api/include/opentelemetry/trace/tracer.h +++ b/api/include/opentelemetry/trace/tracer.h @@ -179,12 +179,6 @@ class Tracer static_cast(std::chrono::duration_cast(timeout))); } - void Close() noexcept - { - /* TODO: respect timeout from TracerOptions? */ - CloseWithMicroseconds(0); - } - virtual void CloseWithMicroseconds(uint64_t timeout) noexcept = 0; }; } // namespace trace diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h index 0512ecc1d4..683799b745 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -255,14 +255,6 @@ class ETWProvider { { "env_name", "Span" }, { "env_ver", "4.0" }, -<<<<<<< HEAD -======= - ->>>>>>> 7afe098... adds unit tests and addresses the following review comments: - // TODO: remove these fields. Provided for illustrative purposes only. - { "env_cloud_role", "BusyWorker" }, - { "env_cloud_roleInstance", "CY1SCH030021417" }, - { "env_cloud_roleVer", "9.0.15289.2" }, // // TODO: compute time in MessagePack-friendly format // TODO: should we consider uint64_t format with Unix timestamps for ELK stack? diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index 8529143b85..c5a1e03600 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -38,7 +38,7 @@ TEST(ETWTracer, TracerCheck) EXPECT_NO_THROW(span->AddEvent(eventName, event)); EXPECT_NO_THROW(span->End()); - EXPECT_NO_THROW(tracer->Close()); + EXPECT_NO_THROW(tracer->CloseWithMicroseconds(0)); } TEST(ETWTracer, ETWTracerTest) diff --git a/sdk/include/opentelemetry/sdk/trace/etw_data.h b/sdk/include/opentelemetry/sdk/trace/etw_data.h index fa08c16710..6c3c5388a6 100644 --- a/sdk/include/opentelemetry/sdk/trace/etw_data.h +++ b/sdk/include/opentelemetry/sdk/trace/etw_data.h @@ -182,7 +182,7 @@ class Tracer : public trace::Tracer /// void AddEvent(Span &span, nostd::string_view name, core::SystemTimestamp timestamp) noexcept { - AddEvent(span, name, timestamp, common::NullKeyValueIterable()); + AddEvent(span, name, timestamp, opentelemetry::sdk::GetEmptyAttributes()); }; /// @@ -192,7 +192,7 @@ class Tracer : public trace::Tracer /// void AddEvent(Span &span, nostd::string_view name) { - AddEvent(span, name, std::chrono::system_clock::now(), common::NullKeyValueIterable()); + AddEvent(span, name, std::chrono::system_clock::now(), opentelemetry::sdk::GetEmptyAttributes()); }; virtual ~Tracer() { CloseWithMicroseconds(0); }; From aaa949ecd0aaad31e8655718dd5487289b03ba24 Mon Sep 17 00:00:00 2001 From: mishal23 Date: Sun, 29 Nov 2020 17:51:22 +0530 Subject: [PATCH 05/20] removed Invalid Span Context, fix formatter issues --- api/include/opentelemetry/trace/span_context.h | 4 ---- exporters/etw/CMakeLists.txt | 12 ++++++++---- .../exporters/etw/etw_tracer_exporter.h | 10 ++++------ exporters/etw/src/etw_provider_exporter.cc | 2 +- exporters/etw/src/etw_tracer_exporter.cc | 2 +- exporters/etw/test/etw_tracer_test.cc | 3 ++- sdk/include/opentelemetry/sdk/trace/etw_data.h | 13 +++++-------- 7 files changed, 21 insertions(+), 25 deletions(-) diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h index 6cf125bb15..6add265eed 100644 --- a/api/include/opentelemetry/trace/span_context.h +++ b/api/include/opentelemetry/trace/span_context.h @@ -33,10 +33,6 @@ namespace trace_api = opentelemetry::trace; class SpanContext final { public: - // An invalid SpanContext. - SpanContext() noexcept - : trace_flags_(trace::TraceFlags((uint8_t) false)), remote_parent_(false){}; - /* A temporary constructor for an invalid SpanContext. * Trace id and span id are set to invalid (all zeros). * diff --git a/exporters/etw/CMakeLists.txt b/exporters/etw/CMakeLists.txt index 8432f06131..a3d02e6f35 100644 --- a/exporters/etw/CMakeLists.txt +++ b/exporters/etw/CMakeLists.txt @@ -15,8 +15,12 @@ if(BUILD_TESTING) etw_tracer_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_exporter_etw_tracer) - gtest_add_tests(TARGET etw_provider_test TEST_PREFIX exporter. TEST_LIST - etw_provider_test) - gtest_add_tests(TARGET etw_tracer_test TEST_PREFIX exporter. TEST_LIST - etw_tracer_test) + gtest_add_tests( + TARGET etw_provider_test + TEST_PREFIX exporter. + TEST_LIST etw_provider_test) + gtest_add_tests( + TARGET etw_tracer_test + TEST_PREFIX exporter. + TEST_LIST etw_tracer_test) endif() # BUILD_TESTING diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h index 5b3f35ac6a..bf635c3514 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -25,14 +25,14 @@ #include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context_kv_iterable_view.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" #include "opentelemetry/trace/tracer_provider.h" -#include "opentelemetry/trace/span_context_kv_iterable_view.h" +#include "opentelemetry/sdk/trace/etw_data.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/recordable.h" -#include "opentelemetry/sdk/trace/etw_data.h" #include #include @@ -60,9 +60,7 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter * @param providerName * @param eventName */ - ETWTracerExporter(std::string providerName): providerName_(providerName) - { - } + ETWTracerExporter(std::string providerName) : providerName_(providerName) {} /** * @return Returns a unique pointer to an empty recordable object @@ -105,6 +103,6 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter std::shared_ptr data_; }; -} // namespace ETW +} // namespace ETW OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/src/etw_provider_exporter.cc b/exporters/etw/src/etw_provider_exporter.cc index f14d64df79..1ad02ca149 100644 --- a/exporters/etw/src/etw_provider_exporter.cc +++ b/exporters/etw/src/etw_provider_exporter.cc @@ -1,3 +1,3 @@ -#define HAVE_NO_TLD +#define HAVE_NO_TLD #include "opentelemetry/exporters/etw/etw_provider_exporter.h" diff --git a/exporters/etw/src/etw_tracer_exporter.cc b/exporters/etw/src/etw_tracer_exporter.cc index 3861ae3638..a6798c6a08 100644 --- a/exporters/etw/src/etw_tracer_exporter.cc +++ b/exporters/etw/src/etw_tracer_exporter.cc @@ -1,3 +1,3 @@ -#define HAVE_NO_TLD +#define HAVE_NO_TLD #include "opentelemetry/exporters/etw/etw_tracer_exporter.h" diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index c5a1e03600..0755a065c9 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -47,7 +47,8 @@ TEST(ETWTracer, ETWTracerTest) auto exporter = std::unique_ptr(new ETW::ETWTracerExporter(providerName)); - auto processor = std::shared_ptr(new sdk::trace::SimpleSpanProcessor(std::move(exporter))); + auto processor = std::shared_ptr( + new sdk::trace::SimpleSpanProcessor(std::move(exporter))); auto recordable = processor->MakeRecordable(); recordable->SetName("MySpan"); diff --git a/sdk/include/opentelemetry/sdk/trace/etw_data.h b/sdk/include/opentelemetry/sdk/trace/etw_data.h index 6c3c5388a6..5081f03cf7 100644 --- a/sdk/include/opentelemetry/sdk/trace/etw_data.h +++ b/sdk/include/opentelemetry/sdk/trace/etw_data.h @@ -20,7 +20,6 @@ #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/recordable.h" #include "opentelemetry/sdk/trace/span_data.h" -#include "opentelemetry/sdk/trace/recordable.h" #include #include @@ -192,7 +191,8 @@ class Tracer : public trace::Tracer /// void AddEvent(Span &span, nostd::string_view name) { - AddEvent(span, name, std::chrono::system_clock::now(), opentelemetry::sdk::GetEmptyAttributes()); + AddEvent(span, name, std::chrono::system_clock::now(), + opentelemetry::sdk::GetEmptyAttributes()); }; virtual ~Tracer() { CloseWithMicroseconds(0); }; @@ -306,7 +306,7 @@ class Span : public trace::Span virtual trace::SpanContext GetContext() const noexcept { // TODO: not implemented - static trace::SpanContext nullContext; + static trace::SpanContext nullContext{trace::SpanContext::GetInvalid()}; return nullContext; } @@ -392,7 +392,7 @@ class TracerProvider : public trace::TracerProvider return nostd::shared_ptr{new (std::nothrow) Tracer(*this, name, evtFmt)}; } }; -} +} // namespace ETW namespace sdk { @@ -402,10 +402,7 @@ namespace trace class ETWSpanData final : public Recordable { public: - ETWSpanData(std::string providerName) - { - InitTracerProvider(providerName); - } + ETWSpanData(std::string providerName) { InitTracerProvider(providerName); } /** * Get the trace id for this span * @return the trace id for this span From e8c0cf305b140676f436d7e6a80817d68add08a9 Mon Sep 17 00:00:00 2001 From: mishal23 Date: Sun, 13 Dec 2020 18:37:38 +0530 Subject: [PATCH 06/20] add spankind method, return in shutdown method --- .../opentelemetry/exporters/etw/etw_tracer_exporter.h | 6 ++++-- sdk/include/opentelemetry/sdk/trace/etw_data.h | 6 ++++++ sdk/include/opentelemetry/sdk/trace/processor.h | 4 ++-- sdk/include/opentelemetry/sdk/trace/simple_processor.h | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h index bf635c3514..65cb4cf00f 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -95,8 +95,10 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter * @param timeout an optional value containing the timeout of the exporter * note: passing custom timeout values is not currently supported for this exporter */ - void Shutdown( - std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override{}; + bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override + { + return true; + }; private: std::string providerName_; diff --git a/sdk/include/opentelemetry/sdk/trace/etw_data.h b/sdk/include/opentelemetry/sdk/trace/etw_data.h index 5081f03cf7..46db7526a6 100644 --- a/sdk/include/opentelemetry/sdk/trace/etw_data.h +++ b/sdk/include/opentelemetry/sdk/trace/etw_data.h @@ -497,6 +497,11 @@ class ETWSpanData final : public Recordable void SetName(nostd::string_view name) noexcept override { name_ = std::string(name); } + void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override + { + span_kind_ = span_kind; + } + void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept override { start_time_ = start_time; @@ -522,6 +527,7 @@ class ETWSpanData final : public Recordable opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; AttributeMap attribute_map_; + opentelemetry::trace::SpanKind span_kind_{opentelemetry::trace::SpanKind::kInternal}; nostd::shared_ptr tracer_; nostd::shared_ptr span_; }; diff --git a/sdk/include/opentelemetry/sdk/trace/processor.h b/sdk/include/opentelemetry/sdk/trace/processor.h index 060f4c7ebb..f1ef6ca6d0 100644 --- a/sdk/include/opentelemetry/sdk/trace/processor.h +++ b/sdk/include/opentelemetry/sdk/trace/processor.h @@ -47,7 +47,7 @@ class SpanProcessor * timeout is applied. */ virtual bool ForceFlush( - std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0; + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept = 0; /** * Shut down the processor and do any cleanup required. Ended spans are @@ -58,7 +58,7 @@ class SpanProcessor * timeout is applied. */ virtual bool Shutdown( - std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0; + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept = 0; }; } // namespace trace } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/trace/simple_processor.h b/sdk/include/opentelemetry/sdk/trace/simple_processor.h index 7ad5848c07..739c541866 100644 --- a/sdk/include/opentelemetry/sdk/trace/simple_processor.h +++ b/sdk/include/opentelemetry/sdk/trace/simple_processor.h @@ -51,13 +51,13 @@ class SimpleSpanProcessor : public SpanProcessor } bool ForceFlush( - std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override { return true; } bool Shutdown( - std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override { // We only call shutdown ONCE. if (exporter_ != nullptr && !shutdown_latch_.test_and_set(std::memory_order_acquire)) From faaf5c000f6094b927cbc874eb9695c5e674e403 Mon Sep 17 00:00:00 2001 From: mishal23 Date: Sat, 19 Dec 2020 16:13:08 +0530 Subject: [PATCH 07/20] move etw_data to exporters/etw, wrap modules with if _WIN32 --- ci/do_ci.sh | 20 +++++++++---------- exporters/etw/BUILD | 1 + .../opentelemetry/exporters/etw}/etw_data.h | 0 .../exporters/etw/etw_tracer_exporter.h | 2 +- exporters/etw/src/etw_provider_exporter.cc | 8 ++++++-- exporters/etw/src/etw_tracer_exporter.cc | 8 ++++++-- exporters/etw/test/etw_provider_test.cc | 12 +++++++---- exporters/etw/test/etw_tracer_test.cc | 14 ++++++++----- 8 files changed, 41 insertions(+), 24 deletions(-) rename {sdk/include/opentelemetry/sdk/trace => exporters/etw/include/opentelemetry/exporters/etw}/etw_data.h (100%) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index f4323ed5bc..36708021ec 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -112,30 +112,30 @@ EOF examples/plugin/load/load_plugin_example ${PLUGIN_DIR}/libexample_plugin.so /dev/null exit 0 elif [[ "$1" == "bazel.test" ]]; then - bazel build $BAZEL_OPTIONS -- //... -//exporters/etw/... - bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... + bazel build $BAZEL_OPTIONS //... + bazel test $BAZEL_TEST_OPTIONS //... exit 0 elif [[ "$1" == "bazel.legacy.test" ]]; then # we uses C++ future and async() function to test the Prometheus Exporter functionality, # that make this test always fail. ignore Prometheus exporter here. - bazel build $BAZEL_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... -//exporters/etw/... - bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... -//exporters/etw/... + bazel build $BAZEL_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... + bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... exit 0 elif [[ "$1" == "bazel.noexcept" ]]; then # there are some exceptions and error handling code from the Prometheus Client # that make this test always fail. ignore Prometheus exporter in the noexcept here. - bazel build --copt=-fno-exceptions $BAZEL_OPTIONS -- //... -//exporters/prometheus/... -//exporters/etw/... - bazel test --copt=-fno-exceptions $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... -//exporters/etw/... + bazel build --copt=-fno-exceptions $BAZEL_OPTIONS -- //... -//exporters/prometheus/... + bazel test --copt=-fno-exceptions $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... exit 0 elif [[ "$1" == "bazel.asan" ]]; then - bazel test --config=asan $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... + bazel test --config=asan $BAZEL_TEST_OPTIONS //... exit 0 elif [[ "$1" == "bazel.tsan" ]]; then - bazel test --config=tsan $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... + bazel test --config=tsan $BAZEL_TEST_OPTIONS //... exit 0 elif [[ "$1" == "bazel.valgrind" ]]; then - bazel build $BAZEL_OPTIONS -- //... -//exporters/etw/... - bazel test --run_under="/usr/bin/valgrind --leak-check=full --error-exitcode=1 --suppressions=\"${SRC_DIR}/ci/valgrind-suppressions\"" $BAZEL_TEST_OPTIONS -- //... -//exporters/etw/... + bazel build $BAZEL_OPTIONS //... + bazel test --run_under="/usr/bin/valgrind --leak-check=full --error-exitcode=1 --suppressions=\"${SRC_DIR}/ci/valgrind-suppressions\"" $BAZEL_TEST_OPTIONS //... exit 0 elif [[ "$1" == "benchmark" ]]; then [ -z "${BENCHMARK_DIR}" ] && export BENCHMARK_DIR=$HOME/benchmark diff --git a/exporters/etw/BUILD b/exporters/etw/BUILD index d67768c7b9..706eeba507 100644 --- a/exporters/etw/BUILD +++ b/exporters/etw/BUILD @@ -32,6 +32,7 @@ cc_library( "src/etw_tracer_exporter.cc", ], hdrs = [ + "include/opentelemetry/exporters/etw/etw_data.h", "include/opentelemetry/exporters/etw/etw_tracer_exporter.h", "include/opentelemetry/exporters/etw/utils.h", "include/opentelemetry/exporters/etw/uuid.hpp", diff --git a/sdk/include/opentelemetry/sdk/trace/etw_data.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h similarity index 100% rename from sdk/include/opentelemetry/sdk/trace/etw_data.h rename to exporters/etw/include/opentelemetry/exporters/etw/etw_data.h diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h index 65cb4cf00f..7253566621 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -30,7 +30,6 @@ #include "opentelemetry/trace/trace_id.h" #include "opentelemetry/trace/tracer_provider.h" -#include "opentelemetry/sdk/trace/etw_data.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/recordable.h" @@ -41,6 +40,7 @@ #include #include +#include "opentelemetry/exporters/etw/etw_data.h" #include "opentelemetry/exporters/etw/etw_provider_exporter.h" #include "opentelemetry/exporters/etw/utils.h" diff --git a/exporters/etw/src/etw_provider_exporter.cc b/exporters/etw/src/etw_provider_exporter.cc index 1ad02ca149..96be5b61d8 100644 --- a/exporters/etw/src/etw_provider_exporter.cc +++ b/exporters/etw/src/etw_provider_exporter.cc @@ -1,3 +1,7 @@ -#define HAVE_NO_TLD +#ifdef _WIN32 -#include "opentelemetry/exporters/etw/etw_provider_exporter.h" +# define HAVE_NO_TLD + +# include "opentelemetry/exporters/etw/etw_provider_exporter.h" + +#endif diff --git a/exporters/etw/src/etw_tracer_exporter.cc b/exporters/etw/src/etw_tracer_exporter.cc index a6798c6a08..21d38bb25e 100644 --- a/exporters/etw/src/etw_tracer_exporter.cc +++ b/exporters/etw/src/etw_tracer_exporter.cc @@ -1,3 +1,7 @@ -#define HAVE_NO_TLD +#ifdef _WIN32 -#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" +# define HAVE_NO_TLD + +# include "opentelemetry/exporters/etw/etw_tracer_exporter.h" + +#endif diff --git a/exporters/etw/test/etw_provider_test.cc b/exporters/etw/test/etw_provider_test.cc index 99fb88a638..b19a87b50c 100644 --- a/exporters/etw/test/etw_provider_test.cc +++ b/exporters/etw/test/etw_provider_test.cc @@ -12,12 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include +#ifdef _WIN32 -#define HAVE_NO_TLD +# include +# include -#include "opentelemetry/exporters/etw/etw_provider_exporter.h" +# define HAVE_NO_TLD + +# include "opentelemetry/exporters/etw/etw_provider_exporter.h" using namespace OPENTELEMETRY_NAMESPACE; @@ -69,3 +71,5 @@ TEST(ETWProvider, CheckCloseSuccess) auto result = etw.close(handle); ASSERT_NE(result, etw.STATUS_ERROR); } + +#endif diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index 0755a065c9..c623546c21 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -12,13 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include +#ifdef _WIN32 -#define HAVE_NO_TLD +# include +# include -#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" -#include "opentelemetry/sdk/trace/simple_processor.h" +# define HAVE_NO_TLD + +# include "opentelemetry/exporters/etw/etw_tracer_exporter.h" +# include "opentelemetry/sdk/trace/simple_processor.h" using namespace OPENTELEMETRY_NAMESPACE; @@ -84,3 +86,5 @@ TEST(ETWTracer, ExportUnitTest) auto result = exporter->Export(batch); EXPECT_EQ(sdk::trace::ExportResult::kSuccess, result); } + +#endif From 73cf5ec05c91e20d097e46d6c75b47a4bdaf2cc9 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 23 Dec 2020 15:45:31 -0800 Subject: [PATCH 08/20] Resolving code review comments --- .../exporters/etw/etw_provider_exporter.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h index 683799b745..daa43dec1c 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -241,9 +241,11 @@ class ETWProvider eventName = (char *)(nostd::get(nameField).data()); // must be 0-terminated! break; +# ifdef HAVE_CSTRING_TYPE case common::AttributeType::TYPE_CSTRING: eventName = (char *)(nostd::get(nameField)); break; +# endif default: // This is user error. Invalid event name! // We supply default 'NoName' event name in this case. @@ -333,12 +335,14 @@ class ETWProvider jObj[name] = temp; break; } +# ifdef HAVE_CSTRING_TYPE case common::AttributeType::TYPE_CSTRING: { auto temp = nostd::get(value); jObj[name] = temp; break; } +# endif # if HAVE_TYPE_GUID // TODO: consider adding UUID/GUID to spec case common::AttributeType::TYPE_GUID: @@ -350,8 +354,7 @@ class ETWProvider } # endif // TODO: arrays are not supported yet -# if 0 - // TODO: array of uint8_t is not supported by OT spec +# ifdef HAVE_SPAN_BYTE case common::AttributeType::TYPE_SPAN_BYTE: # endif case common::AttributeType::TYPE_SPAN_BOOL: @@ -471,9 +474,11 @@ class ETWProvider eventName = (char *)(nostd::get(nameField).data()); // must be 0-terminated! break; +# ifdef HAVE_CSTRING_TYPE case common::AttributeType::TYPE_CSTRING: eventName = (char *)(nostd::get(nameField)); break; +# endif default: // This is user error. Invalid event name! // We supply default 'NoName' event name in this case. @@ -540,6 +545,7 @@ class ETWProvider dbuilder.AddString(temp.data()); break; } +# ifdef HAVE_CSTRING_TYPE case common::AttributeType::TYPE_CSTRING: { builder.AddField(name, tld::TypeUtf8String); @@ -547,7 +553,7 @@ class ETWProvider dbuilder.AddString(temp); break; } - +# endif # if HAVE_TYPE_GUID // TODO: consider adding UUID/GUID to spec case common::AttributeType::TYPE_GUID: @@ -560,7 +566,7 @@ class ETWProvider # endif // TODO: arrays are not supported -# if 0 +# ifdef HAVE_SPAN_BYTE case common::AttributeType::TYPE_SPAN_BYTE: # endif case common::AttributeType::TYPE_SPAN_BOOL: From 19788f3c4203313b18da4bf847721740a3664a4d Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 16:10:25 -0800 Subject: [PATCH 09/20] Fix compilation error with C++20 STL --- .../opentelemetry/trace/propagation/http_trace_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/include/opentelemetry/trace/propagation/http_trace_context.h b/api/include/opentelemetry/trace/propagation/http_trace_context.h index 3d28196a28..19de20d523 100644 --- a/api/include/opentelemetry/trace/propagation/http_trace_context.h +++ b/api/include/opentelemetry/trace/propagation/http_trace_context.h @@ -129,7 +129,7 @@ class HttpTraceContext : public HTTPTextFormat // Converts the hex numbers stored as strings into bytes stored in a buffer. static void GenerateHexFromString(nostd::string_view string, int bytes, uint8_t *buf) { - const char *str_id = string.begin(); + const char *str_id = string.data(); for (int i = 0; i < bytes; i++) { int tmp = HexToInt(str_id[i]); From 33505c61e1c2a4b1f8b773eab3d7e716643254f7 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 16:11:09 -0800 Subject: [PATCH 10/20] Rename option to WITH_ETW to be consistent with other exporters --- CMakeLists.txt | 7 ++++++- exporters/CMakeLists.txt | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c655b3fa5a..3b199c3113 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,12 @@ option(WITH_ELASTICSEARCH option(BUILD_TESTING "Whether to enable tests" ON) if(WIN32) - option(WITH_ETW_EXPORTER "Whether to include the ETW Exporter in the SDK" ON) + option(WITH_ETW "Whether to include the ETW Exporter in the SDK" ON) + if(WITH_ETW) + add_definitions(-DHAVE_MSGPACK) + # Option below will be removed once we donate the TraceLoggingDynamic.h to OSS + add_definitions(-DHAVE_NO_TLD) + endif(WITH_ETW) endif(WIN32) option(WITH_EXAMPLES "Whether to build examples" ON) diff --git a/exporters/CMakeLists.txt b/exporters/CMakeLists.txt index 9141686ab1..1f18637712 100644 --- a/exporters/CMakeLists.txt +++ b/exporters/CMakeLists.txt @@ -13,6 +13,6 @@ if(WITH_ELASTICSEARCH) add_subdirectory(elasticsearch) endif() -if(WITH_ETW_EXPORTER) +if(WITH_ETW) add_subdirectory(etw) endif() From ee99010b8200f735cea5196b7e9687a135a86ef9 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 16:11:31 -0800 Subject: [PATCH 11/20] Fix missing include when compiling with C++20 --- exporters/etw/include/opentelemetry/exporters/etw/utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/utils.h b/exporters/etw/include/opentelemetry/exporters/etw/utils.h index 3238245e09..9a7bd44577 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/utils.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -14,6 +14,7 @@ #pragma once +#include #include #include #include From ec0e6badba2c3339efb92e86ff15857fffa45bf3 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 16:15:06 -0800 Subject: [PATCH 12/20] Resolve code review issue with NUL terminator --- CMakeLists.txt | 3 ++- .../exporters/etw/etw_provider_exporter.h | 15 +++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b199c3113..a2cdde4de2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,8 @@ if(WIN32) option(WITH_ETW "Whether to include the ETW Exporter in the SDK" ON) if(WITH_ETW) add_definitions(-DHAVE_MSGPACK) - # Option below will be removed once we donate the TraceLoggingDynamic.h to OSS + # Option below will be removed once we donate the TraceLoggingDynamic.h to + # OSS add_definitions(-DHAVE_NO_TLD) endif(WITH_ETW) endif(WIN32) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h index daa43dec1c..358d87b317 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -405,17 +405,12 @@ class ETWProvider std::vector v = nlohmann::json::to_msgpack(l1); - // NUL-terminator and padding for odd-sized buffers - v.push_back(0); - v.push_back(0); - if (v.size() % 2) - { - v.push_back(0); - }; - void *buff = v.data(); + EVENT_DESCRIPTOR evtDescriptor = { + .Id = 0, .Version = 0x1, .Channel = 0, .Level = 0, .Opcode = 0, .Task = 0, .Keyword = 0}; + EVENT_DATA_DESCRIPTOR evtData[1]; + EventDataDescCreate(&evtData[0], v.data(), v.size()); - UCHAR level = 0; // LogAlways - auto writeResponse = EventWriteString(providerData.providerHandle, level, 0, (PCWSTR)buff); + auto writeResponse = EventWrite(providerData.providerHandle, &evtDescriptor, 1, evtData); switch (writeResponse) { From 466be980509153f7039abe396dd341d7dcd44685 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 18:39:11 -0800 Subject: [PATCH 13/20] Fix an issue that required C++-latest --- .../opentelemetry/exporters/etw/etw_provider_exporter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h index 358d87b317..cda3487bcb 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -405,8 +405,8 @@ class ETWProvider std::vector v = nlohmann::json::to_msgpack(l1); - EVENT_DESCRIPTOR evtDescriptor = { - .Id = 0, .Version = 0x1, .Channel = 0, .Level = 0, .Opcode = 0, .Task = 0, .Keyword = 0}; + EVENT_DESCRIPTOR evtDescriptor; + EventDescCreate(&evtDescriptor, 0, 0x1, 0, 0, 0, 0, 0); EVENT_DATA_DESCRIPTOR evtData[1]; EventDataDescCreate(&evtData[0], v.data(), v.size()); From 7acc32f63eae2c0696fe3326dc8c91ba6ed7462f Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 18:39:58 -0800 Subject: [PATCH 14/20] Add comment that highlights the places of code that turn-off TraceLoggingDynamic feature for now. --- exporters/etw/src/etw_provider_exporter.cc | 3 +++ exporters/etw/src/etw_tracer_exporter.cc | 3 +++ exporters/etw/test/etw_provider_test.cc | 3 +++ exporters/etw/test/etw_tracer_test.cc | 3 +++ 4 files changed, 12 insertions(+) diff --git a/exporters/etw/src/etw_provider_exporter.cc b/exporters/etw/src/etw_provider_exporter.cc index 96be5b61d8..1232bc63f2 100644 --- a/exporters/etw/src/etw_provider_exporter.cc +++ b/exporters/etw/src/etw_provider_exporter.cc @@ -1,6 +1,9 @@ #ifdef _WIN32 +/* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ +# ifndef HAVE_NO_TLD # define HAVE_NO_TLD +# endif # include "opentelemetry/exporters/etw/etw_provider_exporter.h" diff --git a/exporters/etw/src/etw_tracer_exporter.cc b/exporters/etw/src/etw_tracer_exporter.cc index 21d38bb25e..c6e75145c1 100644 --- a/exporters/etw/src/etw_tracer_exporter.cc +++ b/exporters/etw/src/etw_tracer_exporter.cc @@ -1,6 +1,9 @@ #ifdef _WIN32 +/* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ +# ifndef HAVE_NO_TLD # define HAVE_NO_TLD +# endif # include "opentelemetry/exporters/etw/etw_tracer_exporter.h" diff --git a/exporters/etw/test/etw_provider_test.cc b/exporters/etw/test/etw_provider_test.cc index b19a87b50c..b6b4af7401 100644 --- a/exporters/etw/test/etw_provider_test.cc +++ b/exporters/etw/test/etw_provider_test.cc @@ -17,7 +17,10 @@ # include # include +/* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ +# ifndef HAVE_NO_TLD # define HAVE_NO_TLD +# endif # include "opentelemetry/exporters/etw/etw_provider_exporter.h" diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index c623546c21..2027a46d58 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -17,7 +17,10 @@ # include # include +/* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ +# ifndef HAVE_NO_TLD # define HAVE_NO_TLD +# endif # include "opentelemetry/exporters/etw/etw_tracer_exporter.h" # include "opentelemetry/sdk/trace/simple_processor.h" From c902bb27abe5e8be3357cc86236648b1d7533c8f Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 18:46:17 -0800 Subject: [PATCH 15/20] Fix formatting issue --- exporters/etw/src/etw_provider_exporter.cc | 2 +- exporters/etw/src/etw_tracer_exporter.cc | 2 +- exporters/etw/test/etw_provider_test.cc | 2 +- exporters/etw/test/etw_tracer_test.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exporters/etw/src/etw_provider_exporter.cc b/exporters/etw/src/etw_provider_exporter.cc index 1232bc63f2..3dd9396897 100644 --- a/exporters/etw/src/etw_provider_exporter.cc +++ b/exporters/etw/src/etw_provider_exporter.cc @@ -2,7 +2,7 @@ /* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ # ifndef HAVE_NO_TLD -# define HAVE_NO_TLD +# define HAVE_NO_TLD # endif # include "opentelemetry/exporters/etw/etw_provider_exporter.h" diff --git a/exporters/etw/src/etw_tracer_exporter.cc b/exporters/etw/src/etw_tracer_exporter.cc index c6e75145c1..6842a83933 100644 --- a/exporters/etw/src/etw_tracer_exporter.cc +++ b/exporters/etw/src/etw_tracer_exporter.cc @@ -2,7 +2,7 @@ /* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ # ifndef HAVE_NO_TLD -# define HAVE_NO_TLD +# define HAVE_NO_TLD # endif # include "opentelemetry/exporters/etw/etw_tracer_exporter.h" diff --git a/exporters/etw/test/etw_provider_test.cc b/exporters/etw/test/etw_provider_test.cc index b6b4af7401..5e5b8750e5 100644 --- a/exporters/etw/test/etw_provider_test.cc +++ b/exporters/etw/test/etw_provider_test.cc @@ -19,7 +19,7 @@ /* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ # ifndef HAVE_NO_TLD -# define HAVE_NO_TLD +# define HAVE_NO_TLD # endif # include "opentelemetry/exporters/etw/etw_provider_exporter.h" diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index 2027a46d58..41c4d8f01d 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -19,7 +19,7 @@ /* TODO: this definition needs to be removed when TraceLoggingDynamic.h is OSS */ # ifndef HAVE_NO_TLD -# define HAVE_NO_TLD +# define HAVE_NO_TLD # endif # include "opentelemetry/exporters/etw/etw_tracer_exporter.h" From 1b1a5f2fed4a4e267e7183b1f5d5537c480d902b Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 20:24:02 -0800 Subject: [PATCH 16/20] Addressing code review comments: refactoring event::UUID to utils::UUID, renaming uuid.hpp to uuid.h --- exporters/etw/BUILD | 4 ++-- .../opentelemetry/exporters/etw/etw_provider_exporter.h | 4 ++-- exporters/etw/include/opentelemetry/exporters/etw/utils.h | 2 +- .../include/opentelemetry/exporters/etw/{uuid.hpp => uuid.h} | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) rename exporters/etw/include/opentelemetry/exporters/etw/{uuid.hpp => uuid.h} (99%) diff --git a/exporters/etw/BUILD b/exporters/etw/BUILD index 706eeba507..1359906b94 100644 --- a/exporters/etw/BUILD +++ b/exporters/etw/BUILD @@ -8,7 +8,7 @@ cc_library( hdrs = [ "include/opentelemetry/exporters/etw/etw_provider_exporter.h", "include/opentelemetry/exporters/etw/utils.h", - "include/opentelemetry/exporters/etw/uuid.hpp", + "include/opentelemetry/exporters/etw/uuid.h", ], strip_include_prefix = "include", deps = [ @@ -35,7 +35,7 @@ cc_library( "include/opentelemetry/exporters/etw/etw_data.h", "include/opentelemetry/exporters/etw/etw_tracer_exporter.h", "include/opentelemetry/exporters/etw/utils.h", - "include/opentelemetry/exporters/etw/uuid.hpp", + "include/opentelemetry/exporters/etw/uuid.h", ], strip_include_prefix = "include", deps = [ diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h index cda3487bcb..e69182b119 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -26,7 +26,7 @@ #endif #include "opentelemetry/common/attribute_value.h" -#include "opentelemetry/exporters/etw/uuid.hpp" +#include "opentelemetry/exporters/etw/uuid.h" #include "opentelemetry/version.h" #include "opentelemetry/exporters/etw/utils.h" @@ -130,7 +130,7 @@ class ETWProvider auto &data = providers()[providerId]; data.providerMetaVector.clear(); - event::UUID guid = (providerId.rfind("{", 0) == 0) ? event::UUID(providerId.c_str()) + utils::UUID guid = (providerId.rfind("{", 0) == 0) ? utils::UUID(providerId.c_str()) : // It's a ProviderGUID utils::GetProviderGuid(providerId.c_str()); // It's a ProviderName diff --git a/exporters/etw/include/opentelemetry/exporters/etw/utils.h b/exporters/etw/include/opentelemetry/exporters/etw/utils.h index 9a7bd44577..079d4e5592 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/utils.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -23,7 +23,7 @@ #include #include -#include "opentelemetry/exporters/etw/uuid.hpp" +#include "opentelemetry/exporters/etw/uuid.h" #include "opentelemetry/version.h" #ifdef _WIN32 diff --git a/exporters/etw/include/opentelemetry/exporters/etw/uuid.hpp b/exporters/etw/include/opentelemetry/exporters/etw/uuid.h similarity index 99% rename from exporters/etw/include/opentelemetry/exporters/etw/uuid.hpp rename to exporters/etw/include/opentelemetry/exporters/etw/uuid.h index 6c9e6bdc98..4a9640a924 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/uuid.hpp +++ b/exporters/etw/include/opentelemetry/exporters/etw/uuid.h @@ -29,7 +29,7 @@ OPENTELEMETRY_BEGIN_NAMESPACE -namespace event +namespace utils { /// @@ -418,6 +418,6 @@ struct UUIDComparer : std::less inline bool operator()(UUID const &lhs, UUID const &rhs) const { return lhs.Hash() < rhs.Hash(); } }; -} // namespace event +} // namespace utils OPENTELEMETRY_END_NAMESPACE From 1d1e63d9a9cdfe0c0ca9be34b703d76f8e7b3054 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 20:35:40 -0800 Subject: [PATCH 17/20] Fix compiler error due to code review refactor --- exporters/etw/test/etw_provider_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporters/etw/test/etw_provider_test.cc b/exporters/etw/test/etw_provider_test.cc index 5e5b8750e5..1f797c91c8 100644 --- a/exporters/etw/test/etw_provider_test.cc +++ b/exporters/etw/test/etw_provider_test.cc @@ -53,12 +53,12 @@ TEST(ETWProvider, CheckOpenGUIDDataSuccessfully) static ETWProvider etw; auto handle = etw.open(providerName.c_str()); - event::UUID uuid_handle(handle.providerGuid); + utils::UUID uuid_handle(handle.providerGuid); auto guidStrHandle = uuid_handle.to_string(); // get GUID from the providerName auto guid = utils::GetProviderGuid(providerName.c_str()); - event::UUID uuid_name(guid); + utils::UUID uuid_name(guid); auto guidStrName = uuid_name.to_string(); ASSERT_STREQ(guidStrHandle.c_str(), guidStrName.c_str()); From 27455e19b8c96057c3c38cde8506f02fbd048497 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Wed, 30 Dec 2020 21:12:58 -0800 Subject: [PATCH 18/20] Addressing code review comment: review unused includes --- .../opentelemetry/exporters/etw/etw_tracer_exporter.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h index 7253566621..5d3cf578fa 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -33,13 +33,6 @@ #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/recordable.h" -#include -#include -#include -#include -#include -#include - #include "opentelemetry/exporters/etw/etw_data.h" #include "opentelemetry/exporters/etw/etw_provider_exporter.h" From 9ec1d2b9425d7277f37877c717994e291d96c637 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Mon, 4 Jan 2021 13:22:09 -0800 Subject: [PATCH 19/20] Move ETW exporter to 'exporter' namespace --- .../opentelemetry/exporters/etw/etw_data.h | 21 ++++++++----------- .../exporters/etw/etw_tracer_exporter.h | 11 +++++----- exporters/etw/test/etw_tracer_test.cc | 6 +++--- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h index 46db7526a6..c3377009c8 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h @@ -37,6 +37,8 @@ namespace trace = opentelemetry::trace; OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ namespace ETW { class Span; @@ -392,14 +394,8 @@ class TracerProvider : public trace::TracerProvider return nostd::shared_ptr{new (std::nothrow) Tracer(*this, name, evtFmt)}; } }; -} // namespace ETW -namespace sdk -{ -namespace trace -{ - -class ETWSpanData final : public Recordable +class ETWSpanData final : public sdk::trace::Recordable { public: ETWSpanData(std::string providerName) { InitTracerProvider(providerName); } @@ -455,7 +451,7 @@ class ETWSpanData final : public Recordable * Get the attributes for this span * @return the attributes for this span */ - const std::unordered_map &GetAttributes() const noexcept + const std::unordered_map &GetAttributes() const noexcept { return attribute_map_.GetAttributes(); } @@ -511,7 +507,7 @@ class ETWSpanData final : public Recordable void InitTracerProvider(std::string providerName) { - ETW::TracerProvider tracer_provider_; + exporter::ETW::TracerProvider tracer_provider_; tracer_ = tracer_provider_.GetTracer(providerName); span_ = tracer_->StartSpan(name_); @@ -526,11 +522,12 @@ class ETWSpanData final : public Recordable std::string name_; opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; - AttributeMap attribute_map_; + sdk::trace::AttributeMap attribute_map_; opentelemetry::trace::SpanKind span_kind_{opentelemetry::trace::SpanKind::kInternal}; nostd::shared_ptr tracer_; nostd::shared_ptr span_; }; -} // namespace trace -} // namespace sdk + +} // namespace ETW +} // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h index 5d3cf578fa..2b6c793e0e 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -43,6 +43,8 @@ namespace trace = opentelemetry::trace; OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ namespace ETW { @@ -60,7 +62,7 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter */ std::unique_ptr MakeRecordable() noexcept override { - return std::unique_ptr(new sdk::trace::ETWSpanData(providerName_)); + return std::unique_ptr(new ETWSpanData(providerName_)); } /** @@ -73,8 +75,8 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter { for (auto &recordable : recordables) { - auto span = std::unique_ptr( - dynamic_cast(recordable.release())); + auto span = std::unique_ptr( + dynamic_cast(recordable.release())); if (span != nullptr) { std::cout << span->GetName() << std::endl; @@ -95,9 +97,8 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter private: std::string providerName_; - std::shared_ptr data_; }; - } // namespace ETW +} // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index 41c4d8f01d..8d252e1947 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -34,7 +34,7 @@ TEST(ETWTracer, TracerCheck) std::string providerName = "OpenTelemetry"; std::string eventName = "MyEvent"; - ETW::TracerProvider tp; + exporter::ETW::TracerProvider tp; auto tracer = tp.GetTracer(providerName); auto span = tracer->StartSpan("MySpan"); @@ -50,7 +50,7 @@ TEST(ETWTracer, ETWTracerTest) { std::string providerName = "OpenTelemetry"; - auto exporter = std::unique_ptr(new ETW::ETWTracerExporter(providerName)); + auto exporter = std::unique_ptr(new exporter::ETW::ETWTracerExporter(providerName)); auto processor = std::shared_ptr( new sdk::trace::SimpleSpanProcessor(std::move(exporter))); @@ -80,7 +80,7 @@ TEST(ETWTracer, ExportUnitTest) { std::string providerName = "OpenTelemetry"; - auto exporter = std::unique_ptr(new ETW::ETWTracerExporter(providerName)); + auto exporter = std::unique_ptr(new exporter::ETW::ETWTracerExporter(providerName)); auto recordable = exporter->MakeRecordable(); recordable->SetName("MySpan"); From ea2a4e4357fe6c86033ae0059f4ba2a406b96efb Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Mon, 4 Jan 2021 13:26:45 -0800 Subject: [PATCH 20/20] Apply code formatting --- .../etw/include/opentelemetry/exporters/etw/etw_data.h | 3 ++- .../opentelemetry/exporters/etw/etw_tracer_exporter.h | 3 +-- exporters/etw/test/etw_tracer_test.cc | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h index c3377009c8..2cce6a6a90 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h @@ -451,7 +451,8 @@ class ETWSpanData final : public sdk::trace::Recordable * Get the attributes for this span * @return the attributes for this span */ - const std::unordered_map &GetAttributes() const noexcept + const std::unordered_map &GetAttributes() const + noexcept { return attribute_map_.GetAttributes(); } diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h index 2b6c793e0e..762dd56b22 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -75,8 +75,7 @@ class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter { for (auto &recordable : recordables) { - auto span = std::unique_ptr( - dynamic_cast(recordable.release())); + auto span = std::unique_ptr(dynamic_cast(recordable.release())); if (span != nullptr) { std::cout << span->GetName() << std::endl; diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index 8d252e1947..c07fa53cd8 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -50,7 +50,8 @@ TEST(ETWTracer, ETWTracerTest) { std::string providerName = "OpenTelemetry"; - auto exporter = std::unique_ptr(new exporter::ETW::ETWTracerExporter(providerName)); + auto exporter = std::unique_ptr( + new exporter::ETW::ETWTracerExporter(providerName)); auto processor = std::shared_ptr( new sdk::trace::SimpleSpanProcessor(std::move(exporter))); @@ -80,7 +81,8 @@ TEST(ETWTracer, ExportUnitTest) { std::string providerName = "OpenTelemetry"; - auto exporter = std::unique_ptr(new exporter::ETW::ETWTracerExporter(providerName)); + auto exporter = std::unique_ptr( + new exporter::ETW::ETWTracerExporter(providerName)); auto recordable = exporter->MakeRecordable(); recordable->SetName("MySpan");