diff --git a/CHANGELOG.md b/CHANGELOG.md index 3671046656..7c54c9051a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Increment the: ## [Unreleased] +* [SDK]Add attributes for InstrumentationScope + [#2004](https://github.com/open-telemetry/opentelemetry-cpp/pull/2004) * [ETW Exporter]Support serialize span/log attributes into JSON [#1991](https://github.com/open-telemetry/opentelemetry-cpp/pull/1991) * ETW Exporter]Do not overwrite ParentId when setting attribute on Span diff --git a/api/include/opentelemetry/common/key_value_iterable_view.h b/api/include/opentelemetry/common/key_value_iterable_view.h index e688ec253f..daea8fce2e 100644 --- a/api/include/opentelemetry/common/key_value_iterable_view.h +++ b/api/include/opentelemetry/common/key_value_iterable_view.h @@ -8,6 +8,8 @@ #include #include "opentelemetry/common/key_value_iterable.h" +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/nostd/utility.h" #include "opentelemetry/version.h" @@ -81,5 +83,59 @@ KeyValueIterableView MakeKeyValueIterableView(const T &container) noexcept return KeyValueIterableView(container); } +/** + * Utility function to help to make a attribute view from initializer_list + * + * @param attributes + * @return nostd::span> + */ +inline static nostd::span> +MakeAttributes(std::initializer_list> + attributes) noexcept +{ + return nostd::span>{ + attributes.begin(), attributes.end()}; +} + +/** + * Utility function to help to make a attribute view from a span + * + * @param attributes + * @return nostd::span> + */ +inline static nostd::span> +MakeAttributes( + nostd::span> attributes) noexcept +{ + return attributes; +} + +/** + * Utility function to help to make a attribute view from a KeyValueIterable + * + * @param attributes + * @return common::KeyValueIterable + */ +inline static const common::KeyValueIterable &MakeAttributes( + const common::KeyValueIterable &attributes) noexcept +{ + return attributes; +} + +/** + * Utility function to help to make a attribute view from a key-value iterable object + * + * @param attributes + * @return nostd::span> + */ +template < + class ArgumentType, + nostd::enable_if_t::value> * = nullptr> +inline static common::KeyValueIterableView MakeAttributes( + const ArgumentType &arg) noexcept +{ + return common::KeyValueIterableView(arg); +} + } // namespace common OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/logs/logger.h b/api/include/opentelemetry/logs/logger.h index 1220219449..23aea11143 100644 --- a/api/include/opentelemetry/logs/logger.h +++ b/api/include/opentelemetry/logs/logger.h @@ -4,27 +4,12 @@ #pragma once #ifdef ENABLE_LOGS_PREVIEW -# include -# include -# include - -# include "opentelemetry/common/attribute_value.h" # include "opentelemetry/common/key_value_iterable.h" -# include "opentelemetry/common/key_value_iterable_view.h" -# include "opentelemetry/common/macros.h" -# include "opentelemetry/common/timestamp.h" # include "opentelemetry/logs/log_record.h" # include "opentelemetry/logs/logger_type_traits.h" # include "opentelemetry/logs/severity.h" -# include "opentelemetry/nostd/shared_ptr.h" -# include "opentelemetry/nostd/span.h" # include "opentelemetry/nostd/string_view.h" -# include "opentelemetry/nostd/type_traits.h" # include "opentelemetry/nostd/unique_ptr.h" -# include "opentelemetry/trace/span_context.h" -# include "opentelemetry/trace/span_id.h" -# include "opentelemetry/trace/trace_flags.h" -# include "opentelemetry/trace/trace_id.h" # include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -36,60 +21,6 @@ namespace logs class Logger { public: - /** - * Utility function to help to make a attribute view from initializer_list - * - * @param attributes - * @return nostd::span> - */ - inline static nostd::span> - MakeAttributes(std::initializer_list> - attributes) noexcept - { - return nostd::span>{ - attributes.begin(), attributes.end()}; - } - - /** - * Utility function to help to make a attribute view from a span - * - * @param attributes - * @return nostd::span> - */ - inline static nostd::span> - MakeAttributes( - nostd::span> attributes) noexcept - { - return attributes; - } - - /** - * Utility function to help to make a attribute view from a KeyValueIterable - * - * @param attributes - * @return common::KeyValueIterable - */ - inline static const common::KeyValueIterable &MakeAttributes( - const common::KeyValueIterable &attributes) noexcept - { - return attributes; - } - - /** - * Utility function to help to make a attribute view from a key-value iterable object - * - * @param attributes - * @return nostd::span> - */ - template < - class ArgumentType, - nostd::enable_if_t::value> * = nullptr> - inline static common::KeyValueIterableView MakeAttributes( - const ArgumentType &arg) noexcept - { - return common::KeyValueIterableView(arg); - } - virtual ~Logger() = default; /* Returns the name of the logger */ diff --git a/api/include/opentelemetry/logs/logger_type_traits.h b/api/include/opentelemetry/logs/logger_type_traits.h index 805d07736c..8736c03f7f 100644 --- a/api/include/opentelemetry/logs/logger_type_traits.h +++ b/api/include/opentelemetry/logs/logger_type_traits.h @@ -5,14 +5,10 @@ #ifdef ENABLE_LOGS_PREVIEW # include -# include # include -# include # include "opentelemetry/common/attribute_value.h" # include "opentelemetry/common/key_value_iterable.h" -# include "opentelemetry/common/key_value_iterable_view.h" -# include "opentelemetry/common/macros.h" # include "opentelemetry/common/timestamp.h" # include "opentelemetry/logs/log_record.h" # include "opentelemetry/logs/severity.h" diff --git a/api/test/logs/logger_test.cc b/api/test/logs/logger_test.cc index 4f811dd418..d07e12e40e 100644 --- a/api/test/logs/logger_test.cc +++ b/api/test/logs/logger_test.cc @@ -61,48 +61,54 @@ TEST(Logger, LogMethodOverloads) logger->EmitLogRecord(Severity::kDebug, m); logger->EmitLogRecord(Severity::kWarn, "Logging a map", m); logger->EmitLogRecord(Severity::kError, - Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->EmitLogRecord(Severity::kFatal, "Logging an initializer list", - Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); - logger->EmitLogRecord(Severity::kDebug, Logger::MakeAttributes(m)); + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->EmitLogRecord(Severity::kDebug, opentelemetry::common::MakeAttributes(m)); logger->EmitLogRecord(Severity::kDebug, common::KeyValueIterableView>(m)); std::pair array[] = {{"key1", "value1"}}; - logger->EmitLogRecord(Severity::kDebug, Logger::MakeAttributes(array)); + logger->EmitLogRecord(Severity::kDebug, opentelemetry::common::MakeAttributes(array)); std::vector> vec = {{"key1", "value1"}}; - logger->EmitLogRecord(Severity::kDebug, Logger::MakeAttributes(vec)); + logger->EmitLogRecord(Severity::kDebug, opentelemetry::common::MakeAttributes(vec)); // Severity methods logger->Trace("Test log message"); logger->Trace("Test log message", m); - logger->Trace("Test log message", Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Trace("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Trace(m); - logger->Trace(Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Trace(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Debug("Test log message"); logger->Debug("Test log message", m); - logger->Debug("Test log message", Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Debug("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Debug(m); - logger->Debug(Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Debug(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Info("Test log message"); logger->Info("Test log message", m); - logger->Info("Test log message", Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Info("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Info(m); - logger->Info(Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Info(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Warn("Test log message"); logger->Warn("Test log message", m); - logger->Warn("Test log message", Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Warn("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Warn(m); - logger->Warn(Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Warn(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Error("Test log message"); logger->Error("Test log message", m); - logger->Error("Test log message", Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Error("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Error(m); - logger->Error(Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Error(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Fatal("Test log message"); logger->Fatal("Test log message", m); - logger->Fatal("Test log message", Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Fatal("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Fatal(m); - logger->Fatal(Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->Fatal(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); } TEST(Logger, EventLogMethodOverloads) @@ -120,17 +126,21 @@ TEST(Logger, EventLogMethodOverloads) event_logger->EmitEvent("event name", Severity::kInfo, "Test log message"); event_logger->EmitEvent("event name", Severity::kDebug, m); event_logger->EmitEvent("event name", Severity::kWarn, "Logging a map", m); - event_logger->EmitEvent("event name", Severity::kError, - Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); - event_logger->EmitEvent("event name", Severity::kFatal, "Logging an initializer list", - Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); - event_logger->EmitEvent("event name", Severity::kDebug, Logger::MakeAttributes(m)); + event_logger->EmitEvent( + "event name", Severity::kError, + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + event_logger->EmitEvent( + "event name", Severity::kFatal, "Logging an initializer list", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + event_logger->EmitEvent("event name", Severity::kDebug, opentelemetry::common::MakeAttributes(m)); event_logger->EmitEvent("event name", Severity::kDebug, common::KeyValueIterableView>(m)); std::pair array[] = {{"key1", "value1"}}; - event_logger->EmitEvent("event name", Severity::kDebug, Logger::MakeAttributes(array)); + event_logger->EmitEvent("event name", Severity::kDebug, + opentelemetry::common::MakeAttributes(array)); std::vector> vec = {{"key1", "value1"}}; - event_logger->EmitEvent("event name", Severity::kDebug, Logger::MakeAttributes(vec)); + event_logger->EmitEvent("event name", Severity::kDebug, + opentelemetry::common::MakeAttributes(vec)); } // Define a basic Logger class diff --git a/exporters/etw/test/etw_logger_test.cc b/exporters/etw/test/etw_logger_test.cc index fba15581a3..2c17dc846e 100644 --- a/exporters/etw/test/etw_logger_test.cc +++ b/exporters/etw/test/etw_logger_test.cc @@ -96,7 +96,7 @@ TEST(ETWLogger, LoggerCheckWithAttributes) // Log attributes Properties attribs = {{"attrib1", 1}, {"attrib2", 2}}; EXPECT_NO_THROW(logger->EmitLogRecord(opentelemetry::logs::Severity::kDebug, - Logger::MakeAttributes(attribs))); + opentelemetry::common::MakeAttributes(attribs))); } # endif // _WIN32 diff --git a/exporters/ostream/src/log_record_exporter.cc b/exporters/ostream/src/log_record_exporter.cc index ca751b810e..0b1093ab9d 100644 --- a/exporters/ostream/src/log_record_exporter.cc +++ b/exporters/ostream/src/log_record_exporter.cc @@ -88,21 +88,26 @@ sdk::common::ExportResult OStreamLogRecordExporter::Export( sout_ << " body : "; opentelemetry::exporter::ostream_common::print_value(log_record->GetBody(), sout_); - sout_ << "\n"; + sout_ << "\n resource : "; + printAttributes(log_record->GetResource().GetAttributes(), "\n "); - sout_ << " resource : "; - printAttributes(log_record->GetResource().GetAttributes()); + sout_ << "\n attributes : "; - sout_ << "\n" - << " attributes : "; - - printAttributes(log_record->GetAttributes()); + printAttributes(log_record->GetAttributes(), "\n "); sout_ << "\n" << " trace_id : " << std::string(trace_id, trace_id_len) << "\n" << " span_id : " << std::string(span_id, span_id__len) << "\n" << " trace_flags : " << std::string(trace_flags, trace_flags_len) << "\n" - << "}\n"; + << " scope : \n" + << " name : " << log_record->GetInstrumentationScope().GetName() << "\n" + << " version : " << log_record->GetInstrumentationScope().GetVersion() << "\n" + << " schema_url : " << log_record->GetInstrumentationScope().GetSchemaURL() + << "\n" + << " attributes : "; + + printAttributes(log_record->GetInstrumentationScope().GetAttributes(), "\n "); + sout_ << "\n}\n"; } return sdk::common::ExportResult::kSuccess; diff --git a/exporters/ostream/test/ostream_log_test.cc b/exporters/ostream/test/ostream_log_test.cc index 5896c6e42d..95cdb69380 100644 --- a/exporters/ostream/test/ostream_log_test.cc +++ b/exporters/ostream/test/ostream_log_test.cc @@ -26,6 +26,19 @@ namespace exporter namespace logs { +namespace +{ +static opentelemetry::sdk::instrumentationscope::InstrumentationScope GetTestInstrumentationScope() +{ + opentelemetry::sdk::instrumentationscope::InstrumentationScope result = + opentelemetry::sdk::logs::ReadableLogRecord::GetDefaultInstrumentationScope(); + + result.SetAttribute("scope.attr.key", "scope.attr.value"); + + return result; +} +} // namespace + // Test that when OStream Log exporter is shutdown, no logs should be sent to stream TEST(OStreamLogRecordExporter, Shutdown) { @@ -71,6 +84,9 @@ TEST(OstreamLogExporter, DefaultLogRecordToCout) // Pass a default recordable created by the exporter to be exported auto log_record = exporter->MakeRecordable(); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + log_record->SetInstrumentationScope(instrumentation_scope); exporter->Export(nostd::span>(&log_record, 1)); // Restore cout's original stringstream @@ -83,18 +99,30 @@ TEST(OstreamLogExporter, DefaultLogRecordToCout) " severity_text : INVALID\n" " body : \n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - " attributes : \n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " attributes : \n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = output.str(); for (auto &expected : expected_output) { - ASSERT_NE(output.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -122,6 +150,10 @@ TEST(OStreamLogRecordExporter, SimpleLogToCout) ->SetSeverity(logs_api::Severity::kTrace); // kTrace has enum value of 1 static_cast(record.get())->SetBody("Message"); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + record->SetInstrumentationScope(instrumentation_scope); + // Log a record to cout exporter->Export(nostd::span>(&record, 1)); @@ -140,18 +172,30 @@ TEST(OStreamLogRecordExporter, SimpleLogToCout) " severity_text : TRACE\n" " body : Message\n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - " attributes : \n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " attributes : \n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = output.str(); for (auto &expected : expected_output) { - ASSERT_NE(output.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -180,6 +224,10 @@ TEST(OStreamLogRecordExporter, LogWithStringAttributesToCerr) // Set attributes to this log record of type static_cast(record.get())->SetAttribute("a", true); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + record->SetInstrumentationScope(instrumentation_scope); + // Log record to cerr exporter->Export(nostd::span>(&record, 1)); @@ -193,21 +241,33 @@ TEST(OStreamLogRecordExporter, LogWithStringAttributesToCerr) " severity_text : INVALID\n" " body : \n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - "service.name: unknown_service\n", - "key1: val1\n", + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " service.name: unknown_service\n", + " key1: val1\n", " attributes : \n", - "\ta: 1\n", - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " a: 1\n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = stdcerrOutput.str(); for (auto &expected : expected_output) { - ASSERT_NE(stdcerrOutput.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -243,6 +303,10 @@ TEST(OStreamLogRecordExporter, LogWithVariantTypesToClog) static_cast(record.get()) ->SetAttribute("attr1", nostd::span{array.data(), array.size()}); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + record->SetInstrumentationScope(instrumentation_scope); + // Log a record to clog exporter->Export(nostd::span>(&record, 1)); @@ -256,21 +320,33 @@ TEST(OStreamLogRecordExporter, LogWithVariantTypesToClog) " severity_text : INVALID\n" " body : \n", " resource : \n", - "service.name: unknown_service\n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - "res1: [1,2,3]\n", - "attributes : \n", - "\tattr1: [0,1,0]\n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " service.name: unknown_service\n", + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " res1: [1,2,3]\n", + " attributes : \n", + " attr1: [0,1,0]\n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = stdclogOutput.str(); for (auto &expected : expected_output) { - ASSERT_NE(stdclogOutput.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -291,7 +367,8 @@ TEST(OStreamLogRecordExporter, IntegrationTest) logs_api::Provider::SetLoggerProvider(provider); const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; auto logger = logs_api::Provider::GetLoggerProvider()->GetLogger( - "Logger", "opentelelemtry_library", "", schema_url); + "Logger", "opentelelemtry_library", OPENTELEMETRY_SDK_VERSION, schema_url, true, + {{"scope.attr.key", 123}}); // Back up cout's streambuf std::streambuf *original = std::cout.rdbuf(); @@ -316,19 +393,31 @@ TEST(OStreamLogRecordExporter, IntegrationTest) " severity_text : DEBUG\n" " body : Hello\n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "service.name: unknown_service\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - " attributes : \n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " service.name: unknown_service\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " attributes : \n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : opentelelemtry_library\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.11.0\n", + " attributes : \n", + " scope.attr.key: 123\n", "}\n"}; + std::string ostream_output = stdcoutOutput.str(); for (auto &expected : expected_output) { - ASSERT_NE(stdcoutOutput.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } diff --git a/exporters/otlp/src/otlp_metric_utils.cc b/exporters/otlp/src/otlp_metric_utils.cc index c570b7d827..c4ab641567 100644 --- a/exporters/otlp/src/otlp_metric_utils.cc +++ b/exporters/otlp/src/otlp_metric_utils.cc @@ -96,7 +96,9 @@ void OtlpMetricUtils::ConvertHistogramMetric( // sum if ((nostd::holds_alternative(histogram_data.sum_))) { - proto_histogram_point_data->set_sum(nostd::get(histogram_data.sum_)); + // Use static_cast to avoid C4244 in MSVC + proto_histogram_point_data->set_sum( + static_cast(nostd::get(histogram_data.sum_))); } else { @@ -108,7 +110,9 @@ void OtlpMetricUtils::ConvertHistogramMetric( { if (nostd::holds_alternative(histogram_data.min_)) { - proto_histogram_point_data->set_min(nostd::get(histogram_data.min_)); + // Use static_cast to avoid C4244 in MSVC + proto_histogram_point_data->set_min( + static_cast(nostd::get(histogram_data.min_))); } else { @@ -116,7 +120,9 @@ void OtlpMetricUtils::ConvertHistogramMetric( } if (nostd::holds_alternative(histogram_data.max_)) { - proto_histogram_point_data->set_max(nostd::get(histogram_data.max_)); + // Use static_cast to avoid C4244 in MSVC + proto_histogram_point_data->set_max( + static_cast(nostd::get(histogram_data.max_))); } else { diff --git a/exporters/otlp/src/otlp_recordable_utils.cc b/exporters/otlp/src/otlp_recordable_utils.cc index a7f688d7f3..81859ba070 100644 --- a/exporters/otlp/src/otlp_recordable_utils.cc +++ b/exporters/otlp/src/otlp_recordable_utils.cc @@ -117,8 +117,18 @@ void OtlpRecordableUtils::PopulateRequest( if (!output_scope_log->has_scope()) { - output_scope_log->mutable_scope()->set_name(input_scope_log.first->GetName()); - output_scope_log->mutable_scope()->set_version(input_scope_log.first->GetVersion()); + auto proto_scope = output_scope_log->mutable_scope(); + if (proto_scope != nullptr) + { + proto_scope->set_name(input_scope_log.first->GetName()); + proto_scope->set_version(input_scope_log.first->GetVersion()); + + for (auto &scope_attribute : input_scope_log.first->GetAttributes()) + { + OtlpPopulateAttributeUtils::PopulateAttribute( + proto_scope->add_attributes(), scope_attribute.first, scope_attribute.second); + } + } output_scope_log->set_schema_url(input_scope_log.first->GetSchemaURL()); } diff --git a/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc b/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc index e606224133..450bebc218 100644 --- a/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc +++ b/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc @@ -136,7 +136,8 @@ TEST_F(OtlpGrpcLogRecordExporterTestPeer, ExportIntegrationTest) opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); std::unordered_map attributes; attributes["service.name"] = "unit_test_service"; attributes["tenant.id"] = "test_user"; diff --git a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc index 4df827238d..459d14a8e3 100644 --- a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc @@ -129,7 +129,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); trace_id.ToLowerBase16(MakeSpan(trace_id_hex)); report_trace_id.assign(trace_id_hex, sizeof(trace_id_hex)); @@ -147,6 +148,7 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test nlohmann::json::parse(mock_session->GetRequest()->body_, nullptr, false); auto resource_logs = *check_json["resource_logs"].begin(); auto scope_logs = *resource_logs["scope_logs"].begin(); + auto scope = scope_logs["scope"]; auto log = *scope_logs["log_records"].begin(); auto received_trace_id = log["trace_id"].get(); auto received_span_id = log["span_id"].get(); @@ -161,13 +163,29 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test EXPECT_EQ("Custom-Header-Value", custom_header->second); } + bool check_scope_attribute = false; + auto scope_attributes = scope["attributes"]; + for (auto &attribute : scope_attributes) + { + if (!attribute.is_object()) + { + continue; + } + if ("scope_key1" == attribute["key"]) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute["value"]["string_value"].get()); + } + } + ASSERT_TRUE(check_scope_attribute); + http_client::nosend::Response response; response.Finish(*callback.get()); }); logger->EmitLogRecord( opentelemetry::logs::Severity::kInfo, "Log message", - opentelemetry::logs::Logger::MakeAttributes( + opentelemetry::common::MakeAttributes( {{"service.name", "unit_test_service"}, {"tenant.id", "test_user"}, {"bool_value", true}, @@ -228,7 +246,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "opentelelemtry_library", "1.2.0", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "1.2.0", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); trace_id.ToLowerBase16(MakeSpan(trace_id_hex)); report_trace_id.assign(trace_id_hex, sizeof(trace_id_hex)); @@ -267,6 +286,22 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test EXPECT_EQ("Custom-Header-Value", custom_header->second); } + bool check_scope_attribute = false; + auto scope_attributes = scope["attributes"]; + for (auto &attribute : scope_attributes) + { + if (!attribute.is_object()) + { + continue; + } + if ("scope_key1" == attribute["key"]) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute["value"]["string_value"].get()); + } + } + ASSERT_TRUE(check_scope_attribute); + // let the otlp_http_client to continue std::thread async_finish{[callback]() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -278,7 +313,7 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test logger->EmitLogRecord( opentelemetry::logs::Severity::kInfo, "Log message", - opentelemetry::logs::Logger::MakeAttributes( + opentelemetry::common::MakeAttributes( {{"service.name", "unit_test_service"}, {"tenant.id", "test_user"}, {"bool_value", true}, @@ -336,7 +371,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "opentelelemtry_library", "1.2.0", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "1.2.0", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); report_trace_id.assign(reinterpret_cast(trace_id_bin), sizeof(trace_id_bin)); report_span_id.assign(reinterpret_cast(span_id_bin), sizeof(span_id_bin)); @@ -370,6 +406,17 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test } ASSERT_TRUE(check_service_name); + bool check_scope_attribute = false; + for (auto &attribute : scope_log.scope().attributes()) + { + if ("scope_key1" == attribute.key()) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute.value().string_value()); + } + } + ASSERT_TRUE(check_scope_attribute); + // let the otlp_http_client to continue http_client::nosend::Response response; @@ -378,7 +425,7 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test logger->EmitLogRecord( opentelemetry::logs::Severity::kInfo, "Log message", - opentelemetry::logs::Logger::MakeAttributes( + opentelemetry::common::MakeAttributes( {{"service.name", "unit_test_service"}, {"tenant.id", "test_user"}, {"bool_value", true}, @@ -437,7 +484,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); report_trace_id.assign(reinterpret_cast(trace_id_bin), sizeof(trace_id_bin)); report_span_id.assign(reinterpret_cast(span_id_bin), sizeof(span_id_bin)); @@ -446,12 +494,13 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test auto mock_session = std::static_pointer_cast(no_send_client->session_); EXPECT_CALL(*mock_session, SendRequest) - .WillOnce([&mock_session, report_trace_id, report_span_id]( + .WillOnce([&mock_session, report_trace_id, report_span_id, schema_url]( std::shared_ptr callback) { opentelemetry::proto::collector::logs::v1::ExportLogsServiceRequest request_body; request_body.ParseFromArray(&mock_session->GetRequest()->body_[0], static_cast(mock_session->GetRequest()->body_.size())); - auto received_log = request_body.resource_logs(0).scope_logs(0).log_records(0); + auto &scope_log = request_body.resource_logs(0).scope_logs(0); + auto received_log = scope_log.log_records(0); EXPECT_EQ(received_log.trace_id(), report_trace_id); EXPECT_EQ(received_log.span_id(), report_span_id); EXPECT_EQ("Log message", received_log.body().string_value()); @@ -467,6 +516,20 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test } ASSERT_TRUE(check_service_name); + auto &scope = scope_log.scope(); + EXPECT_EQ(scope.name(), "opentelelemtry_library"); + EXPECT_EQ(scope_log.schema_url(), schema_url); + bool check_scope_attribute = false; + for (auto &attribute : scope.attributes()) + { + if ("scope_key1" == attribute.key()) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute.value().string_value()); + } + } + ASSERT_TRUE(check_scope_attribute); + // let the otlp_http_client to continue std::thread async_finish{[callback]() { @@ -479,7 +542,7 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test logger->EmitLogRecord( opentelemetry::logs::Severity::kInfo, "Log message", - opentelemetry::logs::Logger::MakeAttributes( + opentelemetry::common::MakeAttributes( {{"service.name", "unit_test_service"}, {"tenant.id", "test_user"}, {"bool_value", true}, diff --git a/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h b/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h index c24b4993d2..5d75e61f75 100644 --- a/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h +++ b/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h @@ -3,8 +3,11 @@ #pragma once +#include "opentelemetry/common/key_value_iterable.h" +#include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" +#include "opentelemetry/sdk/common/attribute_utils.h" #include "opentelemetry/version.h" #include @@ -17,6 +20,8 @@ namespace sdk namespace instrumentationscope { +using InstrumentationScopeAttributes = opentelemetry::sdk::common::AttributeMap; + class InstrumentationScope { public: @@ -27,14 +32,65 @@ class InstrumentationScope * @param name name of the instrumentation scope. * @param version version of the instrumentation scope. * @param schema_url schema url of the telemetry emitted by the library. + * @param attributes attributes of the instrumentation scope. * @returns the newly created InstrumentationScope. */ - static nostd::unique_ptr Create(nostd::string_view name, - nostd::string_view version = "", - nostd::string_view schema_url = "") + static nostd::unique_ptr Create( + nostd::string_view name, + nostd::string_view version = "", + nostd::string_view schema_url = "", + InstrumentationScopeAttributes &&attributes = {}) { return nostd::unique_ptr( + new InstrumentationScope{name, version, schema_url, std::move(attributes)}); + } + + /** + * Returns a newly created InstrumentationScope with the specified library name and version. + * @param name name of the instrumentation scope. + * @param version version of the instrumentation scope. + * @param schema_url schema url of the telemetry emitted by the library. + * @param attributes attributes of the instrumentation scope. + * @returns the newly created InstrumentationScope. + */ + static nostd::unique_ptr Create( + nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const InstrumentationScopeAttributes &attributes) + { + return nostd::unique_ptr(new InstrumentationScope{ + name, version, schema_url, InstrumentationScopeAttributes(attributes)}); + } + + /** + * Returns a newly created InstrumentationScope with the specified library name and version. + * @param name name of the instrumentation scope. + * @param version version of the instrumentation scope. + * @param schema_url schema url of the telemetry emitted by the library. + * @param arg arguments used to create attributes of the instrumentation scope. + * @returns the newly created InstrumentationScope. + */ + template < + class ArgumentType, + nostd::enable_if_t::value> + * = nullptr> + static nostd::unique_ptr Create(nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const ArgumentType &arg) + { + nostd::unique_ptr result = nostd::unique_ptr( new InstrumentationScope{name, version, schema_url}); + + // Do not construct a KeyValueIterable, so it has better performance. + result->attributes_.reserve(opentelemetry::nostd::size(arg)); + for (auto &argv : arg) + { + result->SetAttribute(argv.first, argv.second); + } + + return result; } std::size_t HashCode() const noexcept { return hash_code_; } @@ -44,7 +100,7 @@ class InstrumentationScope * @param other the instrumentation scope to compare to. * @returns true if the 2 instrumentation libraries are equal, false otherwise. */ - bool operator==(const InstrumentationScope &other) const + bool operator==(const InstrumentationScope &other) const noexcept { return equal(other.name_, other.version_, other.schema_url_); } @@ -60,20 +116,28 @@ class InstrumentationScope */ bool equal(const nostd::string_view name, const nostd::string_view version, - const nostd::string_view schema_url = "") const + const nostd::string_view schema_url = "") const noexcept { return this->name_ == name && this->version_ == version && this->schema_url_ == schema_url; } - const std::string &GetName() const { return name_; } - const std::string &GetVersion() const { return version_; } - const std::string &GetSchemaURL() const { return schema_url_; } + const std::string &GetName() const noexcept { return name_; } + const std::string &GetVersion() const noexcept { return version_; } + const std::string &GetSchemaURL() const noexcept { return schema_url_; } + const InstrumentationScopeAttributes &GetAttributes() const noexcept { return attributes_; } + + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept + { + attributes_[std::string(key)] = nostd::visit(common::AttributeConverter(), value); + } private: InstrumentationScope(nostd::string_view name, nostd::string_view version, - nostd::string_view schema_url = "") - : name_(name), version_(version), schema_url_(schema_url) + nostd::string_view schema_url = "", + InstrumentationScopeAttributes &&attributes = {}) + : name_(name), version_(version), schema_url_(schema_url), attributes_(std::move(attributes)) { std::string hash_data; hash_data.reserve(name_.size() + version_.size() + schema_url_.size()); @@ -88,6 +152,8 @@ class InstrumentationScope std::string version_; std::string schema_url_; std::size_t hash_code_; + + InstrumentationScopeAttributes attributes_; }; } // namespace instrumentationscope diff --git a/sdk/include/opentelemetry/sdk/logs/logger_provider.h b/sdk/include/opentelemetry/sdk/logs/logger_provider.h index c1efd71753..a52c1a7220 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger_provider.h +++ b/sdk/include/opentelemetry/sdk/logs/logger_provider.h @@ -63,6 +63,8 @@ class LoggerProvider final : public opentelemetry::logs::LoggerProvider ~LoggerProvider() override; + using opentelemetry::logs::LoggerProvider::GetLogger; + /** * 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 diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index b262d0df44..2f75a09247 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -62,7 +62,7 @@ nostd::shared_ptr LoggerProvider::GetLogger( nostd::string_view library_version, nostd::string_view schema_url, bool include_trace_context, - const opentelemetry::common::KeyValueIterable & /*attributes*/) noexcept + const opentelemetry::common::KeyValueIterable &attributes) noexcept { // Ensure only one thread can read/write from the map of loggers std::lock_guard lock_guard{lock_}; @@ -96,14 +96,13 @@ nostd::shared_ptr LoggerProvider::GetLogger( if (library_name.empty()) { lib = instrumentationscope::InstrumentationScope::Create(logger_name, library_version, - schema_url); + schema_url, attributes); } else { lib = instrumentationscope::InstrumentationScope::Create(library_name, library_version, - schema_url); + schema_url, attributes); } - // TODO: attributes should be added into InstrumentationScope once it implement attributes. loggers_.push_back(std::shared_ptr( new Logger(logger_name, context_, std::move(lib), include_trace_context))); diff --git a/sdk/test/instrumentationscope/instrumentationscope_test.cc b/sdk/test/instrumentationscope/instrumentationscope_test.cc index f5ddeaa35a..50800fd136 100644 --- a/sdk/test/instrumentationscope/instrumentationscope_test.cc +++ b/sdk/test/instrumentationscope/instrumentationscope_test.cc @@ -7,6 +7,7 @@ #include #include +#include #include using namespace opentelemetry; @@ -14,16 +15,176 @@ using namespace opentelemetry::sdk::instrumentationscope; TEST(InstrumentationScope, CreateInstrumentationScope) { + std::string library_name = "opentelemetry-cpp"; + std::string library_version = "0.1.0"; + std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; + auto instrumentation_scope = InstrumentationScope::Create( + library_name, library_version, schema_url, + {{"attribute-key1", "attribute-value"}, + {"attribute-key2", static_cast(123)}, + {"attribute-key3", opentelemetry::nostd::span(attrubite_value3)}}); + + EXPECT_EQ(instrumentation_scope->GetName(), library_name); + EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); + EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } +} + +TEST(InstrumentationScope, CreateInstrumentationScopeWithLoopForAttributes) +{ std::string library_name = "opentelemetry-cpp"; std::string library_version = "0.1.0"; std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; + + std::unordered_map attributes = { + {"attribute-key1", "attribute-value"}, + {"attribute-key2", static_cast(123)}, + {"attribute-key3", opentelemetry::nostd::span(attrubite_value3)}}; + + auto instrumentation_scope = + InstrumentationScope::Create(library_name, library_version, schema_url, attributes); + + EXPECT_EQ(instrumentation_scope->GetName(), library_name); + EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); + EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } +} + +TEST(InstrumentationScope, CreateInstrumentationScopeWithKeyValueIterableAttributes) +{ + std::string library_name = "opentelemetry-cpp"; + std::string library_version = "0.1.0"; + std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; + + std::unordered_map attributes = { + {"attribute-key1", "attribute-value"}, + {"attribute-key2", static_cast(123)}, + {"attribute-key3", opentelemetry::nostd::span(attrubite_value3)}}; + + opentelemetry::common::KeyValueIterableView< + std::unordered_map> + attributes_view{attributes}; + + auto instrumentation_scope = + InstrumentationScope::Create(library_name, library_version, schema_url, attributes_view); + + EXPECT_EQ(instrumentation_scope->GetName(), library_name); + EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); + EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } +} + +TEST(InstrumentationScope, SetAttribute) +{ + std::string library_name = "opentelemetry-cpp"; + std::string library_version = "0.1.0"; + std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; auto instrumentation_scope = InstrumentationScope::Create(library_name, library_version, schema_url); EXPECT_EQ(instrumentation_scope->GetName(), library_name); EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + EXPECT_EQ(instrumentation_scope->GetAttributes().size(), 0); + + instrumentation_scope->SetAttribute("attribute-key1", "attribute-value"); + instrumentation_scope->SetAttribute("attribute-key2", static_cast(123)); + instrumentation_scope->SetAttribute("attribute-key3", + opentelemetry::nostd::span(attrubite_value3)); + EXPECT_EQ(instrumentation_scope->GetAttributes().size(), 3); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } } TEST(InstrumentationScope, LegacyInstrumentationLibrary) diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index db5772ebf5..cf993dc44c 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -65,9 +65,6 @@ TEST(LoggerProviderSDK, LoggerProviderGetLoggerSimple) TEST(LoggerProviderSDK, LoggerProviderLoggerArguments) { - // Currently, arguments are not supported by the loggers. - // TODO: Once the logging spec defines what arguments are allowed, add more - // detail to this test auto lp = std::shared_ptr(new LoggerProvider()); nostd::string_view schema_url{"https://opentelemetry.io/schemas/1.11.0"}; @@ -79,11 +76,29 @@ TEST(LoggerProviderSDK, LoggerProviderLoggerArguments) ASSERT_EQ(sdk_logger2->GetInstrumentationScope(), sdk_logger1->GetInstrumentationScope()); auto logger3 = lp->GetLogger("logger3", "opentelelemtry_library", "", schema_url, true, - {{"scope_key1", "scope_value"}, {"scope_key1", 2}}); + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); + + auto sdk_logger3 = static_cast(logger3.get()); + EXPECT_EQ(sdk_logger3->GetInstrumentationScope().GetAttributes().size(), 2); + { + auto attibute = sdk_logger3->GetInstrumentationScope().GetAttributes().find("scope_key1"); + ASSERT_FALSE(attibute == sdk_logger3->GetInstrumentationScope().GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attibute->second)); + EXPECT_EQ(opentelemetry::nostd::get(attibute->second), "scope_value"); + } std::unordered_map scope_attributes = {{"scope_key", "scope_value"}}; auto logger4 = lp->GetLogger("logger4", "opentelelemtry_library", "", schema_url, true, scope_attributes); + auto sdk_logger4 = static_cast(logger4.get()); + + EXPECT_EQ(sdk_logger4->GetInstrumentationScope().GetAttributes().size(), 1); + { + auto attibute = sdk_logger4->GetInstrumentationScope().GetAttributes().find("scope_key"); + ASSERT_FALSE(attibute == sdk_logger4->GetInstrumentationScope().GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attibute->second)); + EXPECT_EQ(opentelemetry::nostd::get(attibute->second), "scope_value"); + } } TEST(LoggerProviderSDK, EventLoggerProviderFactory)