From d206b505e01df6b07e0fa9f7ddf104d19344f07b Mon Sep 17 00:00:00 2001 From: WenTao Ou Date: Thu, 13 Jan 2022 02:11:43 +0800 Subject: [PATCH] Logger: Propagating resources through LoggerProvider (#1154) --- CHANGELOG.md | 3 +- api/include/opentelemetry/common/macros.h | 26 +++ api/include/opentelemetry/logs/logger.h | 40 ++--- api/include/opentelemetry/logs/noop.h | 1 - api/test/logs/logger_test.cc | 1 - bazel/repository.bzl | 6 +- .../common/logs_foo_library/foo_library.cc | 2 +- examples/otlp/grpc_log_main.cc | 9 +- examples/otlp/http_log_main.cc | 7 +- exporters/elasticsearch/CMakeLists.txt | 5 +- .../elasticsearch/es_log_recordable.h | 62 ++++++- .../test/es_log_exporter_test.cc | 5 +- .../opentelemetry/exporters/etw/etw_logger.h | 22 ++- exporters/ostream/src/log_exporter.cc | 21 ++- exporters/ostream/test/ostream_log_test.cc | 35 ++-- .../exporters/otlp/otlp_log_recordable.h | 28 ++-- exporters/otlp/src/otlp_http_client.cc | 16 +- exporters/otlp/src/otlp_log_recordable.cc | 16 +- .../otlp/test/otlp_grpc_log_exporter_test.cc | 32 ++-- .../otlp/test/otlp_http_log_exporter_test.cc | 74 +++++---- .../otlp/test/otlp_log_recordable_test.cc | 4 +- .../sdk/common/empty_attributes.h | 4 +- .../opentelemetry/sdk/logs/log_record.h | 27 ++-- sdk/include/opentelemetry/sdk/logs/logger.h | 10 +- .../opentelemetry/sdk/logs/logger_context.h | 81 ++++++++++ .../opentelemetry/sdk/logs/logger_provider.h | 49 ++++-- .../sdk/logs/multi_log_processor.h | 69 ++++++++ .../opentelemetry/sdk/logs/multi_recordable.h | 96 +++++++++++ .../opentelemetry/sdk/logs/recordable.h | 10 +- .../opentelemetry/sdk/trace/tracer_provider.h | 6 - sdk/src/logs/BUILD | 1 + sdk/src/logs/CMakeLists.txt | 14 +- sdk/src/logs/logger.cc | 19 +-- sdk/src/logs/logger_context.cc | 54 +++++++ sdk/src/logs/logger_provider.cc | 42 ++++- sdk/src/logs/multi_log_processor.cc | 153 ++++++++++++++++++ sdk/src/logs/multi_recordable.cc | 136 ++++++++++++++++ sdk/test/logs/log_record_test.cc | 7 +- sdk/test/logs/logger_provider_sdk_test.cc | 12 +- sdk/test/logs/logger_sdk_test.cc | 4 +- 40 files changed, 972 insertions(+), 237 deletions(-) create mode 100644 api/include/opentelemetry/common/macros.h create mode 100644 sdk/include/opentelemetry/sdk/logs/logger_context.h create mode 100644 sdk/include/opentelemetry/sdk/logs/multi_log_processor.h create mode 100644 sdk/include/opentelemetry/sdk/logs/multi_recordable.h create mode 100644 sdk/src/logs/logger_context.cc create mode 100644 sdk/src/logs/multi_log_processor.cc create mode 100644 sdk/src/logs/multi_recordable.cc diff --git a/CHANGELOG.md b/CHANGELOG.md index fbae450f6f..5ae67939cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,8 +16,9 @@ Increment the: ## [Unreleased] * [SDK] Add LogLevel to internal_log ([#1147](https://github.com/open-telemetry/opentelemetry-cpp/pull/1147)) +* [API/SDK] Logger: Propagating resources through LoggerProvider ([#1154](https://github.com/open-telemetry/opentelemetry-cpp/pull/1154)) -## [1.1.1] 2021-12- +## [1.1.1] 2021-12-20 * [SDK] Rename OTEL_CPP_GET_ATTR macro, and define it using fully qualified attr function ([#1140](https://github.com/open-telemetry/opentelemetry-cpp/pull/1140)) * [SDK] Default resource attributes and attributes in OTEL_RESOURCE_ATTRIBUTES are missing when using Otlp*LogExporter ([#1082](https://github.com/open-telemetry/opentelemetry-cpp/pull/1082)) diff --git a/api/include/opentelemetry/common/macros.h b/api/include/opentelemetry/common/macros.h new file mode 100644 index 0000000000..8c2b6bd175 --- /dev/null +++ b/api/include/opentelemetry/common/macros.h @@ -0,0 +1,26 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "opentelemetry/version.h" + +/// \brief Declare variable as maybe unused +/// usage: +/// OPENTELEMETRY_MAYBE_UNUSED int a; +/// class OPENTELEMETRY_MAYBE_UNUSED a; +/// OPENTELEMETRY_MAYBE_UNUSED int a(); +/// +#if defined(__cplusplus) && __cplusplus >= 201703L +# define OPENTELEMETRY_MAYBE_UNUSED [[maybe_unused]] +#elif defined(__clang__) +# define OPENTELEMETRY_MAYBE_UNUSED __attribute__((unused)) +#elif defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +# define OPENTELEMETRY_MAYBE_UNUSED __attribute__((unused)) +#elif (defined(_MSC_VER) && _MSC_VER >= 1910) && (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define OPENTELEMETRY_MAYBE_UNUSED [[maybe_unused]] +#else +# define OPENTELEMETRY_MAYBE_UNUSED +#endif diff --git a/api/include/opentelemetry/logs/logger.h b/api/include/opentelemetry/logs/logger.h index 5ce878d760..91e882717f 100644 --- a/api/include/opentelemetry/logs/logger.h +++ b/api/include/opentelemetry/logs/logger.h @@ -43,8 +43,6 @@ class Logger * @param severity the severity level of the log event. * @param name the name of the log event. * @param message the string message of the log (perhaps support std::fmt or fmt-lib format). - * @param resource the resources, stored as a 2D list of key/value pairs, that are associated - * with the log event. * @param attributes the attributes, stored as a 2D list of key/value pairs, that are associated * with the log event. * @param trace_id the trace id associated with the log event. @@ -57,13 +55,10 @@ class Logger /** * The base Log(...) method that all other Log(...) overloaded methods will eventually call, * in order to create a log record. - * - * Note this takes in a KeyValueIterable for the resource and attributes fields. */ virtual void Log(Severity severity, nostd::string_view name, nostd::string_view body, - const common::KeyValueIterable &resource, const common::KeyValueIterable &attributes, trace::TraceId trace_id, trace::SpanId span_id, @@ -74,31 +69,25 @@ class Logger /** * The secondary base Log(...) method that all other Log(...) overloaded methods except the one * above will eventually call, in order to create a log record. - * - * Note this takes in template types for the resource and attributes fields. */ template ::value> * = nullptr, - nostd::enable_if_t::value> * = nullptr> + nostd::enable_if_t::value> * = nullptr> void Log(Severity severity, nostd::string_view name, nostd::string_view body, - const T &resource, - const U &attributes, + const T &attributes, trace::TraceId trace_id, trace::SpanId span_id, trace::TraceFlags trace_flags, common::SystemTimestamp timestamp) noexcept { - Log(severity, name, body, common::KeyValueIterableView(resource), - common::KeyValueIterableView(attributes), trace_id, span_id, trace_flags, timestamp); + Log(severity, name, body, common::KeyValueIterableView(attributes), trace_id, span_id, + trace_flags, timestamp); } void Log(Severity severity, nostd::string_view name, nostd::string_view body, - std::initializer_list> resource, std::initializer_list> attributes, trace::TraceId trace_id, trace::SpanId span_id, @@ -106,8 +95,6 @@ class Logger common::SystemTimestamp timestamp) noexcept { return this->Log(severity, name, body, - nostd::span>{ - resource.begin(), resource.end()}, nostd::span>{ attributes.begin(), attributes.end()}, trace_id, span_id, trace_flags, timestamp); @@ -122,7 +109,7 @@ class Logger */ void Log(Severity severity, nostd::string_view message) noexcept { - this->Log(severity, "", message, {}, {}, {}, {}, {}, std::chrono::system_clock::now()); + this->Log(severity, "", message, {}, {}, {}, {}, std::chrono::system_clock::now()); } /** @@ -133,7 +120,7 @@ class Logger */ void Log(Severity severity, nostd::string_view name, nostd::string_view message) noexcept { - this->Log(severity, name, message, {}, {}, {}, {}, {}, std::chrono::system_clock::now()); + this->Log(severity, name, message, {}, {}, {}, {}, std::chrono::system_clock::now()); } /** @@ -145,8 +132,7 @@ class Logger nostd::enable_if_t::value> * = nullptr> void Log(Severity severity, const T &attributes) noexcept { - this->Log(severity, "", "", std::map{}, attributes, {}, {}, {}, - std::chrono::system_clock::now()); + this->Log(severity, "", "", attributes, {}, {}, {}, std::chrono::system_clock::now()); } /** @@ -159,8 +145,7 @@ class Logger nostd::enable_if_t::value> * = nullptr> void Log(Severity severity, nostd::string_view name, const T &attributes) noexcept { - this->Log(severity, name, "", std::map{}, attributes, {}, {}, {}, - std::chrono::system_clock::now()); + this->Log(severity, name, "", attributes, {}, {}, {}, std::chrono::system_clock::now()); } /** @@ -172,7 +157,7 @@ class Logger std::initializer_list> attributes) noexcept { - this->Log(severity, "", "", {}, attributes, {}, {}, {}, std::chrono::system_clock::now()); + this->Log(severity, "", "", attributes, {}, {}, {}, std::chrono::system_clock::now()); } /** @@ -186,7 +171,7 @@ class Logger std::initializer_list> attributes) noexcept { - this->Log(severity, name, "", {}, attributes, {}, {}, {}, std::chrono::system_clock::now()); + this->Log(severity, name, "", attributes, {}, {}, {}, std::chrono::system_clock::now()); } /** @@ -200,10 +185,7 @@ class Logger nostd::string_view name, common::KeyValueIterable &attributes) noexcept { - this->Log(severity, name, {}, - common::KeyValueIterableView< - std::initializer_list>>({}), - attributes, {}, {}, {}, std::chrono::system_clock::now()); + this->Log(severity, name, {}, attributes, {}, {}, {}, std::chrono::system_clock::now()); } /** Trace severity overloads **/ diff --git a/api/include/opentelemetry/logs/noop.h b/api/include/opentelemetry/logs/noop.h index a61507093c..571c5cdbf8 100644 --- a/api/include/opentelemetry/logs/noop.h +++ b/api/include/opentelemetry/logs/noop.h @@ -44,7 +44,6 @@ class NoopLogger final : public Logger void Log(Severity severity, nostd::string_view name, nostd::string_view body, - const common::KeyValueIterable &resource, const common::KeyValueIterable &attributes, trace::TraceId trace_id, trace::SpanId span_id, diff --git a/api/test/logs/logger_test.cc b/api/test/logs/logger_test.cc index 99c7474280..dad5cac7f6 100644 --- a/api/test/logs/logger_test.cc +++ b/api/test/logs/logger_test.cc @@ -80,7 +80,6 @@ class TestLogger : public Logger void Log(Severity severity, string_view name, string_view body, - const common::KeyValueIterable &resource, const common::KeyValueIterable &attributes, trace::TraceId trace_id, trace::SpanId span_id, diff --git a/bazel/repository.bzl b/bazel/repository.bzl index 6f9826e801..eed7ebe157 100644 --- a/bazel/repository.bzl +++ b/bazel/repository.bzl @@ -9,10 +9,10 @@ def opentelemetry_cpp_deps(): maybe( http_archive, name = "com_github_google_benchmark", - sha256 = "dccbdab796baa1043f04982147e67bb6e118fe610da2c65f88912d73987e700c", - strip_prefix = "benchmark-1.5.2", + sha256 = "1f71c72ce08d2c1310011ea6436b31e39ccab8c2db94186d26657d41747c85d6", + strip_prefix = "benchmark-1.6.0", urls = [ - "https://github.com/google/benchmark/archive/v1.5.2.tar.gz", + "https://github.com/google/benchmark/archive/v1.6.0.tar.gz", ], ) diff --git a/examples/common/logs_foo_library/foo_library.cc b/examples/common/logs_foo_library/foo_library.cc index a5b8d9ae98..7c545f2d1a 100644 --- a/examples/common/logs_foo_library/foo_library.cc +++ b/examples/common/logs_foo_library/foo_library.cc @@ -32,7 +32,7 @@ void foo_library() auto scoped_span = trace::Scope(get_tracer()->StartSpan("foo_library")); auto ctx = span->GetContext(); auto logger = get_logger(); - logger->Log(opentelemetry::logs::Severity::kDebug, "name", "body", {}, {}, ctx.trace_id(), + logger->Log(opentelemetry::logs::Severity::kDebug, "name", "body", {}, ctx.trace_id(), ctx.span_id(), ctx.trace_flags(), opentelemetry::common::SystemTimestamp()); } #endif diff --git a/examples/otlp/grpc_log_main.cc b/examples/otlp/grpc_log_main.cc index d937e450ab..9a578c7fbd 100644 --- a/examples/otlp/grpc_log_main.cc +++ b/examples/otlp/grpc_log_main.cc @@ -44,11 +44,10 @@ void InitTracer() void InitLogger() { // Create OTLP exporter instance - auto exporter = std::unique_ptr(new otlp::OtlpGrpcLogExporter(opts)); - auto processor = std::shared_ptr( - new logs_sdk::SimpleLogProcessor(std::move(exporter))); - auto sdkProvider = std::shared_ptr(new logs_sdk::LoggerProvider()); - sdkProvider->SetProcessor(processor); + auto exporter = std::unique_ptr(new otlp::OtlpGrpcLogExporter(opts)); + auto sdkProvider = std::shared_ptr( + new logs_sdk::LoggerProvider(std::unique_ptr( + new logs_sdk::SimpleLogProcessor(std::move(exporter))))); auto apiProvider = nostd::shared_ptr(sdkProvider); auto provider = nostd::shared_ptr(apiProvider); opentelemetry::logs::Provider::SetLoggerProvider(provider); diff --git a/examples/otlp/http_log_main.cc b/examples/otlp/http_log_main.cc index 0f1989d853..b56dcf5aa5 100644 --- a/examples/otlp/http_log_main.cc +++ b/examples/otlp/http_log_main.cc @@ -49,10 +49,9 @@ void InitLogger() // Create OTLP exporter instance auto exporter = std::unique_ptr(new otlp::OtlpHttpLogExporter(logger_opts)); - auto processor = std::shared_ptr( - new logs_sdk::SimpleLogProcessor(std::move(exporter))); - auto sdkProvider = std::shared_ptr(new logs_sdk::LoggerProvider()); - sdkProvider->SetProcessor(processor); + auto sdkProvider = std::shared_ptr( + new logs_sdk::LoggerProvider(std::unique_ptr( + new logs_sdk::SimpleLogProcessor(std::move(exporter))))); auto apiProvider = nostd::shared_ptr(sdkProvider); auto provider = nostd::shared_ptr(apiProvider); opentelemetry::logs::Provider::SetLoggerProvider(provider); diff --git a/exporters/elasticsearch/CMakeLists.txt b/exporters/elasticsearch/CMakeLists.txt index 8f675e530a..1538a6f44a 100644 --- a/exporters/elasticsearch/CMakeLists.txt +++ b/exporters/elasticsearch/CMakeLists.txt @@ -8,8 +8,9 @@ target_include_directories( PUBLIC "$" "$") -target_link_libraries(opentelemetry_exporter_elasticsearch_logs - PUBLIC opentelemetry_trace http_client_curl) +target_link_libraries( + opentelemetry_exporter_elasticsearch_logs + PUBLIC opentelemetry_trace opentelemetry_logs http_client_curl) install( TARGETS opentelemetry_exporter_elasticsearch_logs 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 8a928d829e..45dbb63ae8 100644 --- a/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_recordable.h +++ b/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_recordable.h @@ -5,7 +5,10 @@ #ifdef ENABLE_LOGS_PREVIEW # include +# include +# include # include + # include "nlohmann/json.hpp" # include "opentelemetry/sdk/common/attribute_utils.h" # include "opentelemetry/sdk/logs/recordable.h" @@ -67,6 +70,39 @@ class ElasticSearchRecordable final : public sdk::logs::Recordable } } + void WriteKeyValue(nostd::string_view key, + const opentelemetry::sdk::common::OwnedAttributeValue &value, + std::string name) + { + namespace common = opentelemetry::sdk::common; + switch (value.index()) + { + case common::kTypeBool: + json_[name][key.data()] = opentelemetry::nostd::get(value) ? true : false; + return; + case common::kTypeInt: + json_[name][key.data()] = opentelemetry::nostd::get(value); + return; + case common::kTypeInt64: + json_[name][key.data()] = opentelemetry::nostd::get(value); + return; + case common::kTypeUInt: + json_[name][key.data()] = opentelemetry::nostd::get(value); + return; + case common::kTypeUInt64: + json_[name][key.data()] = opentelemetry::nostd::get(value); + return; + case common::kTypeDouble: + json_[name][key.data()] = opentelemetry::nostd::get(value); + return; + case common::kTypeString: + json_[name][key.data()] = opentelemetry::nostd::get(value).data(); + return; + default: + return; + } + } + public: /** * Set the severity for this log. @@ -75,7 +111,18 @@ class ElasticSearchRecordable final : public sdk::logs::Recordable void SetSeverity(opentelemetry::logs::Severity severity) noexcept override { // Convert the severity enum to a string - json_["severity"] = opentelemetry::logs::SeverityNumToText[static_cast(severity)]; + int severity_index = static_cast(severity); + if (severity_index < 0 || + severity_index >= std::extent::value) + { + std::stringstream sout; + sout << "Invalid severity(" << severity_index << ")"; + json_["severity"] = sout.str(); + } + else + { + json_["severity"] = opentelemetry::logs::SeverityNumToText[severity_index]; + } } /** @@ -91,14 +138,15 @@ class ElasticSearchRecordable final : public sdk::logs::Recordable void SetBody(nostd::string_view message) noexcept override { json_["body"] = message.data(); } /** - * Set a resource for this log. - * @param name the name of the resource - * @param value the resource value + * Set Resource of this log + * @param Resource the resource to set */ - void SetResource(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept override + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override { - WriteKeyValue(key, value, "resource"); + for (auto &kv : resource.GetAttributes()) + { + WriteKeyValue(kv.first, kv.second, "resource"); + } } /** diff --git a/exporters/elasticsearch/test/es_log_exporter_test.cc b/exporters/elasticsearch/test/es_log_exporter_test.cc index 8aa5cd654c..d32048e83d 100644 --- a/exporters/elasticsearch/test/es_log_exporter_test.cc +++ b/exporters/elasticsearch/test/es_log_exporter_test.cc @@ -77,8 +77,9 @@ TEST(ElasticsearchLogsExporterTests, RecordableCreation) // Attributes and resource support different types record->SetAttribute("key0", false); record->SetAttribute("key1", "1"); - record->SetResource("key2", 2); - record->SetResource("key3", 3.142); + + auto resource = opentelemetry::sdk::resource::Resource::Create({{"key2", 2}, {"key3", 3142}}); + record->SetResource(resource); exporter->Export(nostd::span>(&record, 1)); } diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h index 3420b3f5db..5acd92f3f0 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h @@ -9,6 +9,8 @@ # include # include # include +# include +# include # include @@ -101,7 +103,6 @@ class Logger : public opentelemetry::logs::Logger void Log(opentelemetry::logs::Severity severity, nostd::string_view name, nostd::string_view body, - const common::KeyValueIterable &resource, const common::KeyValueIterable &attributes, opentelemetry::trace::TraceId trace_id, opentelemetry::trace::SpanId span_id, @@ -111,8 +112,7 @@ class Logger : public opentelemetry::logs::Logger # ifdef RTTI_ENABLED common::KeyValueIterable &attribs = const_cast(attributes); - // common::KeyValueIterable &resr = const_cast(resource); - Properties *evt = dynamic_cast(&attribs); + Properties *evt = dynamic_cast(&attribs); // Properties *res = dynamic_cast(&resr); if (evt != nullptr) @@ -122,7 +122,6 @@ class Logger : public opentelemetry::logs::Logger } # endif Properties evtCopy = attributes; - // Properties resCopy = resource; return Log(severity, name, body, evtCopy, trace_id, span_id, trace_flags, timestamp); } @@ -169,8 +168,19 @@ class Logger : public opentelemetry::logs::Logger int64_t tsMs = std::chrono::duration_cast(ts.time_since_epoch()).count(); evt[ETW_FIELD_TIMESTAMP] = utils::formatUtcTimestampMsAsISO8601(tsMs); - evt[ETW_FIELD_LOG_SEVERITY_TEXT] = - opentelemetry::logs::SeverityNumToText[static_cast(severity)].data(); + int severity_index = static_cast(severity); + if (severity_index < 0 || + severity_index >= std::extent::value) + { + std::stringstream sout; + sout << "Invalid severity(" << severity_index << ")"; + evt[ETW_FIELD_LOG_SEVERITY_TEXT] = sout.str(); + } + else + { + evt[ETW_FIELD_LOG_SEVERITY_TEXT] = + opentelemetry::logs::SeverityNumToText[severity_index].data(); + } evt[ETW_FIELD_LOG_SEVERITY_NUM] = static_cast(severity); evt[ETW_FIELD_LOG_BODY] = std::string(body.data(), body.length()); etwProvider().write(provHandle, evt, nullptr, nullptr, 0, encoding); diff --git a/exporters/ostream/src/log_exporter.cc b/exporters/ostream/src/log_exporter.cc index 3bfb40dd52..c11ec13786 100644 --- a/exporters/ostream/src/log_exporter.cc +++ b/exporters/ostream/src/log_exporter.cc @@ -7,6 +7,7 @@ # include "opentelemetry/sdk_config.h" # include +# include namespace nostd = opentelemetry::nostd; namespace sdklogs = opentelemetry::sdk::logs; @@ -146,14 +147,24 @@ sdk::common::ExportResult OStreamLogExporter::Export( sout_ << "{\n" << " timestamp : " << log_record->GetTimestamp().time_since_epoch().count() << "\n" << " severity_num : " << static_cast(log_record->GetSeverity()) << "\n" - << " severity_text : " - << opentelemetry::logs::SeverityNumToText[static_cast(log_record->GetSeverity())] - << "\n" - << " name : " << log_record->GetName() << "\n" + << " severity_text : "; + + int severity_index = static_cast(log_record->GetSeverity()); + if (severity_index < 0 || + severity_index >= std::extent::value) + { + sout_ << "Invalid severity(" << severity_index << ")\n"; + } + else + { + sout_ << opentelemetry::logs::SeverityNumToText[severity_index] << "\n"; + } + + sout_ << " name : " << log_record->GetName() << "\n" << " body : " << log_record->GetBody() << "\n" << " resource : "; - printMap(log_record->GetResource(), sout_); + printMap(log_record->GetResource().GetAttributes(), sout_); sout_ << "\n" << " attributes : "; diff --git a/exporters/ostream/test/ostream_log_test.cc b/exporters/ostream/test/ostream_log_test.cc index 80abdadfcf..839c323129 100644 --- a/exporters/ostream/test/ostream_log_test.cc +++ b/exporters/ostream/test/ostream_log_test.cc @@ -81,7 +81,8 @@ TEST(OstreamLogExporter, DefaultLogRecordToCout) " severity_text : INVALID\n" " name : \n" " body : \n" - " resource : {}\n" + " resource : {{telemetry.sdk.version: " OPENTELEMETRY_VERSION + "}, {telemetry.sdk.name: opentelemetry}, {telemetry.sdk.language: cpp}}\n" " attributes : {}\n" " trace_id : 00000000000000000000000000000000\n" " span_id : 0000000000000000\n" @@ -129,7 +130,9 @@ TEST(OStreamLogExporter, SimpleLogToCout) " severity_text : TRACE\n" " name : Name\n" " body : Message\n" - " resource : {}\n" + " resource : {{telemetry.sdk.version: " OPENTELEMETRY_VERSION + "}, {telemetry.sdk.name: opentelemetry}, " + "{telemetry.sdk.language: cpp}}\n" " attributes : {}\n" " trace_id : 00000000000000000000000000000000\n" " span_id : 0000000000000000\n" @@ -157,7 +160,8 @@ TEST(OStreamLogExporter, LogWithStringAttributesToCerr) auto record = exporter->MakeRecordable(); // Set resources for this log record only of type - record->SetResource("key1", "val1"); + auto resource = opentelemetry::sdk::resource::Resource::Create({{"key1", "val1"}}); + record->SetResource(resource); // Set attributes to this log record of type record->SetAttribute("a", true); @@ -175,7 +179,9 @@ TEST(OStreamLogExporter, LogWithStringAttributesToCerr) " severity_text : INVALID\n" " name : \n" " body : \n" - " resource : {{key1: val1}}\n" + " resource : {{telemetry.sdk.version: " OPENTELEMETRY_VERSION + "}, {telemetry.sdk.name: opentelemetry}, {telemetry.sdk.language: cpp}, {service.name: " + "unknown_service}, {key1: val1}}\n" " attributes : {{a: 1}}\n" " trace_id : 00000000000000000000000000000000\n" " span_id : 0000000000000000\n" @@ -206,7 +212,9 @@ TEST(OStreamLogExporter, LogWithVariantTypesToClog) // Set resources for this log record of only integer types as the value std::array array1 = {1, 2, 3}; nostd::span data1{array1.data(), array1.size()}; - record->SetResource("res1", data1); + + auto resource = opentelemetry::sdk::resource::Resource::Create({{"res1", data1}}); + record->SetResource(resource); // Set resources for this log record of bool types as the value // e.g. key/value is a par of type @@ -226,7 +234,9 @@ TEST(OStreamLogExporter, LogWithVariantTypesToClog) " severity_text : INVALID\n" " name : \n" " body : \n" - " resource : {{res1: [1, 2, 3]}}\n" + " resource : {{service.name: unknown_service}, " + "{telemetry.sdk.version: " OPENTELEMETRY_VERSION + "}, {telemetry.sdk.name: opentelemetry}, {telemetry.sdk.language: cpp}, {res1: [1, 2, 3]}}\n" " attributes : {{attr1: [0, 1, 0]}}\n" " trace_id : 00000000000000000000000000000000\n" " span_id : 0000000000000000\n" @@ -242,11 +252,10 @@ TEST(OStreamLogExporter, LogWithVariantTypesToClog) TEST(OStreamLogExporter, IntegrationTest) { // Initialize a logger - auto exporter = std::unique_ptr(new exporterlogs::OStreamLogExporter); - auto processor = - std::shared_ptr(new sdklogs::SimpleLogProcessor(std::move(exporter))); + auto exporter = std::unique_ptr(new exporterlogs::OStreamLogExporter); auto sdkProvider = std::shared_ptr(new sdklogs::LoggerProvider()); - sdkProvider->SetProcessor(processor); + sdkProvider->AddProcessor( + std::unique_ptr(new sdklogs::SimpleLogProcessor(std::move(exporter)))); auto apiProvider = nostd::shared_ptr(sdkProvider); auto provider = nostd::shared_ptr(apiProvider); logs_api::Provider::SetLoggerProvider(provider); @@ -261,7 +270,7 @@ TEST(OStreamLogExporter, IntegrationTest) // Write a log to ostream exporter common::SystemTimestamp now(std::chrono::system_clock::now()); - logger->Log(logs_api::Severity::kDebug, "", "Hello", {}, {}, {}, {}, {}, now); + logger->Log(logs_api::Severity::kDebug, "", "Hello", {}, {}, {}, {}, now); // Restore cout's original streambuf std::cout.rdbuf(original); @@ -276,7 +285,9 @@ TEST(OStreamLogExporter, IntegrationTest) " severity_text : DEBUG\n" " name : \n" " body : Hello\n" - " resource : {}\n" + " resource : {{service.name: unknown_service}, " + "{telemetry.sdk.version: " OPENTELEMETRY_VERSION + "}, {telemetry.sdk.name: opentelemetry}, {telemetry.sdk.language: cpp}}\n" " attributes : {}\n" " trace_id : 00000000000000000000000000000000\n" " span_id : 0000000000000000\n" diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_log_recordable.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_log_recordable.h index 368505ca2a..06d0ba7160 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_log_recordable.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_log_recordable.h @@ -40,63 +40,61 @@ class OtlpLogRecordable final : public opentelemetry::sdk::logs::Recordable * Set the timestamp for this log. * @param timestamp the timestamp to set */ - virtual void SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept override; + void SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept override; /** * Set the severity for this log. * @param severity the severity of the event */ - virtual void SetSeverity(opentelemetry::logs::Severity severity) noexcept override; + void SetSeverity(opentelemetry::logs::Severity severity) noexcept override; /** * Set name for this log * @param name the name to set */ - virtual void SetName(nostd::string_view name) noexcept override; + void SetName(nostd::string_view name) noexcept override; /** * Set body field for this log. * @param message the body to set */ - virtual void SetBody(nostd::string_view message) noexcept override; + void SetBody(nostd::string_view message) noexcept override; /** - * Set a single resource of a log record. - * @param key the name of the resource to set - * @param value the resource value to set + * Set Resource of this log + * @param Resource the resource to set */ - virtual void SetResource(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept override; + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override; /** * Set an attribute of a log. * @param key the name of the attribute * @param value the attribute value */ - virtual void SetAttribute(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept override; + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept override; /** * Set the trace id for this log. * @param trace_id the trace id to set */ - virtual void SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept override; + void SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept override; /** * Set the span id for this log. * @param span_id the span id to set */ - virtual void SetSpanId(opentelemetry::trace::SpanId span_id) noexcept override; + void SetSpanId(opentelemetry::trace::SpanId span_id) noexcept override; /** * Inject trace_flags for this log. * @param trace_flags the trace flags to set */ - virtual void SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept override; + void SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept override; private: proto::logs::v1::LogRecord log_record_; - opentelemetry::sdk::common::AttributeMap resource_attributes_; + const opentelemetry::sdk::resource::Resource *resource_ = nullptr; // TODO shared resource // const opentelemetry::sdk::resource::Resource *resource_ = nullptr; // TODO InstrumentationLibrary diff --git a/exporters/otlp/src/otlp_http_client.cc b/exporters/otlp/src/otlp_http_client.cc index aa65279bc3..fd86b1e136 100644 --- a/exporters/otlp/src/otlp_http_client.cc +++ b/exporters/otlp/src/otlp_http_client.cc @@ -362,6 +362,18 @@ static void ConvertGenericMessageToJson(nlohmann::json &value, } } +static bool SerializeToHttpBody(http_client::Body &output, const google::protobuf::Message &message) +{ + auto body_size = message.ByteSizeLong(); + if (body_size > 0) + { + output.resize(body_size); + return message.SerializeWithCachedSizesToArray( + reinterpret_cast(&output[0])); + } + return true; +} + void ConvertGenericFieldToJson(nlohmann::json &value, const google::protobuf::Message &message, const google::protobuf::FieldDescriptor *field_descriptor, @@ -601,9 +613,7 @@ opentelemetry::sdk::common::ExportResult OtlpHttpClient::Export( std::string content_type; if (options_.content_type == HttpRequestContentType::kBinary) { - body_vec.resize(message.ByteSizeLong()); - if (message.SerializeWithCachedSizesToArray( - reinterpret_cast(&body_vec[0]))) + if (SerializeToHttpBody(body_vec, message)) { if (options_.console_debug) { diff --git a/exporters/otlp/src/otlp_log_recordable.cc b/exporters/otlp/src/otlp_log_recordable.cc index 5276b62690..9df2b42d07 100644 --- a/exporters/otlp/src/otlp_log_recordable.cc +++ b/exporters/otlp/src/otlp_log_recordable.cc @@ -18,8 +18,15 @@ namespace otlp proto::resource::v1::Resource OtlpLogRecordable::ProtoResource() const noexcept { proto::resource::v1::Resource proto; - OtlpRecordableUtils::PopulateAttribute( - &proto, opentelemetry::sdk::resource::Resource::Create(resource_attributes_)); + if (nullptr == resource_) + { + OtlpRecordableUtils::PopulateAttribute(&proto, sdk::resource::Resource::GetDefault()); + } + else + { + OtlpRecordableUtils::PopulateAttribute(&proto, *resource_); + } + return proto; } @@ -170,10 +177,9 @@ void OtlpLogRecordable::SetBody(nostd::string_view message) noexcept log_record_.mutable_body()->set_string_value(message.data(), message.size()); } -void OtlpLogRecordable::SetResource(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept +void OtlpLogRecordable::SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept { - resource_attributes_.SetAttribute(key, value); + resource_ = &resource; } void OtlpLogRecordable::SetAttribute(nostd::string_view key, diff --git a/exporters/otlp/test/otlp_grpc_log_exporter_test.cc b/exporters/otlp/test/otlp_grpc_log_exporter_test.cc index 0f28e46c24..81d46ea3e3 100644 --- a/exporters/otlp/test/otlp_grpc_log_exporter_test.cc +++ b/exporters/otlp/test/otlp_grpc_log_exporter_test.cc @@ -114,16 +114,16 @@ TEST_F(OtlpGrpcLogExporterTestPeer, ExportIntegrationTest) auto exporter = GetExporter(stub_interface); - bool resource_storage_bool_value[] = {true, false, true}; - int32_t resource_storage_int32_value[] = {1, 2}; - uint32_t resource_storage_uint32_value[] = {3, 4}; - int64_t resource_storage_int64_value[] = {5, 6}; - uint64_t resource_storage_uint64_value[] = {7, 8}; - double resource_storage_double_value[] = {3.2, 3.3}; - std::string resource_storage_string_value[] = {"vector", "string"}; + bool attribute_storage_bool_value[] = {true, false, true}; + int32_t attribute_storage_int32_value[] = {1, 2}; + uint32_t attribute_storage_uint32_value[] = {3, 4}; + int64_t attribute_storage_int64_value[] = {5, 6}; + uint64_t attribute_storage_uint64_value[] = {7, 8}; + double attribute_storage_double_value[] = {3.2, 3.3}; + std::string attribute_storage_string_value[] = {"vector", "string"}; auto provider = nostd::shared_ptr(new sdk::logs::LoggerProvider()); - provider->SetProcessor(std::unique_ptr( + provider->AddProcessor(std::unique_ptr( new sdk::logs::BatchLogProcessor(std::move(exporter), 5, std::chrono::milliseconds(256), 1))); EXPECT_CALL(*mock_stub, Export(_, _, _)) @@ -147,14 +147,14 @@ TEST_F(OtlpGrpcLogExporterTestPeer, ExportIntegrationTest) {"int64_value", static_cast(0x1100000000LL)}, {"uint64_value", static_cast(0x1200000000ULL)}, {"double_value", static_cast(3.1)}, - {"vec_bool_value", resource_storage_bool_value}, - {"vec_int32_value", resource_storage_int32_value}, - {"vec_uint32_value", resource_storage_uint32_value}, - {"vec_int64_value", resource_storage_int64_value}, - {"vec_uint64_value", resource_storage_uint64_value}, - {"vec_double_value", resource_storage_double_value}, - {"vec_string_value", resource_storage_string_value}}, - {{"log_attribute", "test_value"}}, trace_id, span_id, + {"vec_bool_value", attribute_storage_bool_value}, + {"vec_int32_value", attribute_storage_int32_value}, + {"vec_uint32_value", attribute_storage_uint32_value}, + {"vec_int64_value", attribute_storage_int64_value}, + {"vec_uint64_value", attribute_storage_uint64_value}, + {"vec_double_value", attribute_storage_double_value}, + {"vec_string_value", attribute_storage_string_value}}, + trace_id, span_id, opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, std::chrono::system_clock::now()); } diff --git a/exporters/otlp/test/otlp_http_log_exporter_test.cc b/exporters/otlp/test/otlp_http_log_exporter_test.cc index 536636033e..35dda11a2e 100755 --- a/exporters/otlp/test/otlp_http_log_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_log_exporter_test.cc @@ -199,16 +199,16 @@ TEST_F(OtlpHttpLogExporterTestPeer, ExportJsonIntegrationTest) size_t old_count = getCurrentRequestCount(); auto exporter = GetExporter(HttpRequestContentType::kJson); - bool resource_storage_bool_value[] = {true, false, true}; - int32_t resource_storage_int32_value[] = {1, 2}; - uint32_t resource_storage_uint32_value[] = {3, 4}; - int64_t resource_storage_int64_value[] = {5, 6}; - uint64_t resource_storage_uint64_value[] = {7, 8}; - double resource_storage_double_value[] = {3.2, 3.3}; - std::string resource_storage_string_value[] = {"vector", "string"}; + bool attribute_storage_bool_value[] = {true, false, true}; + int32_t attribute_storage_int32_value[] = {1, 2}; + uint32_t attribute_storage_uint32_value[] = {3, 4}; + int64_t attribute_storage_int64_value[] = {5, 6}; + uint64_t attribute_storage_uint64_value[] = {7, 8}; + double attribute_storage_double_value[] = {3.2, 3.3}; + std::string attribute_storage_string_value[] = {"vector", "string"}; auto provider = nostd::shared_ptr(new sdk::logs::LoggerProvider()); - provider->SetProcessor(std::unique_ptr( + provider->AddProcessor(std::unique_ptr( new sdk::logs::BatchLogProcessor(std::move(exporter), 5, std::chrono::milliseconds(256), 1))); std::string report_trace_id; @@ -233,14 +233,14 @@ TEST_F(OtlpHttpLogExporterTestPeer, ExportJsonIntegrationTest) {"int64_value", static_cast(0x1100000000LL)}, {"uint64_value", static_cast(0x1200000000ULL)}, {"double_value", static_cast(3.1)}, - {"vec_bool_value", resource_storage_bool_value}, - {"vec_int32_value", resource_storage_int32_value}, - {"vec_uint32_value", resource_storage_uint32_value}, - {"vec_int64_value", resource_storage_int64_value}, - {"vec_uint64_value", resource_storage_uint64_value}, - {"vec_double_value", resource_storage_double_value}, - {"vec_string_value", resource_storage_string_value}}, - {{"log_attribute", "test_value"}}, trace_id, span_id, + {"vec_bool_value", attribute_storage_bool_value}, + {"vec_int32_value", attribute_storage_int32_value}, + {"vec_uint32_value", attribute_storage_uint32_value}, + {"vec_int64_value", attribute_storage_int64_value}, + {"vec_uint64_value", attribute_storage_uint64_value}, + {"vec_double_value", attribute_storage_double_value}, + {"vec_string_value", attribute_storage_string_value}}, + trace_id, span_id, opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, std::chrono::system_clock::now()); @@ -262,10 +262,9 @@ TEST_F(OtlpHttpLogExporterTestPeer, ExportJsonIntegrationTest) EXPECT_EQ(received_span_id, report_span_id); EXPECT_EQ("Log name", log["name"].get()); EXPECT_EQ("Log message", log["body"]["string_value"].get()); - EXPECT_EQ("test_value", (*log["attributes"].begin())["value"]["string_value"].get()); - EXPECT_LE(15, resource_logs["resource"]["attributes"].size()); + EXPECT_LE(15, log["attributes"].size()); bool check_service_name = false; - for (auto attribute : resource_logs["resource"]["attributes"]) + for (auto attribute : log["attributes"]) { if ("service.name" == attribute["key"].get()) { @@ -292,16 +291,16 @@ TEST_F(OtlpHttpLogExporterTestPeer, ExportBinaryIntegrationTest) auto exporter = GetExporter(HttpRequestContentType::kBinary); - bool resource_storage_bool_value[] = {true, false, true}; - int32_t resource_storage_int32_value[] = {1, 2}; - uint32_t resource_storage_uint32_value[] = {3, 4}; - int64_t resource_storage_int64_value[] = {5, 6}; - uint64_t resource_storage_uint64_value[] = {7, 8}; - double resource_storage_double_value[] = {3.2, 3.3}; - std::string resource_storage_string_value[] = {"vector", "string"}; + bool attribute_storage_bool_value[] = {true, false, true}; + int32_t attribute_storage_int32_value[] = {1, 2}; + uint32_t attribute_storage_uint32_value[] = {3, 4}; + int64_t attribute_storage_int64_value[] = {5, 6}; + uint64_t attribute_storage_uint64_value[] = {7, 8}; + double attribute_storage_double_value[] = {3.2, 3.3}; + std::string attribute_storage_string_value[] = {"vector", "string"}; auto provider = nostd::shared_ptr(new sdk::logs::LoggerProvider()); - provider->SetProcessor(std::unique_ptr( + provider->AddProcessor(std::unique_ptr( new sdk::logs::BatchLogProcessor(std::move(exporter), 5, std::chrono::milliseconds(256), 1))); std::string report_trace_id; @@ -324,14 +323,14 @@ TEST_F(OtlpHttpLogExporterTestPeer, ExportBinaryIntegrationTest) {"int64_value", static_cast(0x1100000000LL)}, {"uint64_value", static_cast(0x1200000000ULL)}, {"double_value", static_cast(3.1)}, - {"vec_bool_value", resource_storage_bool_value}, - {"vec_int32_value", resource_storage_int32_value}, - {"vec_uint32_value", resource_storage_uint32_value}, - {"vec_int64_value", resource_storage_int64_value}, - {"vec_uint64_value", resource_storage_uint64_value}, - {"vec_double_value", resource_storage_double_value}, - {"vec_string_value", resource_storage_string_value}}, - {{"log_attribute", "test_value"}}, trace_id, span_id, + {"vec_bool_value", attribute_storage_bool_value}, + {"vec_int32_value", attribute_storage_int32_value}, + {"vec_uint32_value", attribute_storage_uint32_value}, + {"vec_int64_value", attribute_storage_int64_value}, + {"vec_uint64_value", attribute_storage_uint64_value}, + {"vec_double_value", attribute_storage_double_value}, + {"vec_string_value", attribute_storage_string_value}}, + trace_id, span_id, opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, std::chrono::system_clock::now()); @@ -346,10 +345,9 @@ TEST_F(OtlpHttpLogExporterTestPeer, ExportBinaryIntegrationTest) EXPECT_EQ(received_log.span_id(), report_span_id); EXPECT_EQ("Log name", received_log.name()); EXPECT_EQ("Log message", received_log.body().string_value()); - EXPECT_EQ("test_value", received_log.attributes(0).value().string_value()); - EXPECT_LE(15, received_requests_binary_.back().resource_logs(0).resource().attributes_size()); + EXPECT_LE(15, received_log.attributes_size()); bool check_service_name = false; - for (auto &attribute : received_requests_binary_.back().resource_logs(0).resource().attributes()) + for (auto &attribute : received_log.attributes()) { if ("service.name" == attribute.key()) { diff --git a/exporters/otlp/test/otlp_log_recordable_test.cc b/exporters/otlp/test/otlp_log_recordable_test.cc index 808d04fafe..b2e2f7bed0 100644 --- a/exporters/otlp/test/otlp_log_recordable_test.cc +++ b/exporters/otlp/test/otlp_log_recordable_test.cc @@ -86,7 +86,9 @@ TEST(OtlpLogRecordable, SetResource) OtlpLogRecordable rec; const std::string service_name_key = "service.name"; std::string service_name = "test-otlp"; - rec.SetResource(service_name_key, service_name); + auto resource = + opentelemetry::sdk::resource::Resource::Create({{service_name_key, service_name}}); + rec.SetResource(resource); auto proto_resource = rec.ProtoResource(); bool found_service_name = false; diff --git a/sdk/include/opentelemetry/sdk/common/empty_attributes.h b/sdk/include/opentelemetry/sdk/common/empty_attributes.h index 2b88751ffc..4f740bf10e 100644 --- a/sdk/include/opentelemetry/sdk/common/empty_attributes.h +++ b/sdk/include/opentelemetry/sdk/common/empty_attributes.h @@ -4,6 +4,7 @@ #pragma once #include "opentelemetry/common/key_value_iterable_view.h" +#include "opentelemetry/common/macros.h" #include #include @@ -18,7 +19,8 @@ namespace sdk * This helps to avoid constructing a new empty container every time a call is made * with default attributes. */ -static const opentelemetry::common::KeyValueIterableView, 0>> +OPENTELEMETRY_MAYBE_UNUSED static const opentelemetry::common::KeyValueIterableView< + std::array, 0>> &GetEmptyAttributes() noexcept { static const std::array, 0> array{}; diff --git a/sdk/include/opentelemetry/sdk/logs/log_record.h b/sdk/include/opentelemetry/sdk/logs/log_record.h index 34ef5befb0..7abe9aca82 100644 --- a/sdk/include/opentelemetry/sdk/logs/log_record.h +++ b/sdk/include/opentelemetry/sdk/logs/log_record.h @@ -8,6 +8,7 @@ # include # include "opentelemetry/sdk/common/attribute_utils.h" # include "opentelemetry/sdk/logs/recordable.h" +# include "opentelemetry/sdk/resource/resource.h" # include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -27,8 +28,8 @@ class LogRecord final : public Recordable private: // Default values are set by the respective data structures' constructors for all fields, // except the severity field, which must be set manually (an enum with no default value). - opentelemetry::logs::Severity severity_ = opentelemetry::logs::Severity::kInvalid; - common::AttributeMap resource_map_; + opentelemetry::logs::Severity severity_ = opentelemetry::logs::Severity::kInvalid; + const opentelemetry::sdk::resource::Resource *resource_ = nullptr; common::AttributeMap attributes_map_; std::string name_; std::string body_; // Currently a simple string, but should be changed to "Any" type @@ -62,14 +63,12 @@ class LogRecord final : public Recordable void SetBody(nostd::string_view message) noexcept override { body_ = std::string(message); } /** - * Set a resource for this log. - * @param name the name of the resource - * @param value the resource value + * Set Resource of this log + * @param Resource the resource to set */ - void SetResource(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept override + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override { - resource_map_.SetAttribute(key, value); + resource_ = &resource; } /** @@ -141,12 +140,16 @@ class LogRecord final : public Recordable std::string GetBody() const noexcept { return body_; } /** - * Get the resource field for this log - * @return the resource field for this log + * Get the resource for this log + * @return the resource for this log */ - const std::unordered_map &GetResource() const noexcept + const opentelemetry::sdk::resource::Resource &GetResource() const noexcept { - return resource_map_.GetAttributes(); + if (nullptr == resource_) + { + return sdk::resource::Resource::GetDefault(); + } + return *resource_; } /** diff --git a/sdk/include/opentelemetry/sdk/logs/logger.h b/sdk/include/opentelemetry/sdk/logs/logger.h index 4fd1ed89ed..fcf9d18abd 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger.h +++ b/sdk/include/opentelemetry/sdk/logs/logger.h @@ -5,8 +5,8 @@ #ifdef ENABLE_LOGS_PREVIEW # include "opentelemetry/logs/logger.h" +# include "opentelemetry/sdk/logs/logger_context.h" # include "opentelemetry/sdk/logs/logger_provider.h" -# include "opentelemetry/sdk/logs/processor.h" # include @@ -23,10 +23,10 @@ class Logger final : public opentelemetry::logs::Logger /** * Initialize a new logger. * @param name The name of this logger instance - * @param logger_provider The logger provider that owns this logger. + * @param context The logger provider that owns this logger. */ explicit Logger(opentelemetry::nostd::string_view name, - std::shared_ptr logger_provider) noexcept; + std::shared_ptr context) noexcept; /** * Returns the name of this logger. @@ -38,7 +38,6 @@ class Logger final : public opentelemetry::logs::Logger * @param severity the severity level of the log event. * @param name the name of the log event. * @param message the string message of the log (perhaps support std::fmt or fmt-lib format). - * @param resource the resources, stored as a 2D list of key/value pairs, that are associated * with the log event. * @param attributes the attributes, stored as a 2D list of key/value pairs, that are associated * with the log event. @@ -50,7 +49,6 @@ class Logger final : public opentelemetry::logs::Logger void Log(opentelemetry::logs::Severity severity, nostd::string_view name, nostd::string_view body, - const opentelemetry::common::KeyValueIterable &resource, const opentelemetry::common::KeyValueIterable &attributes, opentelemetry::trace::TraceId trace_id, opentelemetry::trace::SpanId span_id, @@ -63,7 +61,7 @@ class Logger final : public opentelemetry::logs::Logger // The logger provider of this Logger. Uses a weak_ptr to avoid cyclic dependency issues the with // logger provider - std::weak_ptr logger_provider_; + std::weak_ptr context_; }; } // namespace logs diff --git a/sdk/include/opentelemetry/sdk/logs/logger_context.h b/sdk/include/opentelemetry/sdk/logs/logger_context.h new file mode 100644 index 0000000000..01c2f7dd89 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/logs/logger_context.h @@ -0,0 +1,81 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/sdk/logs/processor.h" +# include "opentelemetry/sdk/resource/resource.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ +/** + * A class which stores the LoggerContext context. + * + * This class meets the following design criteria: + * - A shared reference between LoggerProvider and Logger instantiated. + * - A thread-safe class that allows updating/altering processor/exporter pipelines + * and sampling config. + * - The owner/destroyer of Processors/Exporters. These will remain active until + * this class is destroyed. I.e. Sampling, Exporting, flushing, Custom Iterator etc. are all ok + * if this object is alive, and they will work together. If this object is destroyed, then no shared + * references to Processor, Exporter, Recordable, Custom Iterator etc. should exist, and all + * associated pipelines will have been flushed. + */ +class LoggerContext +{ +public: + explicit LoggerContext(std::vector> &&processors, + opentelemetry::sdk::resource::Resource resource = + opentelemetry::sdk::resource::Resource::Create({})) noexcept; + + /** + * Attaches a log processor to list of configured processors to this tracer context. + * Processor once attached can't be removed. + * @param processor The new log processor for this tracer. This must not be + * a nullptr. Ownership is given to the `TracerContext`. + * + * Note: This method is not thread safe. + */ + void AddProcessor(std::unique_ptr processor) noexcept; + + /** + * Obtain the configured (composite) processor. + * + * Note: When more than one processor is active, this will + * return an "aggregate" processor + */ + LogProcessor &GetProcessor() const noexcept; + + /** + * Obtain the resource associated with this tracer context. + * @return The resource for this tracer context. + */ + const opentelemetry::sdk::resource::Resource &GetResource() const noexcept; + + /** + * Force all active LogProcessors to flush any buffered logs + * within the given timeout. + */ + bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept; + + /** + * Shutdown the log processor associated with this tracer provider. + */ + bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept; + +private: + // order of declaration is important here - resource object should be destroyed after processor. + opentelemetry::sdk::resource::Resource resource_; + std::unique_ptr processor_; +}; +} // namespace logs +} // namespace sdk + +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/logs/logger_provider.h b/sdk/include/opentelemetry/sdk/logs/logger_provider.h index db07ba5f66..d29b18bc3d 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger_provider.h +++ b/sdk/include/opentelemetry/sdk/logs/logger_provider.h @@ -15,6 +15,7 @@ # include "opentelemetry/nostd/shared_ptr.h" # include "opentelemetry/sdk/common/atomic_shared_ptr.h" # include "opentelemetry/sdk/logs/logger.h" +# include "opentelemetry/sdk/logs/logger_context.h" # include "opentelemetry/sdk/logs/processor.h" // Define the maximum number of loggers that are allowed to be registered to the loggerprovider. @@ -28,16 +29,39 @@ namespace logs { class Logger; -class LoggerProvider final : public opentelemetry::logs::LoggerProvider, - public std::enable_shared_from_this +class LoggerProvider final : public opentelemetry::logs::LoggerProvider { public: + /** + * Initialize a new logger provider + * @param processor The span processor for this logger provider. This must + * not be a nullptr. + * @param resource The resources for this logger provider. + * @param sampler The sampler for this logger provider. This must + * not be a nullptr. + * @param id_generator The custom id generator for this logger provider. This must + * not be a nullptr + */ + explicit LoggerProvider(std::unique_ptr &&processor, + opentelemetry::sdk::resource::Resource resource = + opentelemetry::sdk::resource::Resource::Create({})) noexcept; + + explicit LoggerProvider(std::vector> &&processors, + opentelemetry::sdk::resource::Resource resource = + opentelemetry::sdk::resource::Resource::Create({})) noexcept; + /** * Initialize a new logger provider. A processor must later be assigned - * to this logger provider via the SetProcessor() method. + * to this logger provider via the AddProcessor() method. */ explicit LoggerProvider() noexcept; + /** + * Initialize a new logger provider with a specified context + * @param context The shared logger configuration/pipeline for this provider. + */ + explicit LoggerProvider(std::shared_ptr context) noexcept; + /** * Creates a logger with the given name, and returns a shared pointer to it. * If a logger with that name already exists, return a shared pointer to it @@ -61,29 +85,28 @@ class LoggerProvider final : public opentelemetry::logs::LoggerProvider, nostd::span args) noexcept override; /** - * Returns a shared pointer to the processor currently stored in the - * logger provider. If no processor exists, returns a nullptr + * Add the processor that is stored internally in the logger provider. + * @param processor The processor to be stored inside the logger provider. + * This must not be a nullptr. */ - std::shared_ptr GetProcessor() noexcept; + void AddProcessor(std::unique_ptr processor) noexcept; - // Sets the common processor that all the Logger instances will use /** - * Sets the processor that is stored internally in the logger provider. - * @param processor The processor to be stored inside the logger provider. - * This must not be a nullptr. + * Obtain the resource associated with this logger provider. + * @return The resource for this logger provider. */ - void SetProcessor(std::shared_ptr processor) noexcept; + const opentelemetry::sdk::resource::Resource &GetResource() const noexcept; private: // A pointer to the processor stored by this logger provider - opentelemetry::sdk::common::AtomicSharedPtr processor_; + std::shared_ptr context_; // A vector of pointers to all the loggers that have been created std::unordered_map> loggers_; // A mutex that ensures only one thread is using the map of loggers - std::mutex mu_; + std::mutex lock_; }; } // namespace logs } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/logs/multi_log_processor.h b/sdk/include/opentelemetry/sdk/logs/multi_log_processor.h new file mode 100644 index 0000000000..c1bda24a0b --- /dev/null +++ b/sdk/include/opentelemetry/sdk/logs/multi_log_processor.h @@ -0,0 +1,69 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifdef ENABLE_LOGS_PREVIEW + +# include +# include + +# include "opentelemetry/sdk/logs/multi_recordable.h" +# include "opentelemetry/sdk/logs/processor.h" +# include "opentelemetry/sdk/resource/resource.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +/** + * Log processor allow hooks for receive method invocations. + * + * Built-in log processors are responsible for batching and conversion of + * logs to exportable representation and passing batches to exporters. + */ +class MultiLogProcessor : public LogProcessor +{ +public: + MultiLogProcessor(std::vector> &&processors); + ~MultiLogProcessor(); + + void AddProcessor(std::unique_ptr &&processor); + + std::unique_ptr MakeRecordable() noexcept override; + + /** + * OnReceive is called by the SDK once a log record has been successfully created. + * @param record the log record + */ + void OnReceive(std::unique_ptr &&record) noexcept override; + + /** + * Exports all log records that have not yet been exported to the configured Exporter. + * @param timeout that the forceflush is required to finish within. + * @return a result code indicating whether it succeeded, failed or timed out + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + + /** + * Shuts down the processor and does any cleanup required. + * ShutDown should only be called once for each processor. + * @param timeout minimum amount of microseconds to wait for + * shutdown before giving up and returning failure. + * @return true if the shutdown succeeded, false otherwise + */ + bool Shutdown( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + +private: + std::vector> processors_; +}; +} // namespace logs +} // namespace sdk + +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/logs/multi_recordable.h b/sdk/include/opentelemetry/sdk/logs/multi_recordable.h new file mode 100644 index 0000000000..fe766b0f6a --- /dev/null +++ b/sdk/include/opentelemetry/sdk/logs/multi_recordable.h @@ -0,0 +1,96 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifdef ENABLE_LOGS_PREVIEW + +# include +# include +# include + +# include "opentelemetry/sdk/logs/processor.h" +# include "opentelemetry/sdk/logs/recordable.h" +# include "opentelemetry/sdk/resource/resource.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ +class MultiRecordable final : public Recordable +{ +public: + void AddRecordable(const LogProcessor &processor, + std::unique_ptr recordable) noexcept; + + const std::unique_ptr &GetRecordable(const LogProcessor &processor) const noexcept; + + std::unique_ptr ReleaseRecordable(const LogProcessor &processor) noexcept; + + /** + * Set the timestamp for this log. + * @param timestamp the timestamp to set + */ + void SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept override; + + /** + * Set the severity for this log. + * @param severity the severity of the event + */ + void SetSeverity(opentelemetry::logs::Severity severity) noexcept override; + + /** + * Set name for this log + * @param name the name to set + */ + void SetName(nostd::string_view name) noexcept override; + + /** + * Set body field for this log. + * @param message the body to set + */ + void SetBody(nostd::string_view message) noexcept override; + + /** + * Set Resource of this log + * @param Resource the resource to set + */ + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override; + + /** + * Set an attribute of a log. + * @param key the name of the attribute + * @param value the attribute value + */ + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept override; + + /** + * Set the trace id for this log. + * @param trace_id the trace id to set + */ + void SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept override; + + /** + * Set the span id for this log. + * @param span_id the span id to set + */ + void SetSpanId(opentelemetry::trace::SpanId span_id) noexcept override; + + /** + * Inject trace_flags for this log. + * @param trace_flags the trace flags to set + */ + void SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept override; + +private: + std::unordered_map> recordables_; +}; +} // namespace logs +} // namespace sdk + +OPENTELEMETRY_END_NAMESPACE + +#endif diff --git a/sdk/include/opentelemetry/sdk/logs/recordable.h b/sdk/include/opentelemetry/sdk/logs/recordable.h index db730752d2..a5d1beb5e1 100644 --- a/sdk/include/opentelemetry/sdk/logs/recordable.h +++ b/sdk/include/opentelemetry/sdk/logs/recordable.h @@ -18,8 +18,6 @@ # include "opentelemetry/trace/trace_id.h" # include "opentelemetry/version.h" -# include - OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -60,12 +58,10 @@ class Recordable virtual void SetBody(nostd::string_view message) noexcept = 0; /** - * Set a single resource of a log record. - * @param key the name of the resource to set - * @param value the resource value to set + * Set Resource of this log + * @param Resource the resource to set */ - virtual void SetResource(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept = 0; + virtual void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept = 0; /** * Set an attribute of a log. diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h index 9ff35e0116..77a9b713ba 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h @@ -80,12 +80,6 @@ class TracerProvider final : public opentelemetry::trace::TracerProvider */ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept; - /** - * Obtain the span processor associated with this tracer provider. - * @return The span processor for this tracer provider. - */ - std::shared_ptr GetProcessor() const noexcept; - /** * Shutdown the span processor associated with this tracer provider. */ diff --git a/sdk/src/logs/BUILD b/sdk/src/logs/BUILD index c1a0542fa1..ac51799125 100644 --- a/sdk/src/logs/BUILD +++ b/sdk/src/logs/BUILD @@ -22,5 +22,6 @@ cc_library( deps = [ "//api", "//sdk:headers", + "//sdk/src/resource", ], ) diff --git a/sdk/src/logs/CMakeLists.txt b/sdk/src/logs/CMakeLists.txt index 70eccf2f15..20f13324e7 100644 --- a/sdk/src/logs/CMakeLists.txt +++ b/sdk/src/logs/CMakeLists.txt @@ -1,9 +1,17 @@ -add_library(opentelemetry_logs logger_provider.cc logger.cc - simple_log_processor.cc batch_log_processor.cc) +add_library( + opentelemetry_logs + logger_provider.cc + logger.cc + simple_log_processor.cc + batch_log_processor.cc + logger_context.cc + multi_log_processor.cc + multi_recordable.cc) set_target_properties(opentelemetry_logs PROPERTIES EXPORT_NAME logs) -target_link_libraries(opentelemetry_logs opentelemetry_common) +target_link_libraries(opentelemetry_logs PUBLIC opentelemetry_resources + opentelemetry_common) target_include_directories( opentelemetry_logs diff --git a/sdk/src/logs/logger.cc b/sdk/src/logs/logger.cc index 735b527b80..aa1e7180db 100644 --- a/sdk/src/logs/logger.cc +++ b/sdk/src/logs/logger.cc @@ -16,8 +16,8 @@ namespace trace_api = opentelemetry::trace; namespace nostd = opentelemetry::nostd; namespace common = opentelemetry::common; -Logger::Logger(nostd::string_view name, std::shared_ptr logger_provider) noexcept - : logger_name_(std::string(name)), logger_provider_(logger_provider) +Logger::Logger(nostd::string_view name, std::shared_ptr context) noexcept + : logger_name_(std::string(name)), context_(context) {} const nostd::string_view Logger::GetName() noexcept @@ -33,7 +33,6 @@ const nostd::string_view Logger::GetName() noexcept void Logger::Log(opentelemetry::logs::Severity severity, nostd::string_view name, nostd::string_view body, - const common::KeyValueIterable &resource, const common::KeyValueIterable &attributes, trace_api::TraceId trace_id, trace_api::SpanId span_id, @@ -41,15 +40,16 @@ void Logger::Log(opentelemetry::logs::Severity severity, common::SystemTimestamp timestamp) noexcept { // If this logger does not have a processor, no need to create a log record - auto processor = logger_provider_.lock()->GetProcessor(); - if (processor == nullptr) + auto context = context_.lock(); + if (!context) { return; } + auto &processor = context->GetProcessor(); // TODO: Sampler (should include check for minSeverity) - auto recordable = processor->MakeRecordable(); + auto recordable = processor.MakeRecordable(); if (recordable == nullptr) { OTEL_INTERNAL_LOG_ERROR("[LOGGER] Recordable creation failed"); @@ -62,10 +62,7 @@ void Logger::Log(opentelemetry::logs::Severity severity, recordable->SetName(name); recordable->SetBody(body); - resource.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { - recordable->SetResource(key, value); - return true; - }); + recordable->SetResource(context->GetResource()); attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { recordable->SetAttribute(key, value); @@ -111,7 +108,7 @@ void Logger::Log(opentelemetry::logs::Severity severity, } // Send the log record to the processor - processor->OnReceive(std::move(recordable)); + processor.OnReceive(std::move(recordable)); } } // namespace logs diff --git a/sdk/src/logs/logger_context.cc b/sdk/src/logs/logger_context.cc new file mode 100644 index 0000000000..b0025ff724 --- /dev/null +++ b/sdk/src/logs/logger_context.cc @@ -0,0 +1,54 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/sdk/logs/logger_context.h" +# include "opentelemetry/sdk/logs/multi_log_processor.h" + +# include +# include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +LoggerContext::LoggerContext(std::vector> &&processors, + opentelemetry::sdk::resource::Resource resource) noexcept + : resource_(resource), + processor_(std::unique_ptr(new MultiLogProcessor(std::move(processors)))) +{} + +void LoggerContext::AddProcessor(std::unique_ptr processor) noexcept +{ + auto multi_processor = static_cast(processor_.get()); + multi_processor->AddProcessor(std::move(processor)); +} + +LogProcessor &LoggerContext::GetProcessor() const noexcept +{ + return *processor_; +} + +const opentelemetry::sdk::resource::Resource &LoggerContext::GetResource() const noexcept +{ + return resource_; +} + +bool LoggerContext::ForceFlush(std::chrono::microseconds timeout) noexcept +{ + return processor_->ForceFlush(timeout); +} + +bool LoggerContext::Shutdown(std::chrono::microseconds timeout) noexcept +{ + return processor_->ForceFlush(timeout); +} + +} // namespace logs +} // namespace sdk + +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index 58e6a75ea4..75c02c89ef 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -5,6 +5,12 @@ # include "opentelemetry/sdk/logs/logger_provider.h" +# include +# include +# include +# include +# include + OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -14,13 +20,34 @@ namespace logs namespace nostd = opentelemetry::nostd; namespace logs_api = opentelemetry::logs; -LoggerProvider::LoggerProvider() noexcept : processor_{nullptr} {} +LoggerProvider::LoggerProvider(std::unique_ptr &&processor, + opentelemetry::sdk::resource::Resource resource) noexcept +{ + std::vector> processors; + processors.emplace_back(std::move(processor)); + context_ = std::make_shared(std::move(processors), std::move(resource)); +} + +LoggerProvider::LoggerProvider(std::vector> &&processors, + opentelemetry::sdk::resource::Resource resource) noexcept + : context_{ + std::make_shared(std::move(processors), std::move(resource))} +{} + +LoggerProvider::LoggerProvider() noexcept + : context_{ + std::make_shared(std::vector>{})} +{} + +LoggerProvider::LoggerProvider(std::shared_ptr context) noexcept + : context_{context} +{} nostd::shared_ptr LoggerProvider::GetLogger(nostd::string_view name, nostd::string_view options) noexcept { // Ensure only one thread can read/write from the map of loggers - std::lock_guard lock_guard{mu_}; + std::lock_guard lock_guard{lock_}; // If a logger with a name "name" already exists, return it auto loggerkv = loggers_.find(name.data()); @@ -44,7 +71,7 @@ nostd::shared_ptr LoggerProvider::GetLogger(nostd::string_view // If no logger with that name exists yet, create it and add it to the map of loggers - nostd::shared_ptr logger(new Logger(name, this->shared_from_this())); + nostd::shared_ptr logger(new Logger(name, context_)); loggers_[name.data()] = logger; return logger; } @@ -57,15 +84,16 @@ nostd::shared_ptr LoggerProvider::GetLogger( return GetLogger(name); } -std::shared_ptr LoggerProvider::GetProcessor() noexcept +void LoggerProvider::AddProcessor(std::unique_ptr processor) noexcept { - return processor_.load(); + context_->AddProcessor(std::move(processor)); } -void LoggerProvider::SetProcessor(std::shared_ptr processor) noexcept +const opentelemetry::sdk::resource::Resource &LoggerProvider::GetResource() const noexcept { - processor_.store(processor); + return context_->GetResource(); } + } // namespace logs } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/logs/multi_log_processor.cc b/sdk/src/logs/multi_log_processor.cc new file mode 100644 index 0000000000..b73cc9e7a6 --- /dev/null +++ b/sdk/src/logs/multi_log_processor.cc @@ -0,0 +1,153 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/sdk/logs/multi_log_processor.h" + +# include +# include +# include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +MultiLogProcessor::MultiLogProcessor(std::vector> &&processors) +{ + for (auto &processor : processors) + { + AddProcessor(std::move(processor)); + } +} +MultiLogProcessor::~MultiLogProcessor() +{ + ForceFlush(); + Shutdown(); +} + +void MultiLogProcessor::AddProcessor(std::unique_ptr &&processor) +{ + // Add preocessor to end of the list. + if (processor) + { + processors_.emplace_back(std::move(processor)); + } +} + +std::unique_ptr MultiLogProcessor::MakeRecordable() noexcept +{ + auto recordable = std::unique_ptr(new MultiRecordable); + auto multi_recordable = static_cast(recordable.get()); + for (auto &processor : processors_) + { + multi_recordable->AddRecordable(*processor, processor->MakeRecordable()); + } + return recordable; +} + +void MultiLogProcessor::OnReceive(std::unique_ptr &&record) noexcept +{ + if (!record) + { + return; + } + auto multi_recordable = static_cast(record.get()); + + for (auto &processor : processors_) + { + auto recordable = multi_recordable->ReleaseRecordable(*processor); + if (recordable) + { + processor->OnReceive(std::move(recordable)); + } + } +} + +bool MultiLogProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept +{ + // Converto nanos to prevent overflow + std::chrono::nanoseconds timeout_ns = std::chrono::nanoseconds::max(); + if (std::chrono::duration_cast(timeout_ns) > timeout) + { + timeout_ns = std::chrono::duration_cast(timeout); + } + bool result = true; + auto start_time = std::chrono::system_clock::now(); + auto overflow_checker = std::chrono::system_clock::time_point::max(); + std::chrono::system_clock::time_point expire_time; + if (overflow_checker - start_time <= timeout_ns) + { + expire_time = overflow_checker; + } + else + { + expire_time = + start_time + std::chrono::duration_cast(timeout_ns); + } + for (auto &processor : processors_) + { + if (!processor->ForceFlush(std::chrono::duration_cast(timeout_ns))) + { + result = false; + } + start_time = std::chrono::system_clock::now(); + if (expire_time > start_time) + { + timeout_ns = std::chrono::duration_cast(expire_time - start_time); + } + else + { + timeout_ns = std::chrono::nanoseconds::zero(); + } + } + return result; +} + +bool MultiLogProcessor::Shutdown(std::chrono::microseconds timeout) noexcept +{ + // Converto nanos to prevent overflow + std::chrono::nanoseconds timeout_ns = std::chrono::nanoseconds::max(); + if (std::chrono::duration_cast(timeout_ns) > timeout) + { + timeout_ns = std::chrono::duration_cast(timeout); + } + bool result = true; + auto start_time = std::chrono::system_clock::now(); + auto overflow_checker = std::chrono::system_clock::time_point::max(); + std::chrono::system_clock::time_point expire_time; + if (overflow_checker - start_time <= timeout_ns) + { + expire_time = overflow_checker; + } + else + { + expire_time = + start_time + std::chrono::duration_cast(timeout_ns); + } + for (auto &processor : processors_) + { + if (!processor->Shutdown(std::chrono::duration_cast(timeout_ns))) + { + result = false; + } + start_time = std::chrono::system_clock::now(); + if (expire_time > start_time) + { + timeout_ns = std::chrono::duration_cast(expire_time - start_time); + } + else + { + timeout_ns = std::chrono::nanoseconds::zero(); + } + } + return result; +} + +} // namespace logs +} // namespace sdk + +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/logs/multi_recordable.cc b/sdk/src/logs/multi_recordable.cc new file mode 100644 index 0000000000..4db79af48c --- /dev/null +++ b/sdk/src/logs/multi_recordable.cc @@ -0,0 +1,136 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/sdk/logs/multi_recordable.h" + +# include +# include +# include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +namespace +{ +std::size_t MakeKey(const opentelemetry::sdk::logs::LogProcessor &processor) +{ + return reinterpret_cast(&processor); +} + +} // namespace + +void MultiRecordable::AddRecordable(const LogProcessor &processor, + std::unique_ptr recordable) noexcept +{ + recordables_[MakeKey(processor)] = std::move(recordable); +} + +const std::unique_ptr &MultiRecordable::GetRecordable( + const LogProcessor &processor) const noexcept +{ + // TODO - return nullptr ref on failed lookup? + auto i = recordables_.find(MakeKey(processor)); + if (i != recordables_.end()) + { + return i->second; + } + static std::unique_ptr empty(nullptr); + return empty; +} + +std::unique_ptr MultiRecordable::ReleaseRecordable( + const LogProcessor &processor) noexcept +{ + auto i = recordables_.find(MakeKey(processor)); + if (i != recordables_.end()) + { + std::unique_ptr result(i->second.release()); + recordables_.erase(MakeKey(processor)); + return result; + } + return std::unique_ptr(nullptr); +} + +void MultiRecordable::SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetTimestamp(timestamp); + } +} + +void MultiRecordable::SetSeverity(opentelemetry::logs::Severity severity) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetSeverity(severity); + } +} + +void MultiRecordable::SetName(nostd::string_view name) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetName(name); + } +} + +void MultiRecordable::SetBody(nostd::string_view message) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetBody(message); + } +} + +void MultiRecordable::SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetResource(resource); + } +} + +void MultiRecordable::SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetAttribute(key, value); + } +} + +void MultiRecordable::SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetTraceId(trace_id); + } +} + +void MultiRecordable::SetSpanId(opentelemetry::trace::SpanId span_id) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetSpanId(span_id); + } +} + +void MultiRecordable::SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept +{ + for (auto &recordable : recordables_) + { + recordable.second->SetTraceFlags(trace_flags); + } +} + +} // namespace logs +} // namespace sdk + +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/test/logs/log_record_test.cc b/sdk/test/logs/log_record_test.cc index 9443091691..dda80cc1ee 100644 --- a/sdk/test/logs/log_record_test.cc +++ b/sdk/test/logs/log_record_test.cc @@ -26,7 +26,7 @@ TEST(LogRecord, GetDefaultValues) ASSERT_EQ(record.GetSeverity(), logs_api::Severity::kInvalid); ASSERT_EQ(record.GetName(), ""); ASSERT_EQ(record.GetBody(), ""); - ASSERT_EQ(record.GetResource().size(), 0); + ASSERT_NE(record.GetResource().GetAttributes().size(), 0); ASSERT_EQ(record.GetAttributes().size(), 0); ASSERT_EQ(record.GetTraceId(), zero_trace_id); ASSERT_EQ(record.GetSpanId(), zero_span_id); @@ -44,10 +44,11 @@ TEST(LogRecord, SetAndGet) // Set all fields of the LogRecord LogRecord record; + auto resource = opentelemetry::sdk::resource::Resource::Create({{"res1", true}}); record.SetSeverity(logs_api::Severity::kInvalid); record.SetName("Log name"); record.SetBody("Message"); - record.SetResource("res1", (bool)true); + record.SetResource(resource); record.SetAttribute("attr1", (int64_t)314159); record.SetTraceId(trace_id); record.SetSpanId(span_id); @@ -58,7 +59,7 @@ TEST(LogRecord, SetAndGet) ASSERT_EQ(record.GetSeverity(), logs_api::Severity::kInvalid); ASSERT_EQ(record.GetName(), "Log name"); ASSERT_EQ(record.GetBody(), "Message"); - ASSERT_EQ(nostd::get(record.GetResource().at("res1")), 1); + ASSERT_TRUE(nostd::get(record.GetResource().GetAttributes().at("res1"))); ASSERT_EQ(nostd::get(record.GetAttributes().at("attr1")), 314159); ASSERT_EQ(record.GetTraceId(), trace_id); ASSERT_EQ(record.GetSpanId(), span_id); diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index 5c0be6fb94..517c05dc94 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -79,15 +79,11 @@ class DummyProcessor : public LogProcessor } }; -TEST(LoggerProviderSDK, GetAndSetProcessor) +TEST(LoggerProviderSDK, GetResource) { // Create a LoggerProvider without a processor - LoggerProvider lp; - ASSERT_EQ(lp.GetProcessor(), nullptr); - - // Create a new processor and check if it is pushed correctly - std::shared_ptr proc2 = std::shared_ptr(new DummyProcessor()); - lp.SetProcessor(proc2); - ASSERT_EQ(proc2, lp.GetProcessor()); + auto resource = opentelemetry::sdk::resource::Resource::Create({{"key", "value"}}); + LoggerProvider lp{nullptr, resource}; + ASSERT_EQ(nostd::get(lp.GetResource().GetAttributes().at("key")), "value"); } #endif diff --git a/sdk/test/logs/logger_sdk_test.cc b/sdk/test/logs/logger_sdk_test.cc index 26632f1f91..cd2f291a80 100644 --- a/sdk/test/logs/logger_sdk_test.cc +++ b/sdk/test/logs/logger_sdk_test.cc @@ -77,9 +77,7 @@ TEST(LoggerSDK, LogToAProcessor) // Set a processor for the LoggerProvider auto shared_recordable = std::shared_ptr(new LogRecord()); - auto processor = std::shared_ptr(new MockProcessor(shared_recordable)); - lp->SetProcessor(processor); - ASSERT_EQ(processor, lp->GetProcessor()); + lp->AddProcessor(std::unique_ptr(new MockProcessor(shared_recordable))); // Check that the recordable created by the Log() statement is set properly logger->Log(logs_api::Severity::kWarn, "Log Name", "Log Message");