From e8ef7eaecadbfa905ff65372f5fec4ecb91778cd Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 6 Jan 2021 23:51:55 +0530 Subject: [PATCH 01/16] ETW Tracer exporter (#376) --- CMakeLists.txt | 10 + exporters/CMakeLists.txt | 4 + exporters/etw/BUILD | 55 ++ exporters/etw/CMakeLists.txt | 26 + .../opentelemetry/exporters/etw/etw_data.h | 534 ++++++++++++++ .../exporters/etw/etw_provider_exporter.h | 658 ++++++++++++++++++ .../exporters/etw/etw_tracer_exporter.h | 103 +++ .../opentelemetry/exporters/etw/utils.h | 210 ++++++ .../opentelemetry/exporters/etw/uuid.h | 423 +++++++++++ exporters/etw/src/etw_provider_exporter.cc | 10 + exporters/etw/src/etw_tracer_exporter.cc | 10 + exporters/etw/test/etw_provider_test.cc | 78 +++ exporters/etw/test/etw_tracer_test.cc | 95 +++ .../opentelemetry/sdk/trace/processor.h | 4 +- .../sdk/trace/simple_processor.h | 4 +- 15 files changed, 2220 insertions(+), 4 deletions(-) create mode 100644 exporters/etw/BUILD create mode 100644 exporters/etw/CMakeLists.txt create mode 100644 exporters/etw/include/opentelemetry/exporters/etw/etw_data.h 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.h 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 97375720b5..1e8aeed756 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,16 @@ 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 "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) find_package(Threads) diff --git a/exporters/CMakeLists.txt b/exporters/CMakeLists.txt index 68ea177c38..1f18637712 100644 --- a/exporters/CMakeLists.txt +++ b/exporters/CMakeLists.txt @@ -12,3 +12,7 @@ endif() if(WITH_ELASTICSEARCH) add_subdirectory(elasticsearch) endif() + +if(WITH_ETW) + add_subdirectory(etw) +endif() diff --git a/exporters/etw/BUILD b/exporters/etw/BUILD new file mode 100644 index 0000000000..1359906b94 --- /dev/null +++ b/exporters/etw/BUILD @@ -0,0 +1,55 @@ +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.h", + ], + 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_data.h", + "include/opentelemetry/exporters/etw/etw_tracer_exporter.h", + "include/opentelemetry/exporters/etw/utils.h", + "include/opentelemetry/exporters/etw/uuid.h", + ], + 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", + ], +) diff --git a/exporters/etw/CMakeLists.txt b/exporters/etw/CMakeLists.txt new file mode 100644 index 0000000000..a3d02e6f35 --- /dev/null +++ b/exporters/etw/CMakeLists.txt @@ -0,0 +1,26 @@ +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_data.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h new file mode 100644 index 0000000000..2cce6a6a90 --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h @@ -0,0 +1,534 @@ +#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 +#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 exporter +{ +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, opentelemetry::sdk::GetEmptyAttributes()); + }; + + /// + /// Add event data to span associated with tracer + /// + /// + /// + void AddEvent(Span &span, nostd::string_view name) + { + AddEvent(span, name, std::chrono::system_clock::now(), + opentelemetry::sdk::GetEmptyAttributes()); + }; + + 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{trace::SpanContext::GetInvalid()}; + 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 sdk::trace::Recordable +{ +public: + ETWSpanData(std::string providerName) { InitTracerProvider(providerName); } + /** + * 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(); + } + + 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 + { + span_->AddEvent(name, timestamp, attributes); + } + + void AddLink(const opentelemetry::trace::SpanContext &span_context, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override + { + // TODO: Link Implementation for the Span to be implemented + } + + 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 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; + } + + void SetDuration(std::chrono::nanoseconds duration) noexcept override { duration_ = duration; } + + void InitTracerProvider(std::string providerName) + { + exporter::ETW::TracerProvider tracer_provider_; + + tracer_ = tracer_provider_.GetTracer(providerName); + span_ = tracer_->StartSpan(name_); + } + +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_; + sdk::trace::AttributeMap attribute_map_; + opentelemetry::trace::SpanKind span_kind_{opentelemetry::trace::SpanKind::kInternal}; + nostd::shared_ptr tracer_; + nostd::shared_ptr span_; +}; + +} // namespace ETW +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE 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..e69182b119 --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -0,0 +1,658 @@ +// 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.h" +#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(); + + 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 + + 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; +# 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. + break; + } + + /* clang-format off */ + nlohmann::json jObj = + { + { "env_name", "Span" }, + { "env_ver", "4.0" }, + // + // 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; + } +# 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: + { + auto temp = nostd::get(value); + // TODO: add transform from GUID type to string? + jObj[name] = temp; + break; + } +# endif + // TODO: arrays are not supported yet +# ifdef HAVE_SPAN_BYTE + 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); + + EVENT_DESCRIPTOR evtDescriptor; + EventDescCreate(&evtDescriptor, 0, 0x1, 0, 0, 0, 0, 0); + EVENT_DATA_DESCRIPTOR evtData[1]; + EventDataDescCreate(&evtData[0], v.data(), v.size()); + + auto writeResponse = EventWrite(providerData.providerHandle, &evtDescriptor, 1, evtData); + + 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; +# 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. + 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; + } +# ifdef HAVE_CSTRING_TYPE + case common::AttributeType::TYPE_CSTRING: + { + builder.AddField(name, tld::TypeUtf8String); + auto temp = nostd::get(value); + dbuilder.AddString(temp); + break; + } +# endif +# 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 +# ifdef HAVE_SPAN_BYTE + 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 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..762dd56b22 --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer_exporter.h @@ -0,0 +1,103 @@ +// 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_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/exporters/etw/etw_data.h" +#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 exporter +{ +namespace ETW +{ + +class ETWTracerExporter final : public opentelemetry::sdk::trace::SpanExporter +{ +public: + /** + * @param providerName + * @param eventName + */ + ETWTracerExporter(std::string providerName) : providerName_(providerName) {} + + /** + * @return Returns a unique pointer to an empty recordable object + */ + std::unique_ptr MakeRecordable() noexcept override + { + return std::unique_ptr(new ETWSpanData(providerName_)); + } + + /** + * @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 span = std::unique_ptr(dynamic_cast(recordable.release())); + if (span != nullptr) + { + std::cout << span->GetName() << std::endl; + } + } + + 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 + */ + bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override + { + return true; + }; + +private: + std::string providerName_; +}; +} // namespace ETW +} // namespace exporter + +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..079d4e5592 --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -0,0 +1,210 @@ +// 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 + +#include "opentelemetry/exporters/etw/uuid.h" +#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 diff --git a/exporters/etw/include/opentelemetry/exporters/etw/uuid.h b/exporters/etw/include/opentelemetry/exporters/etw/uuid.h new file mode 100644 index 0000000000..4a9640a924 --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/uuid.h @@ -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 utils +{ + +/// +/// 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 utils + +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..3dd9396897 --- /dev/null +++ b/exporters/etw/src/etw_provider_exporter.cc @@ -0,0 +1,10 @@ +#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" + +#endif diff --git a/exporters/etw/src/etw_tracer_exporter.cc b/exporters/etw/src/etw_tracer_exporter.cc new file mode 100644 index 0000000000..6842a83933 --- /dev/null +++ b/exporters/etw/src/etw_tracer_exporter.cc @@ -0,0 +1,10 @@ +#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" + +#endif diff --git a/exporters/etw/test/etw_provider_test.cc b/exporters/etw/test/etw_provider_test.cc new file mode 100644 index 0000000000..1f797c91c8 --- /dev/null +++ b/exporters/etw/test/etw_provider_test.cc @@ -0,0 +1,78 @@ +// 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. + +#ifdef _WIN32 + +# 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" + +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()); + + utils::UUID uuid_handle(handle.providerGuid); + auto guidStrHandle = uuid_handle.to_string(); + + // get GUID from the providerName + auto guid = utils::GetProviderGuid(providerName.c_str()); + utils::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); +} + +#endif diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc new file mode 100644 index 0000000000..c07fa53cd8 --- /dev/null +++ b/exporters/etw/test/etw_tracer_test.cc @@ -0,0 +1,95 @@ +// 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. + +#ifdef _WIN32 + +# 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" + +using namespace OPENTELEMETRY_NAMESPACE; + +using ETWEvent = std::map; + +TEST(ETWTracer, TracerCheck) +{ + std::string providerName = "OpenTelemetry"; + std::string eventName = "MyEvent"; + + exporter::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->CloseWithMicroseconds(0)); +} + +TEST(ETWTracer, ETWTracerTest) +{ + std::string providerName = "OpenTelemetry"; + + auto exporter = std::unique_ptr( + new exporter::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 exporter::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); +} + +#endif 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 ff797b59b2899a6ace7117862a09820a97742c30 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 6 Jan 2021 11:02:09 -0800 Subject: [PATCH 02/16] Add cache for bazel to prove why bazel rocks (#505) --- .github/workflows/ci.yml | 58 +++++++++++++++++++++++++++++++++++++++- ci/do_ci.sh | 23 ++++++++-------- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2bd69380a..915f6a0826 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,13 +87,20 @@ jobs: - name: run tests run: ./ci/do_ci.sh cmake.test_example_plugin - gcc_48_test: + bazel_gcc_48_test: name: Bazel gcc 4.8 runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /home/runner/.cache/bazel + key: bazel_gcc_48_test - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -111,6 +118,13 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /home/runner/.cache/bazel + key: bazel_test - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -125,6 +139,13 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /home/runner/.cache/bazel + key: bazel_valgrind - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -139,6 +160,13 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /home/runner/.cache/bazel + key: bazel_noexcept - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -153,6 +181,13 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /home/runner/.cache/bazel + key: bazel_asan - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -167,6 +202,13 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /home/runner/.cache/bazel + key: bazel_tsan - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -181,6 +223,13 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /Users/runner/.cache/bazel + key: bazel_osx - name: run tests run: ./ci/do_ci.sh bazel.test @@ -191,6 +240,13 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' + - name: Mount Bazel Cache + uses: actions/cache@v2 + env: + cache-name: bazel_cache + with: + path: /home/runner/.cache/bazel + key: bazel_benchmark - name: setup run: | sudo ./ci/setup_ci_environment.sh diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 79797279b4..32a8bb99df 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -10,6 +10,7 @@ mkdir -p "${PLUGIN_DIR}" BAZEL_OPTIONS="" BAZEL_TEST_OPTIONS="$BAZEL_OPTIONS --test_output=errors" +BAZEL_STARTUP_OPTIONS="--output_user_root=$HOME/.cache/bazel" if [[ "$1" == "cmake.test" ]]; then cd "${BUILD_DIR}" @@ -114,34 +115,34 @@ 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 $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS //... + bazel $BAZEL_STARTUP_OPTIONS 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/... - bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... + bazel $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/... + bazel $BAZEL_STARTUP_OPTIONS 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/... - bazel test --copt=-fno-exceptions $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... + bazel $BAZEL_STARTUP_OPTIONS build --copt=-fno-exceptions $BAZEL_OPTIONS -- //... -//exporters/prometheus/... + bazel $BAZEL_STARTUP_OPTIONS test --copt=-fno-exceptions $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... exit 0 elif [[ "$1" == "bazel.asan" ]]; then - bazel test --config=asan $BAZEL_TEST_OPTIONS //... + bazel $BAZEL_STARTUP_OPTIONS test --config=asan $BAZEL_TEST_OPTIONS //... exit 0 elif [[ "$1" == "bazel.tsan" ]]; then - bazel test --config=tsan $BAZEL_TEST_OPTIONS //... + bazel $BAZEL_STARTUP_OPTIONS test --config=tsan $BAZEL_TEST_OPTIONS //... 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 $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS //... + bazel $BAZEL_STARTUP_OPTIONS 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 - bazel build $BAZEL_OPTIONS -c opt -- \ + bazel $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS -c opt -- \ $(bazel query 'attr("tags", "benchmark_result", ...)') echo "" echo "Benchmark results in $BENCHMARK_DIR:" From f9db910ff1be246cbc6e29b4e10683be9daa562c Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Wed, 6 Jan 2021 11:20:49 -0800 Subject: [PATCH 03/16] Don't override CURL_LIBRARY found by find_package (#498) --- ext/test/http/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/test/http/CMakeLists.txt b/ext/test/http/CMakeLists.txt index f063c887d1..e79ae7fea4 100644 --- a/ext/test/http/CMakeLists.txt +++ b/ext/test/http/CMakeLists.txt @@ -1,6 +1,5 @@ find_package(CURL) if(CURL_FOUND) - set(CURL_LIBRARY "-lcurl") set(FILENAME curl_http_test) add_executable(${FILENAME} ${FILENAME}.cc) target_link_libraries(${FILENAME} ${GTEST_BOTH_LIBRARIES} From fb4feea7617315dfe774f1791ee7c2aa84d9df1d Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 6 Jan 2021 20:10:16 -0800 Subject: [PATCH 04/16] Upgrade prometheus to v0.11.0, consume directly the repo in bazel (#508) --- bazel/repository.bzl | 8 ++++++-- third_party/prometheus-cpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bazel/repository.bzl b/bazel/repository.bzl index cd2eabb6a2..3069fe9a88 100644 --- a/bazel/repository.bzl +++ b/bazel/repository.bzl @@ -60,9 +60,13 @@ def opentelemetry_cpp_deps(): # C++ Prometheus Client library. maybe( - native.local_repository, + http_archive, name = "com_github_jupp0r_prometheus_cpp", - path = "third_party/prometheus-cpp", + sha256 = "aab4ef8342319f631969e01b8c41e355704847cbe76131cb1dd5ea1862000bda", + strip_prefix = "prometheus-cpp-0.11.0", + urls = [ + "https://github.com/jupp0r/prometheus-cpp/archive/v0.11.0.tar.gz", + ], ) # libcurl (optional) diff --git a/third_party/prometheus-cpp b/third_party/prometheus-cpp index 27c3d670c6..bb017ec15a 160000 --- a/third_party/prometheus-cpp +++ b/third_party/prometheus-cpp @@ -1 +1 @@ -Subproject commit 27c3d670c66985c0096d378cdd780088b08bc8f4 +Subproject commit bb017ec15a824d3301845a1274b4b46a01d6d871 From aa7b3c8f17918c71785ff9213d7e1f58c0de3867 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Thu, 7 Jan 2021 10:15:14 +0530 Subject: [PATCH 05/16] Consolidate cmake test on ubuntu-latest (#506) --- .github/workflows/ci.yml | 8 +++----- ci/do_ci.sh | 38 ++++++++++++++------------------------ 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 915f6a0826..69fa811927 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: jobs: cmake_test: - name: CMake test + name: CMake test (without otlp-exporter) runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -18,10 +18,8 @@ jobs: run: | sudo ./ci/setup_cmake.sh sudo ./ci/setup_ci_environment.sh - - name: run tests + - name: run cmake tests (without otlp-exporter) run: ./ci/do_ci.sh cmake.test - - name: run prometheus exporter tests - run: ./ci/do_ci.sh cmake.exporter.prometheus.test cmake_gcc_48_test: name: CMake gcc 4.8 @@ -58,7 +56,7 @@ jobs: run: ./ci/do_ci.sh cmake.c++20.test cmake_otprotocol_test: - name: CMake otprotocol test + name: CMake test (with otlp-exporter) runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 32a8bb99df..62723fb5d3 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -2,6 +2,18 @@ set -e +function install_prometheus_cpp_client +{ + pushd third_party/prometheus-cpp + git submodule update --recursive --init + [[ -d _build ]] && rm -rf ./_build + mkdir _build && cd _build + cmake .. -DBUILD_SHARED_LIBS=ON -DUSE_THIRDPARTY_LIBRARIES=ON + make -j 4 + sudo make install + popd +} + [ -z "${SRC_DIR}" ] && export SRC_DIR="`pwd`" [ -z "${BUILD_DIR}" ] && export BUILD_DIR=$HOME/build mkdir -p "${BUILD_DIR}" @@ -13,9 +25,11 @@ BAZEL_TEST_OPTIONS="$BAZEL_OPTIONS --test_output=errors" BAZEL_STARTUP_OPTIONS="--output_user_root=$HOME/.cache/bazel" if [[ "$1" == "cmake.test" ]]; then + install_prometheus_cpp_client cd "${BUILD_DIR}" rm -rf * cmake -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_PROMETHEUS=ON \ -DCMAKE_CXX_FLAGS="-Werror" \ "${SRC_DIR}" make @@ -56,30 +70,6 @@ elif [[ "$1" == "cmake.exporter.otprotocol.test" ]]; then make -j $(nproc) cd exporters/otlp && make test exit 0 -elif [[ "$1" == "cmake.exporter.prometheus.test" ]]; then -# export DEBIAN_FRONTEND=noninteractive -# apt-get update -# apt-get install sudo -# apt-get install zlib1g-dev -# apt-get -y install libcurl4-openssl-dev - cd third_party/prometheus-cpp - git submodule update --recursive --init - [[ -d _build ]] && rm -rf ./_build - mkdir _build && cd _build - cmake .. -DBUILD_SHARED_LIBS=ON -DUSE_THIRDPARTY_LIBRARIES=ON - make -j 4 - sudo make install - - cd "${BUILD_DIR}" - rm -rf * - - cmake -DCMAKE_BUILD_TYPE=Debug \ - -DWITH_PROMETHEUS=ON \ - -DCMAKE_CXX_FLAGS="-Werror" \ - "${SRC_DIR}" - make - make test - exit 0 elif [[ "$1" == "cmake.test_example_plugin" ]]; then # Build the plugin cd "${BUILD_DIR}" From 1c4b727bfe37b7ded845c47d398a0238964bd9b3 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Fri, 8 Jan 2021 07:11:56 -0800 Subject: [PATCH 06/16] Use http archive instead of git submodule for googletest, same version as submodule (#509) --- bazel/repository.bzl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bazel/repository.bzl b/bazel/repository.bzl index 3069fe9a88..59ed8b1ada 100644 --- a/bazel/repository.bzl +++ b/bazel/repository.bzl @@ -19,9 +19,13 @@ def opentelemetry_cpp_deps(): # GoogleTest framework. # Only needed for tests, not to build the OpenTelemetry library. maybe( - native.local_repository, + http_archive, name = "com_google_googletest", - path = "third_party/googletest", + sha256 = "a03a7b24b3a0766dc823c9008dd32c56a1183889c04f084653266af22289ab0c", + strip_prefix = "googletest-a6dfd3aca7f2f91f95fc7ab650c95a48420d513d", + urls = [ + "https://github.com/google/googletest/archive/a6dfd3aca7f2f91f95fc7ab650c95a48420d513d.tar.gz", + ], ) # Load gRPC dependency From c8db8476ef10194fc69f8919eb7ef3ef778c1617 Mon Sep 17 00:00:00 2001 From: Karen Xu Date: Sat, 9 Jan 2021 01:12:19 -0500 Subject: [PATCH 07/16] Use attribute_utils.h from common instead of trace (#482) --- .../elasticsearch/es_log_recordable.h | 2 +- .../opentelemetry/exporters/etw/etw_data.h | 4 +- .../exporters/ostream/span_exporter.h | 15 +- .../ext/zpages/threadsafe_span_data.h | 19 +-- ext/src/zpages/tracez_http_server.cc | 2 +- ext/test/zpages/threadsafe_span_data_test.cc | 4 +- .../sdk/common/attribute_utils.h | 23 +++ .../opentelemetry/sdk/logs/log_record.h | 2 +- .../opentelemetry/sdk/trace/attribute_utils.h | 131 ------------------ .../opentelemetry/sdk/trace/span_data.h | 14 +- sdk/test/common/BUILD | 12 ++ sdk/test/common/CMakeLists.txt | 4 +- .../{trace => common}/attribute_utils_test.cc | 6 +- sdk/test/trace/BUILD | 11 -- sdk/test/trace/CMakeLists.txt | 3 +- 15 files changed, 71 insertions(+), 181 deletions(-) delete mode 100644 sdk/include/opentelemetry/sdk/trace/attribute_utils.h rename sdk/test/{trace => common}/attribute_utils_test.cc (81%) diff --git a/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_recordable.h b/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_recordable.h index 1745db2618..4e9d9aaabb 100644 --- a/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_recordable.h +++ b/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_recordable.h @@ -19,7 +19,7 @@ #include #include #include "nlohmann/json.hpp" -#include "opentelemetry/sdk/common/attribute_utils.h" // same as traces/attribute_utils +#include "opentelemetry/sdk/common/attribute_utils.h" #include "opentelemetry/sdk/logs/recordable.h" #include "opentelemetry/version.h" diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h index 2cce6a6a90..8e589a7d07 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_data.h @@ -451,7 +451,7 @@ 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 + const std::unordered_map &GetAttributes() const noexcept { return attribute_map_.GetAttributes(); @@ -523,7 +523,7 @@ class ETWSpanData final : public sdk::trace::Recordable std::string name_; opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; - sdk::trace::AttributeMap attribute_map_; + sdk::common::AttributeMap attribute_map_; opentelemetry::trace::SpanKind span_kind_{opentelemetry::trace::SpanKind::kInternal}; nostd::shared_ptr tracer_; nostd::shared_ptr span_; diff --git a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h index 8580c53b6b..758c32fb04 100644 --- a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h +++ b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h @@ -9,8 +9,9 @@ #include #include -namespace nostd = opentelemetry::nostd; -namespace sdktrace = opentelemetry::sdk::trace; +namespace nostd = opentelemetry::nostd; +namespace sdktrace = opentelemetry::sdk::trace; +namespace sdkcommon = opentelemetry::sdk::common; OPENTELEMETRY_BEGIN_NAMESPACE namespace exporter @@ -93,10 +94,10 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter // Prior to C++14, generic lambda is not available so fallback to functor. #if __cplusplus < 201402L - class SpanDataAttributeValueVisitor + class OwnedAttributeValueVisitor { public: - SpanDataAttributeValueVisitor(OStreamSpanExporter &exporter) : exporter_(exporter) {} + OwnedAttributeValueVisitor(OStreamSpanExporter &exporter) : exporter_(exporter) {} template void operator()(T &&arg) @@ -110,16 +111,16 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter #endif - void print_value(sdktrace::SpanDataAttributeValue &value) + void print_value(sdkcommon::OwnedAttributeValue &value) { #if __cplusplus < 201402L - nostd::visit(SpanDataAttributeValueVisitor(*this), value); + nostd::visit(OwnedAttributeValueVisitor(*this), value); #else nostd::visit([this](auto &&arg) { print_value(arg); }, value); #endif } - void printAttributes(std::unordered_map map) + void printAttributes(std::unordered_map map) { size_t size = map.size(); size_t i = 1; diff --git a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h index 06073ac0b2..286e3d62c7 100644 --- a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h +++ b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h @@ -14,13 +14,6 @@ #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" -using opentelemetry::sdk::trace::AttributeConverter; -using opentelemetry::sdk::trace::SpanDataAttributeValue; -using opentelemetry::sdk::trace::SpanDataEvent; - -// TODO: Create generic short pattern for opentelemetry::common and opentelemetry::trace and others -// as necessary - OPENTELEMETRY_BEGIN_NAMESPACE namespace ext { @@ -117,7 +110,8 @@ class ThreadsafeSpanData final : public opentelemetry::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 { std::lock_guard lock(mutex_); return attributes_; @@ -188,7 +182,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable {})) noexcept override { std::lock_guard lock(mutex_); - events_.push_back(SpanDataEvent(std::string(name), timestamp, attributes)); + events_.push_back( + opentelemetry::sdk::trace::SpanDataEvent(std::string(name), timestamp, attributes)); } ThreadsafeSpanData() {} @@ -223,9 +218,9 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable opentelemetry::trace::SpanKind span_kind_; opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; - std::unordered_map attributes_; - std::vector events_; - AttributeConverter converter_; + std::unordered_map attributes_; + std::vector events_; + opentelemetry::sdk::common::AttributeConverter converter_; }; } // namespace zpages } // namespace ext diff --git a/ext/src/zpages/tracez_http_server.cc b/ext/src/zpages/tracez_http_server.cc index ebef512c1f..d44a8939a3 100644 --- a/ext/src/zpages/tracez_http_server.cc +++ b/ext/src/zpages/tracez_http_server.cc @@ -111,7 +111,7 @@ json TracezHttpServer::GetAttributesJSON( for (const auto &sample_attribute : sample.GetAttributes()) { auto &key = sample_attribute.first; - auto &val = sample_attribute.second; // SpanDataAttributeValue + auto &val = sample_attribute.second; // OwnedAttributeValue /* Convert variant types to into their nonvariant form. This is done this way because the frontend and JSON doesn't care about type, and variant's get function only allows diff --git a/ext/test/zpages/threadsafe_span_data_test.cc b/ext/test/zpages/threadsafe_span_data_test.cc index 5a4791d527..582d3ce11d 100644 --- a/ext/test/zpages/threadsafe_span_data_test.cc +++ b/ext/test/zpages/threadsafe_span_data_test.cc @@ -7,8 +7,8 @@ #include using opentelemetry::ext::zpages::ThreadsafeSpanData; -using opentelemetry::sdk::trace::AttributeConverter; -using opentelemetry::sdk::trace::SpanDataAttributeValue; +using opentelemetry::sdk::common::AttributeConverter; +using opentelemetry::sdk::common::OwnedAttributeValue; TEST(ThreadsafeSpanData, DefaultValues) { diff --git a/sdk/include/opentelemetry/sdk/common/attribute_utils.h b/sdk/include/opentelemetry/sdk/common/attribute_utils.h index 6d791d909f..481257c40a 100644 --- a/sdk/include/opentelemetry/sdk/common/attribute_utils.h +++ b/sdk/include/opentelemetry/sdk/common/attribute_utils.h @@ -1,5 +1,22 @@ +/* + * Copyright The 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 "opentelemetry/common/attribute_value.h" @@ -21,6 +38,9 @@ using OwnedAttributeValue = nostd::variant, +#endif std::vector, std::vector, std::vector, @@ -44,6 +64,9 @@ struct AttributeConverter { return OwnedAttributeValue(std::string(v)); } +#ifdef HAVE_SPAN_BYTE + OwnedAttributeValue operator()(nostd::span v) { return convertSpan(v); } +#endif OwnedAttributeValue operator()(nostd::span v) { return convertSpan(v); } OwnedAttributeValue operator()(nostd::span v) { return convertSpan(v); } OwnedAttributeValue operator()(nostd::span v) { return convertSpan(v); } diff --git a/sdk/include/opentelemetry/sdk/logs/log_record.h b/sdk/include/opentelemetry/sdk/logs/log_record.h index 4cef50ca90..f8c4fe5365 100644 --- a/sdk/include/opentelemetry/sdk/logs/log_record.h +++ b/sdk/include/opentelemetry/sdk/logs/log_record.h @@ -18,7 +18,7 @@ #include #include -#include "opentelemetry/sdk/common/attribute_utils.h" // same as traces/attribute_utils +#include "opentelemetry/sdk/common/attribute_utils.h" #include "opentelemetry/sdk/logs/recordable.h" #include "opentelemetry/version.h" diff --git a/sdk/include/opentelemetry/sdk/trace/attribute_utils.h b/sdk/include/opentelemetry/sdk/trace/attribute_utils.h deleted file mode 100644 index 821ad953fa..0000000000 --- a/sdk/include/opentelemetry/sdk/trace/attribute_utils.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include -#include -#include -#include "opentelemetry/common/attribute_value.h" -#include "opentelemetry/common/key_value_iterable_view.h" - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace trace -{ -/** - * A counterpart to AttributeValue that makes sure a value is owned. This - * replaces all non-owning references with owned copies. - */ -using SpanDataAttributeValue = nostd::variant, -#endif - std::vector, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector>; - -/** - * Creates an owned copy (SpanDataAttributeValue) of a non-owning AttributeValue. - */ -struct AttributeConverter -{ - SpanDataAttributeValue operator()(bool v) { return SpanDataAttributeValue(v); } - SpanDataAttributeValue operator()(int32_t v) { return SpanDataAttributeValue(v); } - SpanDataAttributeValue operator()(uint32_t v) { return SpanDataAttributeValue(v); } - SpanDataAttributeValue operator()(int64_t v) { return SpanDataAttributeValue(v); } - SpanDataAttributeValue operator()(uint64_t v) { return SpanDataAttributeValue(v); } - SpanDataAttributeValue operator()(double v) { return SpanDataAttributeValue(v); } - SpanDataAttributeValue operator()(nostd::string_view v) - { - return SpanDataAttributeValue(std::string(v.data(), v.size())); - } - SpanDataAttributeValue operator()(const char *s) - { - return SpanDataAttributeValue(std::string(s)); - } -#ifdef HAVE_SPAN_BYTE - SpanDataAttributeValue operator()(nostd::span v) - { - return convertSpan(v); - } -#endif - SpanDataAttributeValue operator()(nostd::span v) { return convertSpan(v); } - SpanDataAttributeValue operator()(nostd::span v) - { - return convertSpan(v); - } - SpanDataAttributeValue operator()(nostd::span v) - { - return convertSpan(v); - } - SpanDataAttributeValue operator()(nostd::span v) - { - return convertSpan(v); - } - SpanDataAttributeValue operator()(nostd::span v) - { - return convertSpan(v); - } - SpanDataAttributeValue operator()(nostd::span v) { return convertSpan(v); } - SpanDataAttributeValue operator()(nostd::span v) - { - return convertSpan(v); - } - - template - SpanDataAttributeValue convertSpan(nostd::span vals) - { - const std::vector copy(vals.begin(), vals.end()); - return SpanDataAttributeValue(std::move(copy)); - } -}; - -/** - * Class for storing attributes. - */ -class AttributeMap -{ -public: - // Contruct empty attribute map - AttributeMap(){}; - - // Contruct attribute map and populate with attributes - AttributeMap(const opentelemetry::common::KeyValueIterable &attributes) - { - attributes.ForEachKeyValue([&](nostd::string_view key, - opentelemetry::common::AttributeValue value) noexcept { - SetAttribute(key, value); - return true; - }); - } - - const std::unordered_map &GetAttributes() const noexcept - { - return attributes_; - } - - void SetAttribute(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept - { - attributes_[std::string(key)] = nostd::visit(converter_, value); - } - -private: - std::unordered_map attributes_; - AttributeConverter converter_; -}; -} // namespace trace -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/trace/span_data.h b/sdk/include/opentelemetry/sdk/trace/span_data.h index b5594804fe..c52ca6ae4b 100644 --- a/sdk/include/opentelemetry/sdk/trace/span_data.h +++ b/sdk/include/opentelemetry/sdk/trace/span_data.h @@ -6,7 +6,7 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/string_view.h" -#include "opentelemetry/sdk/trace/attribute_utils.h" +#include "opentelemetry/sdk/common/attribute_utils.h" #include "opentelemetry/sdk/trace/recordable.h" #include "opentelemetry/trace/canonical_code.h" #include "opentelemetry/trace/span.h" @@ -48,7 +48,7 @@ class SpanDataEvent * Get the attributes for this event * @return the attributes for this event */ - const std::unordered_map &GetAttributes() const noexcept + const std::unordered_map &GetAttributes() const noexcept { return attribute_map_.GetAttributes(); } @@ -56,7 +56,7 @@ class SpanDataEvent private: std::string name_; core::SystemTimestamp timestamp_; - AttributeMap attribute_map_; + common::AttributeMap attribute_map_; }; /** @@ -75,14 +75,14 @@ class SpanDataLink * Get the attributes for this link * @return the attributes for this link */ - const std::unordered_map &GetAttributes() const noexcept + const std::unordered_map &GetAttributes() const noexcept { return attribute_map_.GetAttributes(); } private: opentelemetry::trace::SpanContext span_context_; - AttributeMap attribute_map_; + common::AttributeMap attribute_map_; }; /** @@ -149,7 +149,7 @@ class SpanData 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(); } @@ -229,7 +229,7 @@ class SpanData final : public Recordable std::string name_; opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; - AttributeMap attribute_map_; + common::AttributeMap attribute_map_; std::vector events_; std::vector links_; opentelemetry::trace::SpanKind span_kind_{opentelemetry::trace::SpanKind::kInternal}; diff --git a/sdk/test/common/BUILD b/sdk/test/common/BUILD index 3864afef45..d727cada65 100644 --- a/sdk/test/common/BUILD +++ b/sdk/test/common/BUILD @@ -93,3 +93,15 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "attribute_utils_test", + srcs = [ + "attribute_utils_test.cc", + ], + deps = [ + "//api", + "//sdk:headers", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/common/CMakeLists.txt b/sdk/test/common/CMakeLists.txt index f1028bf6d8..647cd42ea1 100644 --- a/sdk/test/common/CMakeLists.txt +++ b/sdk/test/common/CMakeLists.txt @@ -1,10 +1,12 @@ foreach(testname random_test fast_random_number_generator_test atomic_unique_ptr_test - circular_buffer_range_test circular_buffer_test) + circular_buffer_range_test circular_buffer_test attribute_utils_test) + add_executable(${testname} "${testname}.cc") target_link_libraries( ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CORE_RUNTIME_LIBS} opentelemetry_common opentelemetry_trace) + gtest_add_tests( TARGET ${testname} TEST_PREFIX trace. diff --git a/sdk/test/trace/attribute_utils_test.cc b/sdk/test/common/attribute_utils_test.cc similarity index 81% rename from sdk/test/trace/attribute_utils_test.cc rename to sdk/test/common/attribute_utils_test.cc index 7a3a753b29..178af01823 100644 --- a/sdk/test/trace/attribute_utils_test.cc +++ b/sdk/test/common/attribute_utils_test.cc @@ -1,10 +1,10 @@ -#include "opentelemetry/sdk/trace/attribute_utils.h" +#include "opentelemetry/sdk/common/attribute_utils.h" #include TEST(AttributeMapTest, DefaultConstruction) { - opentelemetry::sdk::trace::AttributeMap map; + opentelemetry::sdk::common::AttributeMap map; EXPECT_EQ(map.GetAttributes().size(), 0); } @@ -17,7 +17,7 @@ TEST(AttributeMapTest, AttributesConstruction) {keys[0], values[0]}, {keys[1], values[1]}, {keys[2], values[2]}}; opentelemetry::common::KeyValueIterableView> iterable(attributes); - opentelemetry::sdk::trace::AttributeMap map(iterable); + opentelemetry::sdk::common::AttributeMap map(iterable); for (int i = 0; i < kNumAttributes; i++) { diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index a4f0e9d1ae..7322697e39 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -102,17 +102,6 @@ cc_test( ], ) -cc_test( - name = "attribute_utils_test", - srcs = [ - "attribute_utils_test.cc", - ], - deps = [ - "//sdk/src/trace", - "@com_google_googletest//:gtest_main", - ], -) - otel_cc_benchmark( name = "sampler_benchmark", srcs = ["sampler_benchmark.cc"], diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index b68a57f9cc..0ba567a102 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -8,8 +8,7 @@ foreach( always_on_sampler_test parent_sampler_test trace_id_ratio_sampler_test - batch_span_processor_test - attribute_utils_test) + batch_span_processor_test) add_executable(${testname} "${testname}.cc") target_link_libraries( ${testname} From c78be170ae4123d43dac397754de2b624b7465f3 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Sat, 9 Jan 2021 12:42:39 +0530 Subject: [PATCH 08/16] Http client factory (#445) --- ext/CMakeLists.txt | 3 ++- .../ext/http/client/http_client_factory.h | 19 ++++++++++++++++++ ext/src/CMakeLists.txt | 1 + ext/src/http/client/curl/BUILD | 14 +++++++++++++ ext/src/http/client/curl/CMakeLists.txt | 4 ++++ .../client/curl/http_client_factory_curl.cc | 9 +++++++++ ext/test/http/BUILD | 2 ++ ext/test/http/CMakeLists.txt | 6 ++++-- ext/test/http/curl_http_test.cc | 20 +++++++++++-------- 9 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 ext/include/opentelemetry/ext/http/client/http_client_factory.h create mode 100644 ext/src/http/client/curl/BUILD create mode 100644 ext/src/http/client/curl/CMakeLists.txt create mode 100644 ext/src/http/client/curl/http_client_factory_curl.cc diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 17a765a92b..0062e6c671 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -1,3 +1,4 @@ +include_directories(sdk) add_library(opentelemetry_ext INTERFACE) target_include_directories( opentelemetry_ext @@ -19,8 +20,8 @@ install( FILES_MATCHING PATTERN "*.h") -add_subdirectory(src) include_directories(include) +add_subdirectory(src) if(BUILD_TESTING) add_subdirectory(test) diff --git a/ext/include/opentelemetry/ext/http/client/http_client_factory.h b/ext/include/opentelemetry/ext/http/client/http_client_factory.h new file mode 100644 index 0000000000..3093b1a149 --- /dev/null +++ b/ext/include/opentelemetry/ext/http/client/http_client_factory.h @@ -0,0 +1,19 @@ +#pragma once +#include "opentelemetry/ext/http/client/http_client.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace ext +{ +namespace http +{ +namespace client +{ +class HttpClientFactory +{ +public: + static std::shared_ptr Create(); +}; +} // namespace client +} // namespace http +} // namespace ext +OPENTELEMETRY_END_NAMESPACE diff --git a/ext/src/CMakeLists.txt b/ext/src/CMakeLists.txt index 189a03f69c..d449d06b06 100644 --- a/ext/src/CMakeLists.txt +++ b/ext/src/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(zpages) +add_subdirectory(http/client/curl) diff --git a/ext/src/http/client/curl/BUILD b/ext/src/http/client/curl/BUILD new file mode 100644 index 0000000000..8360692601 --- /dev/null +++ b/ext/src/http/client/curl/BUILD @@ -0,0 +1,14 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "http_client_curl", + srcs = ["http_client_factory_curl.cc"], + include_prefix = "src/http/client/curl", + deps = [ + "//api", + "//ext:headers", + "//sdk:headers", + "//sdk/src/common:random", + "@curl", + ], +) diff --git a/ext/src/http/client/curl/CMakeLists.txt b/ext/src/http/client/curl/CMakeLists.txt new file mode 100644 index 0000000000..2026dbaf28 --- /dev/null +++ b/ext/src/http/client/curl/CMakeLists.txt @@ -0,0 +1,4 @@ +find_package(CURL) +if(CURL_FOUND) + add_library(opentelemetry_curl_factory http_client_factory_curl) +endif() diff --git a/ext/src/http/client/curl/http_client_factory_curl.cc b/ext/src/http/client/curl/http_client_factory_curl.cc new file mode 100644 index 0000000000..f75885aa43 --- /dev/null +++ b/ext/src/http/client/curl/http_client_factory_curl.cc @@ -0,0 +1,9 @@ +#include "opentelemetry/ext/http/client/curl/http_client_curl.h" +#include "opentelemetry/ext/http/client/http_client.h" +#include "opentelemetry/ext/http/client/http_client_factory.h" + +std::shared_ptr +opentelemetry::ext::http::client::HttpClientFactory::Create() +{ + return std::make_shared(); +} \ No newline at end of file diff --git a/ext/test/http/BUILD b/ext/test/http/BUILD index 678b2e5da7..7251c0fde6 100644 --- a/ext/test/http/BUILD +++ b/ext/test/http/BUILD @@ -6,6 +6,7 @@ cc_test( # TODO: Move copts/linkopts for static CURL usage into shared bzl file. copts = [ "-DCURL_STATICLIB", + "-DWITH_CURL", ], linkopts = select({ "//bazel:windows": [ @@ -17,6 +18,7 @@ cc_test( }), deps = [ "//ext:headers", + "//ext/src/http/client/curl:http_client_curl", "//sdk/src/trace", "@com_google_googletest//:gtest_main", "@curl", diff --git a/ext/test/http/CMakeLists.txt b/ext/test/http/CMakeLists.txt index e79ae7fea4..0fcaa24c48 100644 --- a/ext/test/http/CMakeLists.txt +++ b/ext/test/http/CMakeLists.txt @@ -1,15 +1,17 @@ find_package(CURL) if(CURL_FOUND) set(FILENAME curl_http_test) + add_compile_definitions(WITH_CURL) add_executable(${FILENAME} ${FILENAME}.cc) target_link_libraries(${FILENAME} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) if(TARGET CURL::libcurl) - target_link_libraries(${FILENAME} CURL::libcurl) + target_link_libraries(${FILENAME} CURL::libcurl opentelemetry_curl_factory) else() include_directories(${CURL_INCLUDE_DIRS}) - target_link_libraries(${FILENAME} ${CURL_LIBRARIES}) + target_link_libraries(${FILENAME} ${CURL_LIBRARIES} + opentelemetry_curl_factory) endif() gtest_add_tests( TARGET ${FILENAME} diff --git a/ext/test/http/curl_http_test.cc b/ext/test/http/curl_http_test.cc index c5466df6ed..13db98131e 100644 --- a/ext/test/http/curl_http_test.cc +++ b/ext/test/http/curl_http_test.cc @@ -1,4 +1,5 @@ #include "opentelemetry/ext//http/client/curl//http_client_curl.h" +#include "opentelemetry/ext/http/client/http_client_factory.h" #include "opentelemetry/ext/http/server/http_server.h" #include @@ -184,9 +185,10 @@ TEST_F(BasicCurlHttpTests, HttpResponse) TEST_F(BasicCurlHttpTests, SendGetRequest) { received_requests_.clear(); - curl::SessionManager session_manager; + auto session_manager = http_client::HttpClientFactory::Create(); + EXPECT_TRUE(session_manager != nullptr); - auto session = session_manager.CreateSession("127.0.0.1", HTTP_PORT); + auto session = session_manager->CreateSession("127.0.0.1", HTTP_PORT); auto request = session->CreateRequest(); request->SetUri("get/"); GetEventHandler *handler = new GetEventHandler(); @@ -200,9 +202,10 @@ TEST_F(BasicCurlHttpTests, SendGetRequest) TEST_F(BasicCurlHttpTests, SendPostRequest) { received_requests_.clear(); - curl::SessionManager session_manager; + auto session_manager = http_client::HttpClientFactory::Create(); + EXPECT_TRUE(session_manager != nullptr); - auto session = session_manager.CreateSession("127.0.0.1", HTTP_PORT); + auto session = session_manager->CreateSession("127.0.0.1", HTTP_PORT); auto request = session->CreateRequest(); request->SetUri("post/"); request->SetMethod(http_client::Method::Post); @@ -217,8 +220,8 @@ TEST_F(BasicCurlHttpTests, SendPostRequest) session->FinishSession(); ASSERT_TRUE(handler->is_called_); - session_manager.CancelAllSessions(); - session_manager.FinishAllSessions(); + session_manager->CancelAllSessions(); + session_manager->FinishAllSessions(); delete handler; } @@ -226,10 +229,11 @@ TEST_F(BasicCurlHttpTests, SendPostRequest) TEST_F(BasicCurlHttpTests, RequestTimeout) { received_requests_.clear(); - curl::SessionManager session_manager; + auto session_manager = http_client::HttpClientFactory::Create(); + EXPECT_TRUE(session_manager != nullptr); auto session = - session_manager.CreateSession("222.222.222.200", HTTP_PORT); // Non Existing address + session_manager->CreateSession("222.222.222.200", HTTP_PORT); // Non Existing address auto request = session->CreateRequest(); request->SetUri("get/"); GetEventHandler *handler = new GetEventHandler(); From 8702a102bfdd687639f3ed289a899556802db538 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Thu, 14 Jan 2021 21:48:39 -0800 Subject: [PATCH 09/16] Install protobuf generated header file for OTLP (#515) --- cmake/opentelemetry-proto.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/opentelemetry-proto.cmake b/cmake/opentelemetry-proto.cmake index 9f9a3fc0ee..b6cb66a3ab 100644 --- a/cmake/opentelemetry-proto.cmake +++ b/cmake/opentelemetry-proto.cmake @@ -141,6 +141,12 @@ install( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install( + DIRECTORY ${GENERATED_PROTOBUF_PATH}/opentelemetry + DESTINATION include + FILES_MATCHING + PATTERN "*.h") + if(TARGET protobuf::libprotobuf) target_link_libraries(opentelemetry_proto PUBLIC protobuf::libprotobuf) else() # cmake 3.8 or lower From bcfcc82e216c82d5fc29a53f1523faf44cacfb60 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Fri, 15 Jan 2021 10:44:59 -0800 Subject: [PATCH 10/16] Fix unsafe type cast and CRT call (#518) --- .../opentelemetry/exporters/etw/etw_provider_exporter.h | 2 +- exporters/etw/include/opentelemetry/exporters/etw/uuid.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 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 e69182b119..e9116534a2 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_provider_exporter.h @@ -408,7 +408,7 @@ class ETWProvider EVENT_DESCRIPTOR evtDescriptor; EventDescCreate(&evtDescriptor, 0, 0x1, 0, 0, 0, 0, 0); EVENT_DATA_DESCRIPTOR evtData[1]; - EventDataDescCreate(&evtData[0], v.data(), v.size()); + EventDataDescCreate(&evtData[0], v.data(), static_cast(v.size())); auto writeResponse = EventWrite(providerData.providerHandle, &evtDescriptor, 1, evtData); diff --git a/exporters/etw/include/opentelemetry/exporters/etw/uuid.h b/exporters/etw/include/opentelemetry/exporters/etw/uuid.h index 4a9640a924..dc9fac0e40 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/uuid.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/uuid.h @@ -99,11 +99,11 @@ struct UUID 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)) || + (11 == sscanf_s(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))) + (11 == sscanf_s(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); From 880e392e10b6d8e964ade2e22d7231950d6d2443 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Mon, 18 Jan 2021 00:40:24 -0800 Subject: [PATCH 11/16] Upgrade CMake to 3.15.2 for Linux (#516) --- ci/setup_cmake.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ci/setup_cmake.sh b/ci/setup_cmake.sh index 5693064c65..61a683b8e4 100755 --- a/ci/setup_cmake.sh +++ b/ci/setup_cmake.sh @@ -5,9 +5,17 @@ set -e export DEBIAN_FRONTEND=noninteractive apt-get update +export CMAKE_VERSION=3.15.2 + +pushd /tmp +wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.sh +chmod +x cmake-${CMAKE_VERSION}-Linux-x86_64.sh +./cmake-${CMAKE_VERSION}-Linux-x86_64.sh --prefix=/usr/local --skip-license +rm cmake-${CMAKE_VERSION}-Linux-x86_64.sh +popd + set +e echo \ - cmake \ libbenchmark-dev \ libgtest-dev \ zlib1g-dev \ From 0435edb9e6f14a5ea1793998cd0540594a54467b Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Wed, 20 Jan 2021 06:27:32 +0100 Subject: [PATCH 12/16] OTLP change default port number (#522) --- examples/otlp/README.md | 4 ++-- exporters/otlp/README.md | 6 +++--- .../include/opentelemetry/exporters/otlp/otlp_exporter.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/otlp/README.md b/examples/otlp/README.md index 9b1a8fd95a..7880bcccfd 100644 --- a/examples/otlp/README.md +++ b/examples/otlp/README.md @@ -15,7 +15,7 @@ receivers: otlp: protocols: grpc: - endpoint: localhost:55680 + endpoint: localhost:4317 exporters: zipkin: endpoint: "http://localhost:9411/api/v2/spans" @@ -26,6 +26,6 @@ service: exporters: [zipkin] ``` -Note that the OTLP exporter connects to the Collector at `localhost:55680` by default. This can be changed with first argument from command-line, for example: `./example_otlp gateway.docker.internal:55680`. +Note that the OTLP exporter connects to the Collector at `localhost:4317` by default. This can be changed with first argument from command-line, for example: `./example_otlp gateway.docker.internal:4317`. Once you have the Collector running, see [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and running the example. diff --git a/exporters/otlp/README.md b/exporters/otlp/README.md index 05915d7b27..7c6ea1d81f 100644 --- a/exporters/otlp/README.md +++ b/exporters/otlp/README.md @@ -18,9 +18,9 @@ auto exporter = std::unique_ptr(new otlp::OtlpExporter(o ### Configuration options -| Option | Default | -| ------------ |------------------ | -| `endpoint` | `localhost:55680` | +| Option | Default | +| ------------ |----------------- | +| `endpoint` | `localhost:4317` | ## Example diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h index e5a0fb8116..cb2b0066d2 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h @@ -14,7 +14,7 @@ namespace otlp struct OtlpExporterOptions { // The endpoint to export to. By default the OpenTelemetry Collector's default endpoint. - std::string endpoint = "localhost:55680"; + std::string endpoint = "localhost:4317"; }; /** From ab7f5f2054f0e5395b0bfde8032bab8cb7fc40bd Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Wed, 20 Jan 2021 20:19:02 -0800 Subject: [PATCH 13/16] Add spell check to CI (#527) --- .github/workflows/ci.yml | 12 ++++++++++++ Versioning.md | 2 +- api/include/opentelemetry/common/spin_lock_mutex.h | 2 +- api/include/opentelemetry/metrics/instrument.h | 2 +- api/include/opentelemetry/trace/span.h | 2 +- api/include/opentelemetry/trace/trace_state.h | 2 +- api/test/common/spinlock_benchmark.cc | 2 +- ci/ports/protobuf/portfile.cmake | 2 +- docs/cpp-metrics-api-design.md | 6 +++--- examples/metrics_simple/README.md | 2 +- exporters/elasticsearch/src/es_log_exporter.cc | 2 +- exporters/otlp/src/otlp_exporter.cc | 2 +- .../opentelemetry/ext/zpages/zpages_http_server.h | 2 +- ext/src/zpages/tracez_data_aggregator.cc | 6 +++--- ext/test/zpages/tracez_data_aggregator_test.cc | 6 +++--- sdk/include/opentelemetry/sdk/logs/logger.h | 2 +- .../sdk/metrics/aggregator/aggregator.h | 14 +++++++------- .../sdk/metrics/aggregator/counter_aggregator.h | 2 +- .../sdk/metrics/aggregator/histogram_aggregator.h | 2 +- .../sdk/metrics/aggregator/sketch_aggregator.h | 2 +- sdk/test/metrics/ungrouped_processor_test.cc | 2 +- sdk/test/trace/trace_id_ratio_sampler_test.cc | 2 +- 22 files changed, 45 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69fa811927..a4ee446c86 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -331,6 +331,18 @@ jobs: with: file: /home/runner/build/coverage.info + misspell: + runs-on: ubuntu-latest + steps: + - name: check out code + uses: actions/checkout@v2 + - name: install misspell + run: | + curl -L -o ./install-misspell.sh https://git.io/misspell + sh ./install-misspell.sh + - name: run misspell + run: ./bin/misspell -error . + docfx_check: name: DocFX check runs-on: windows-latest diff --git a/Versioning.md b/Versioning.md index dfa1bcac82..3cb4ac427c 100644 --- a/Versioning.md +++ b/Versioning.md @@ -42,7 +42,7 @@ Refer to the [ABI Policy](./docs/abi-policy.md) for more details. To summarise The guidelines in creating feature flag would be: - Naming: - - `ENABLE__PREVIEW` : For experimetal release of signal api/sdks eg, `METRICS_PREVIEW`, `LOGGING_PREVIEW`, + - `ENABLE__PREVIEW` : For experimental release of signal api/sdks eg, `METRICS_PREVIEW`, `LOGGING_PREVIEW`, - `ENABLE___PREVIEW` : For experimental release for any feature within stable signal. For example, `TRACING_JAEGER_PREVIEW` to release the experimental Jaeger exporter for tracing. diff --git a/api/include/opentelemetry/common/spin_lock_mutex.h b/api/include/opentelemetry/common/spin_lock_mutex.h index cf47a4fd07..66d291b116 100644 --- a/api/include/opentelemetry/common/spin_lock_mutex.h +++ b/api/include/opentelemetry/common/spin_lock_mutex.h @@ -68,7 +68,7 @@ class SpinLockMutex * Blocks until a lock can be obtained for the current thread. * * This mutex will spin the current CPU waiting for the lock to be available. This can have - * decent performance in scenarios where there is low lock contention and lock-holders acheive + * decent performance in scenarios where there is low lock contention and lock-holders achieve * their work quickly. It degrades in scenarios where locked tasks take a long time. */ void lock() noexcept diff --git a/api/include/opentelemetry/metrics/instrument.h b/api/include/opentelemetry/metrics/instrument.h index 45d8339481..5d1c07a5d5 100644 --- a/api/include/opentelemetry/metrics/instrument.h +++ b/api/include/opentelemetry/metrics/instrument.h @@ -38,7 +38,7 @@ class Instrument * @param description explains what the metric captures * @param unit specifies the data type held in the instrument * @param enabled determines if the metric is currently capturing data - * @return Instrument type with the specified attirbutes + * @return Instrument type with the specified attributes */ Instrument(nostd::string_view name, nostd::string_view description, diff --git a/api/include/opentelemetry/trace/span.h b/api/include/opentelemetry/trace/span.h index 1d046e1f9e..e202f6e584 100644 --- a/api/include/opentelemetry/trace/span.h +++ b/api/include/opentelemetry/trace/span.h @@ -47,7 +47,7 @@ struct StartSpanOptions core::SystemTimestamp start_system_time; core::SteadyTimestamp start_steady_time; - // Explicitely set the parent of a Span. + // Explicitly set the parent of a Span. // // This defaults to an invalid span context. In this case, the Span is // automatically parented to the currently active span. diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h index 5afa0823f6..3b2e371009 100644 --- a/api/include/opentelemetry/trace/trace_state.h +++ b/api/include/opentelemetry/trace/trace_state.h @@ -117,7 +117,7 @@ class TraceState } // Creates an Entry for the key-value pair and adds it to entries. Returns true if pair was added - // succesfully, false otherwise. If value is null or entries_ is full, this function is a no-op. + // successfully, false otherwise. If value is null or entries_ is full, this function is a no-op. bool Set(nostd::string_view key, nostd::string_view value) noexcept { if (value.empty() || num_entries_ >= kMaxKeyValuePairs) diff --git a/api/test/common/spinlock_benchmark.cc b/api/test/common/spinlock_benchmark.cc index 3291fad06c..72b48bcac3 100644 --- a/api/test/common/spinlock_benchmark.cc +++ b/api/test/common/spinlock_benchmark.cc @@ -119,7 +119,7 @@ static void BM_ThreadYieldSpinLockThrashing(benchmark::State &s) [](std::atomic &l) { l.store(false, std::memory_order_release); }); } -// Run the benchamrks at 2x thread/core and measure the amount of time to thrash around. +// Run the benchmarks at 2x thread/core and measure the amount of time to thrash around. BENCHMARK(BM_SpinLockThrashing) ->RangeMultiplier(2) ->Range(1, std::thread::hardware_concurrency()) diff --git a/ci/ports/protobuf/portfile.cmake b/ci/ports/protobuf/portfile.cmake index f8610470ac..77b718e5fd 100644 --- a/ci/ports/protobuf/portfile.cmake +++ b/ci/ports/protobuf/portfile.cmake @@ -19,7 +19,7 @@ else() endif() if(NOT protobuf_BUILD_PROTOC_BINARIES AND NOT EXISTS ${CURRENT_INSTALLED_DIR}/../x86-windows/tools/protobuf) - message(FATAL_ERROR "Cross-targetting protobuf requires the x86-windows protoc to be available. Please install protobuf:x86-windows first.") + message(FATAL_ERROR "Cross-targeting protobuf requires the x86-windows protoc to be available. Please install protobuf:x86-windows first.") endif() if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") diff --git a/docs/cpp-metrics-api-design.md b/docs/cpp-metrics-api-design.md index cdfdbdecd0..8bf54d2893 100644 --- a/docs/cpp-metrics-api-design.md +++ b/docs/cpp-metrics-api-design.md @@ -316,8 +316,8 @@ public: * @param name is the identifier of the instrumenting library * @param description explains what the metric captures * @param unit specified the data type held in the instrument - * @param enabled determins if the metric is currently capturing data - * @return Instrument type with the specified attirbutes + * @param enabled determines if the metric is currently capturing data + * @return Instrument type with the specified attributes */ Instrument(nostd::string_view name, nostd::string_view description, nostd::string_view unit, bool enabled); @@ -412,7 +412,7 @@ public: /** * Captures data by activating the callback function associated with the - * instrument and storing its return value. Callbacks for asychronous + * instrument and storing its return value. Callbacks for asynchronous * instruments are defined during construction. * * @param none diff --git a/examples/metrics_simple/README.md b/examples/metrics_simple/README.md index 380fcf3951..30bc41406a 100644 --- a/examples/metrics_simple/README.md +++ b/examples/metrics_simple/README.md @@ -26,7 +26,7 @@ shared_ptr processor = shared_ptr(new Ungrou `metrics_sdk::PushController controller(meter, std::move(exporter), processor, 5);` `controller.start();` -6. Instrument code with synchronous and asynchronous instrument. These instruments can be placed in areas of interest to collect metrics and are created by the meter. Synchronous instruments are updated whenever the user desires with a value and label set. Calling add on a counter instrument for example will increase its value. Asynchronous instruments can be updated the same way, but are intended to recieve updates from a callback function. The callback below observes a value of 1. The user never has to call this function as it is automatically called by the controller. +6. Instrument code with synchronous and asynchronous instrument. These instruments can be placed in areas of interest to collect metrics and are created by the meter. Synchronous instruments are updated whenever the user desires with a value and label set. Calling add on a counter instrument for example will increase its value. Asynchronous instruments can be updated the same way, but are intended to receive updates from a callback function. The callback below observes a value of 1. The user never has to call this function as it is automatically called by the controller. ``` diff --git a/exporters/elasticsearch/src/es_log_exporter.cc b/exporters/elasticsearch/src/es_log_exporter.cc index 4e21acd6ad..18fb444ba6 100644 --- a/exporters/elasticsearch/src/es_log_exporter.cc +++ b/exporters/elasticsearch/src/es_log_exporter.cc @@ -191,7 +191,7 @@ sdklogs::ExportResult ElasticsearchLogExporter::Export( // End the session session->FinishSession(); - // If an error occured with the HTTP request + // If an error occurred with the HTTP request if (!write_successful) { // TODO: retry logic diff --git a/exporters/otlp/src/otlp_exporter.cc b/exporters/otlp/src/otlp_exporter.cc index 74851976ca..63db30436c 100644 --- a/exporters/otlp/src/otlp_exporter.cc +++ b/exporters/otlp/src/otlp_exporter.cc @@ -40,7 +40,7 @@ std::unique_ptr MakeServiceStub return proto::collector::trace::v1::TraceService::NewStub(channel); } -// -------------------------------- Contructors -------------------------------- +// -------------------------------- Constructors -------------------------------- OtlpExporter::OtlpExporter() : OtlpExporter(OtlpExporterOptions()) {} diff --git a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h index fb43ed0642..9438baf199 100644 --- a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h @@ -80,7 +80,7 @@ class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer } /** - * Helper that replaces all occurances a string within a string + * Helper that replaces all occurrences a string within a string * @param str string to modify * @param search substring to remove from str * @param replacement string to replace search with whenever search is found diff --git a/ext/src/zpages/tracez_data_aggregator.cc b/ext/src/zpages/tracez_data_aggregator.cc index 478b38eb96..b743a1d7d9 100644 --- a/ext/src/zpages/tracez_data_aggregator.cc +++ b/ext/src/zpages/tracez_data_aggregator.cc @@ -159,7 +159,7 @@ void TracezDataAggregator::AggregateSpans() * If in the future this is added then clearing of running spans will not bee * required. * For now this step of clearing and recalculating running span data is - * required because it is unkown which spans have moved from running to + * required because it is unknown which spans have moved from running to * completed since the previous call. Additionally, the span name can change * for spans while they are running. * @@ -170,9 +170,9 @@ void TracezDataAggregator::AggregateSpans() * unique identifiers to span data have not been added yet. * * A few things to note: - * i) Duplicate running spans may be recieved from the span processor in one + * i) Duplicate running spans may be received from the span processor in one * multiple successive calls to this function. - * ii) Only the newly completed spans are recieved by this function. + * ii) Only the newly completed spans are received by this function. * Completed spans will not be seen more than once **/ ClearRunningSpanData(); diff --git a/ext/test/zpages/tracez_data_aggregator_test.cc b/ext/test/zpages/tracez_data_aggregator_test.cc index 78812e22b3..a5240257cb 100644 --- a/ext/test/zpages/tracez_data_aggregator_test.cc +++ b/ext/test/zpages/tracez_data_aggregator_test.cc @@ -356,7 +356,7 @@ TEST_F(TracezDataAggregatorTest, MultipleErrorSpans) /** * This test checks to see that the maximum number of running samples(5) for a * bucket is not exceeded. If there are more spans than this for a single bucket - * it removes the earliest span that was recieved + * it removes the earliest span that was received */ TEST_F(TracezDataAggregatorTest, RunningSampleSpansOverCapacity) { @@ -387,7 +387,7 @@ TEST_F(TracezDataAggregatorTest, RunningSampleSpansOverCapacity) /** * This test checks to see that the maximum number of error samples(5) for a * bucket is not exceeded. If there are more spans than this for a single bucket - * it removes the earliest span that was recieved + * it removes the earliest span that was received */ TEST_F(TracezDataAggregatorTest, ErrorSampleSpansOverCapacity) { @@ -429,7 +429,7 @@ TEST_F(TracezDataAggregatorTest, ErrorSampleSpansOverCapacity) /** * This test checks to see that the maximum number of latency samples(5) for a * bucket is not exceeded. If there are more spans than this for a single bucket - * it removes the earliest span that was recieved + * it removes the earliest span that was received */ TEST_F(TracezDataAggregatorTest, CompletedSampleSpansOverCapacity) { diff --git a/sdk/include/opentelemetry/sdk/logs/logger.h b/sdk/include/opentelemetry/sdk/logs/logger.h index 8cf21a09f6..e9d3e38fc7 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger.h +++ b/sdk/include/opentelemetry/sdk/logs/logger.h @@ -70,7 +70,7 @@ class Logger final : public opentelemetry::logs::Logger core::SystemTimestamp timestamp) noexcept override; private: - // The logger provider of this Logger. Uses a weak_ptr to avoid cyclic dependancy issues the with + // The logger provider of this Logger. Uses a weak_ptr to avoid cyclic dependency issues the with // logger provider std::weak_ptr logger_provider_; diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h index 77c167cc57..f90f1d7b5a 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h @@ -105,25 +105,25 @@ class Aggregator */ virtual bool is_updated() final { return updated_; } - // virtual function to be overriden for the Histogram Aggregator + // virtual function to be overridden for the Histogram Aggregator virtual std::vector get_boundaries() { return std::vector(); } - // virtual function to be overriden for the Histogram Aggregator + // virtual function to be overridden for the Histogram Aggregator virtual std::vector get_counts() { return std::vector(); } - // virtual function to be overriden for Exact and Sketch Aggregators + // virtual function to be overridden for Exact and Sketch Aggregators virtual bool get_quant_estimation() { return false; } - // virtual function to be overriden for Exact and Sketch Aggregators + // virtual function to be overridden for Exact and Sketch Aggregators virtual T get_quantiles(double q) { return values_[0]; } - // virtual function to be overriden for Sketch Aggregator + // virtual function to be overridden for Sketch Aggregator virtual double get_error_bound() { return 0; } - // virtual function to be overriden for Sketch Aggregator + // virtual function to be overridden for Sketch Aggregator virtual size_t get_max_buckets() { return 0; } - // virtual function to be overriden for Gauge Aggregator + // virtual function to be overridden for Gauge Aggregator virtual core::SystemTimestamp get_checkpoint_timestamp() { return core::SystemTimestamp(); } // Custom copy constructor to handle the mutex diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h index a82cf40766..e744d9b150 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h @@ -28,7 +28,7 @@ class CounterAggregator final : public Aggregator } /** - * Recieves a captured value from the instrument and applies it to the current aggregator value. + * Receives a captured value from the instrument and applies it to the current aggregator value. * * @param val, the raw value used in aggregation * @return none diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h index 785ae2733d..6cd417f650 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h @@ -48,7 +48,7 @@ class HistogramAggregator final : public Aggregator } /** - * Recieves a captured value from the instrument and inserts it into the current histogram counts. + * Receives a captured value from the instrument and inserts it into the current histogram counts. * * Depending on the use case, a linear search or binary search based implementation may be * preferred. In uniformly distributed datasets, linear search outperforms binary search until 512 diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/sketch_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/sketch_aggregator.h index 26baba5b42..4de4174df2 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/sketch_aggregator.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/sketch_aggregator.h @@ -96,7 +96,7 @@ class SketchAggregator final : public Aggregator /** * Calculate and return the value of a user specified quantile. * - * @param q, the quantile to calculate (for example 0.5 is equivelant to the 50th percentile) + * @param q, the quantile to calculate (for example 0.5 is equivalent to the 50th percentile) */ virtual T get_quantiles(double q) override { diff --git a/sdk/test/metrics/ungrouped_processor_test.cc b/sdk/test/metrics/ungrouped_processor_test.cc index 2b69d574cd..0ecff02659 100644 --- a/sdk/test/metrics/ungrouped_processor_test.cc +++ b/sdk/test/metrics/ungrouped_processor_test.cc @@ -181,7 +181,7 @@ TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStateles } /** - * The following tests are for the Stateful verison of the processor. These tests will make sure + * The following tests are for the Stateful version of the processor. These tests will make sure * that when we send the same aggreagtor twice through process(), that the values will be merged. * We can easily recreate this expected value by making a test aggregator that is updated through * both process functions but only checkpointed at the end. diff --git a/sdk/test/trace/trace_id_ratio_sampler_test.cc b/sdk/test/trace/trace_id_ratio_sampler_test.cc index ff711630fa..4c2c270022 100644 --- a/sdk/test/trace/trace_id_ratio_sampler_test.cc +++ b/sdk/test/trace/trace_id_ratio_sampler_test.cc @@ -21,7 +21,7 @@ namespace * * @param context a required valid span context * @param sampler a required valid sampler - * @param iterations a requried number specifying the number of times to + * @param iterations a required number specifying the number of times to * generate a random trace_id and check if it should sample using the provided * provider and context */ From 1a55ef1c712df0525e8ded2bcfe7747718424f34 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Thu, 21 Jan 2021 10:27:28 +0530 Subject: [PATCH 14/16] Update PR merge requirement. (#524) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 080103ee6e..2192172b1d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -116,7 +116,7 @@ A PR is considered to be **ready to merge** when: * Trivial changes (typo, cosmetic, doc, etc.) don't have to wait for one day. * Urgent fixes can take exceptions as long as it has been actively communicated. -Any Maintainer can merge the PR once it is **ready to merge**. +Any Maintainer can merge the PR once it is **ready to merge**. Maintainer can make conscious judgement to merge pull requests which have not strictly met above mentioned requirements. If a PR has been stuck (e.g. there are lots of debates and people couldn't agree on each other), the owner should try to get people aligned by: From c4df3bfab00cc55021f3febd4e466ccf6827fdba Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Thu, 21 Jan 2021 12:16:34 +0530 Subject: [PATCH 15/16] fix namespace in trace_state class (#526) --- api/include/opentelemetry/trace/trace_state.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h index 3b2e371009..71b374010e 100644 --- a/api/include/opentelemetry/trace/trace_state.h +++ b/api/include/opentelemetry/trace/trace_state.h @@ -21,8 +21,7 @@ #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" -namespace opentelemetry -{ +OPENTELEMETRY_BEGIN_NAMESPACE namespace trace { @@ -193,4 +192,4 @@ class TraceState }; } // namespace trace -} // namespace opentelemetry +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file From a9ca938344f2360ae119b7e653a12de5f365e43f Mon Sep 17 00:00:00 2001 From: Siim Kallas Date: Thu, 21 Jan 2021 09:15:32 +0200 Subject: [PATCH 16/16] Fix grpc_cpp_plugin executable import (#525) --- cmake/opentelemetry-proto.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/opentelemetry-proto.cmake b/cmake/opentelemetry-proto.cmake index b6cb66a3ab..5484dcd439 100644 --- a/cmake/opentelemetry-proto.cmake +++ b/cmake/opentelemetry-proto.cmake @@ -82,8 +82,7 @@ foreach(IMPORT_DIR ${PROTOBUF_IMPORT_DIRS}) list(APPEND PROTOBUF_INCLUDE_FLAGS "-I${IMPORT_DIR}") endforeach() -get_target_property(gRPC_CPP_PLUGIN_EXECUTABLE gRPC::grpc_cpp_plugin - IMPORTED_LOCATION_RELEASE) +set(gRPC_CPP_PLUGIN_EXECUTABLE $) add_custom_command( OUTPUT ${COMMON_PB_H_FILE}