From 84dab2ceb9148e8ccf48b84fa57309cbb3d37f84 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 20 Dec 2020 05:45:53 -0700 Subject: [PATCH] Supporting Logging API .Log() Overloads and GetName() method (#422) --- api/include/opentelemetry/logs/logger.h | 457 +++++++++++++++++- api/include/opentelemetry/logs/noop.h | 2 + api/test/logs/BUILD | 4 +- api/test/logs/CMakeLists.txt | 10 +- api/test/logs/logger_test.cc | 53 +- ...gger_provider_test.cc => provider_test.cc} | 0 exporters/ostream/test/ostream_log_test.cc | 2 +- sdk/include/opentelemetry/sdk/logs/logger.h | 6 + sdk/src/logs/logger.cc | 5 + sdk/test/logs/logger_sdk_test.cc | 13 +- 10 files changed, 508 insertions(+), 44 deletions(-) rename api/test/logs/{logger_provider_test.cc => provider_test.cc} (100%) diff --git a/api/include/opentelemetry/logs/logger.h b/api/include/opentelemetry/logs/logger.h index fc486ec464..c7e4896165 100644 --- a/api/include/opentelemetry/logs/logger.h +++ b/api/include/opentelemetry/logs/logger.h @@ -44,6 +44,9 @@ class Logger public: virtual ~Logger() = default; + /* Returns the name of the logger */ + virtual const nostd::string_view GetName() noexcept = 0; + /** * Each of the following overloaded Log(...) methods * creates a log message with the specific parameters passed. @@ -123,25 +126,457 @@ class Logger /** Wrapper methods that the user could call for convenience when logging **/ - // Set default values for unspecified fields, then call the base Log() method - void Log(Severity severity, nostd::string_view message, core::SystemTimestamp timestamp) noexcept + /** + * Writes a log. + * @param severity The severity of the log + * @param message The message to log + */ + void Log(Severity severity, nostd::string_view message) noexcept { - this->Log(severity, "", message, {}, {}, {}, {}, {}, timestamp); + this->Log(severity, "", message, {}, {}, {}, {}, {}, std::chrono::system_clock::now()); } - // Set default time, and call base Log(severity, message, time) method - void Log(Severity severity, nostd::string_view message) noexcept + /** + * Writes a log. + * @param severity The severity of the log + * @param name The name of the log + * @param message The message to log + */ + void Log(Severity severity, nostd::string_view name, nostd::string_view message) noexcept + { + this->Log(severity, name, message, {}, {}, {}, {}, {}, std::chrono::system_clock::now()); + } + + /** + * Writes a log. + * @param severity The severity of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + inline void Log(Severity severity, const T &attributes) noexcept + { + this->Log(severity, "", "", std::map{}, attributes, {}, {}, {}, + std::chrono::system_clock::now()); + } + + /** + * Writes a log. + * @param severity The severity of the log + * @param name The name of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + inline void Log(Severity severity, nostd::string_view name, const T &attributes) noexcept + { + this->Log(severity, name, "", std::map{}, attributes, {}, {}, {}, + std::chrono::system_clock::now()); + } + + /** + * Writes a log. + * @param severity The severity of the log + * @param attributes The attributes of the log as an initializer list + */ + void Log(Severity severity, + std::initializer_list> + attributes) noexcept + { + this->Log(severity, "", "", {}, attributes, {}, {}, {}, std::chrono::system_clock::now()); + } + + /** + * Writes a log. + * @param severity The severity of the log + * @param name The name of the log + * @param attributes The attributes of the log as an initializer list + */ + void Log(Severity severity, + nostd::string_view name, + std::initializer_list> + attributes) noexcept + { + this->Log(severity, name, "", {}, attributes, {}, {}, {}, std::chrono::system_clock::now()); + } + + /** Trace severity overloads **/ + + /** + * Writes a log with a severity of trace. + * @param message The message to log + */ + void Trace(nostd::string_view message) noexcept { this->Log(Severity::kTrace, message); } + + /** + * Writes a log with a severity of trace. + * @param name The name of the log + * @param message The message to log + */ + void Trace(nostd::string_view name, nostd::string_view message) noexcept + { + this->Log(Severity::kTrace, name, message); + } + + /** + * Writes a log with a severity of trace. + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Trace(const T &attributes) noexcept + { + this->Log(Severity::kTrace, attributes); + } + + /** + * Writes a log with a severity of trace. + * @param name The name of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Trace(nostd::string_view name, const T &attributes) noexcept + { + this->Log(Severity::kTrace, name, attributes); + } + + /** + * Writes a log with a severity of trace. + * @param attributes The attributes of the log as an initializer list + */ + void Trace(std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kTrace, attributes); + } + + /** + * Writes a log with a severity of trace. + * @param name The name of the log + * @param attributes The attributes of the log as an initializer list + */ + void Trace(nostd::string_view name, + std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kTrace, name, attributes); + } + + /** Debug severity overloads **/ + + /** + * Writes a log with a severity of debug. + * @param message The message to log + */ + void Debug(nostd::string_view message) noexcept { this->Log(Severity::kDebug, message); } + + /** + * Writes a log with a severity of debug. + * @param name The name of the log + * @param message The message to log + */ + void Debug(nostd::string_view name, nostd::string_view message) noexcept + { + this->Log(Severity::kDebug, name, message); + } + + /** + * Writes a log with a severity of debug. + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Debug(const T &attributes) noexcept + { + this->Log(Severity::kDebug, attributes); + } + + /** + * Writes a log with a severity of debug. + * @param name The name of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Debug(nostd::string_view name, const T &attributes) noexcept + { + this->Log(Severity::kDebug, name, attributes); + } + + /** + * Writes a log with a severity of debug. + * @param attributes The attributes of the log as an initializer list + */ + void Debug(std::initializer_list> + attributes) noexcept { - this->Log(severity, message, std::chrono::system_clock::now()); + this->Log(Severity::kDebug, attributes); } - // Set default severity then call Log(Severity, String message) method - void Log(nostd::string_view message) noexcept { this->Log(Severity::kInfo, message); } + /** + * Writes a log with a severity of debug. + * @param name The name of the log + * @param attributes The attributes of the log as an initializer list + */ + void Debug(nostd::string_view name, + std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kDebug, name, attributes); + } - // TODO: Add more overloaded Log(...) methods with different combiantions of parameters. + /** Info severity overloads **/ - // TODO: Add function aliases such as void debug(), void trace(), void info(), etc. for each - // severity level + /** + * Writes a log with a severity of info. + * @param message The message to log + */ + void Info(nostd::string_view message) noexcept { this->Log(Severity::kInfo, message); } + + /** + * Writes a log with a severity of info. + * @param name The name of the log + * @param message The message to log + */ + void Info(nostd::string_view name, nostd::string_view message) noexcept + { + this->Log(Severity::kInfo, name, message); + } + + /** + * Writes a log with a severity of info. + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Info(const T &attributes) noexcept + { + this->Log(Severity::kInfo, attributes); + } + + /** + * Writes a log with a severity of info. + * @param name The name of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Info(nostd::string_view name, const T &attributes) noexcept + { + this->Log(Severity::kInfo, name, attributes); + } + + /** + * Writes a log with a severity of info. + * @param attributes The attributes of the log as an initializer list + */ + void Info(std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kInfo, attributes); + } + + /** + * Writes a log with a severity of info. + * @param name The name of the log + * @param attributes The attributes of the log as an initializer list + */ + void Info(nostd::string_view name, + std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kInfo, name, attributes); + } + + /** Warn severity overloads **/ + + /** + * Writes a log with a severity of warn. + * @param message The message to log + */ + void Warn(nostd::string_view message) noexcept { this->Log(Severity::kWarn, message); } + + /** + * Writes a log with a severity of warn. + * @param name The name of the log + * @param message The message to log + */ + void Warn(nostd::string_view name, nostd::string_view message) noexcept + { + this->Log(Severity::kWarn, name, message); + } + + /** + * Writes a log with a severity of warn. + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Warn(const T &attributes) noexcept + { + this->Log(Severity::kWarn, attributes); + } + + /** + * Writes a log with a severity of warn. + * @param name The name of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Warn(nostd::string_view name, const T &attributes) noexcept + { + this->Log(Severity::kWarn, name, attributes); + } + + /** + * Writes a log with a severity of warn. + * @param attributes The attributes of the log as an initializer list + */ + void Warn(std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kWarn, attributes); + } + + /** + * Writes a log with a severity of warn. + * @param name The name of the log + * @param attributes The attributes of the log as an initializer list + */ + void Warn(nostd::string_view name, + std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kWarn, name, attributes); + } + + /** Error severity overloads **/ + + /** + * Writes a log with a severity of error. + * @param message The message to log + */ + void Error(nostd::string_view message) noexcept { this->Log(Severity::kError, message); } + + /** + * Writes a log with a severity of error. + * @param name The name of the log + * @param message The message to log + */ + void Error(nostd::string_view name, nostd::string_view message) noexcept + { + this->Log(Severity::kError, name, message); + } + + /** + * Writes a log with a severity of error. + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Error(const T &attributes) noexcept + { + this->Log(Severity::kError, attributes); + } + + /** + * Writes a log with a severity of error. + * @param name The name of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Error(nostd::string_view name, const T &attributes) noexcept + { + this->Log(Severity::kError, name, attributes); + } + + /** + * Writes a log with a severity of error. + * @param attributes The attributes of the log as an initializer list + */ + void Error(std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kError, attributes); + } + + /** + * Writes a log with a severity of error. + * @param name The name of the log + * @param attributes The attributes of the log as an initializer list + */ + void Error(nostd::string_view name, + std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kError, name, attributes); + } + + /** Fatal severity overloads **/ + + /** + * Writes a log with a severity of fatal. + * @param message The message to log + */ + void Fatal(nostd::string_view message) noexcept { this->Log(Severity::kFatal, message); } + + /** + * Writes a log with a severity of fatal. + * @param name The name of the log + * @param message The message to log + */ + void Fatal(nostd::string_view name, nostd::string_view message) noexcept + { + this->Log(Severity::kFatal, name, message); + } + + /** + * Writes a log with a severity of fatal. + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Fatal(const T &attributes) noexcept + { + this->Log(Severity::kFatal, attributes); + } + + /** + * Writes a log with a severity of fatal. + * @param name The name of the log + * @param attributes The attributes of the log as a key/value object + */ + template ::value> * = nullptr> + void Fatal(nostd::string_view name, const T &attributes) noexcept + { + this->Log(Severity::kFatal, name, attributes); + } + + /** + * Writes a log with a severity of fatal. + * @param attributes The attributes of the log as an initializer list + */ + void Fatal(std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kFatal, attributes); + } + + /** + * Writes a log with a severity of fatal. + * @param name The name of the log + * @param attributes The attributes of the log as an initializer list + */ + void Fatal(nostd::string_view name, + std::initializer_list> + attributes) noexcept + { + this->Log(Severity::kFatal, name, attributes); + } }; } // namespace logs OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/logs/noop.h b/api/include/opentelemetry/logs/noop.h index 8a19e1a677..86738692c1 100644 --- a/api/include/opentelemetry/logs/noop.h +++ b/api/include/opentelemetry/logs/noop.h @@ -50,6 +50,8 @@ namespace logs class NoopLogger final : public Logger { public: + const nostd::string_view GetName() noexcept override { return "noop logger"; } + void Log(Severity severity, nostd::string_view name, nostd::string_view body, diff --git a/api/test/logs/BUILD b/api/test/logs/BUILD index 899400b2e8..cba6f19220 100644 --- a/api/test/logs/BUILD +++ b/api/test/logs/BUILD @@ -1,9 +1,9 @@ load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( - name = "logger_provider_test", + name = "provider_test", srcs = [ - "logger_provider_test.cc", + "provider_test.cc", ], deps = [ "//api", diff --git a/api/test/logs/CMakeLists.txt b/api/test/logs/CMakeLists.txt index 9b1b3b0e7d..a5f9c04084 100644 --- a/api/test/logs/CMakeLists.txt +++ b/api/test/logs/CMakeLists.txt @@ -1,9 +1,9 @@ -foreach(testname logger_provider_test logger_test) - add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} +foreach(testname provider_test logger_test) + add_executable(logs_api_${testname} "${testname}.cc") + target_link_libraries(logs_api_${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( - TARGET ${testname} + TARGET logs_api_${testname} TEST_PREFIX logs. - TEST_LIST ${testname}) + TEST_LIST logs_api_${testname}) endforeach() diff --git a/api/test/logs/logger_test.cc b/api/test/logs/logger_test.cc index d875a54c35..de03c8d403 100644 --- a/api/test/logs/logger_test.cc +++ b/api/test/logs/logger_test.cc @@ -14,40 +14,61 @@ using opentelemetry::nostd::shared_ptr; using opentelemetry::nostd::span; using opentelemetry::nostd::string_view; +// Check that the default logger is a noop logger instance TEST(Logger, GetLoggerDefault) { auto lp = Provider::GetLoggerProvider(); auto logger = lp->GetLogger("TestLogger"); + auto name = logger->GetName(); EXPECT_NE(nullptr, logger); + EXPECT_EQ(name, "noop logger"); } -TEST(Logger, GetNoopLoggerName) -{ - auto lp = Provider::GetLoggerProvider(); - auto logger = lp->GetLogger("TestLogger"); -} - +// Test the two additional overloads for GetLogger() TEST(Logger, GetNoopLoggerNameWithArgs) { auto lp = Provider::GetLoggerProvider(); + // GetLogger(name, list(args)) std::array sv{"string"}; span args{sv}; - auto logger = lp->GetLogger("NoopLoggerWithArgs", args); - // should probably also test that arguments were set properly too - // by adding a getArgs() method in NoopLogger + lp->GetLogger("NoopLoggerWithArgs", args); + + // GetLogger(name, string options) + lp->GetLogger("NoopLoggerWithOptions", "options"); } -TEST(Logger, NoopLog) +// Test the Log() overloads +TEST(Logger, LogMethodOverloads) { auto lp = Provider::GetLoggerProvider(); auto logger = lp->GetLogger("TestLogger"); - logger->Log("Noop log name"); + + // Create a map to test the logs with + std::map m = {{"key1", "value1"}}; + + // Log overloads + logger->Log(Severity::kTrace, "Test log message"); + logger->Log(Severity::kInfo, "Logging a message", "Test log message"); + logger->Log(Severity::kDebug, m); + logger->Log(Severity::kWarn, "Logging a map", m); + logger->Log(Severity::kError, {{"key1", "value 1"}, {"key2", 2}}); + logger->Log(Severity::kFatal, "Logging an initializer list", {{"key1", "value 1"}, {"key2", 2}}); + + // Severity methods + logger->Trace("Test log message"); + logger->Debug("Logging a message", "Test log message"); + logger->Info(m); + logger->Warn("Logging a map", m); + logger->Error({{"key1", "value 1"}, {"key2", 2}}); + logger->Fatal("Logging an initializer list", {{"key1", "value 1"}, {"key2", 2}}); } // Define a basic Logger class class TestLogger : public Logger { + const opentelemetry::nostd::string_view GetName() noexcept override { return "test logger"; } + void Log(Severity severity, string_view name, string_view body, @@ -82,11 +103,7 @@ TEST(Logger, PushLoggerImplementation) auto lp = Provider::GetLoggerProvider(); - // GetLogger(name, options) function + // Check that the implementation was pushed by calling TestLogger's GetName() auto logger = lp->GetLogger("TestLogger"); - - // GetLogger(name, args) function - std::array sv{"string"}; - span args{sv}; - auto logger2 = lp->GetLogger("TestLogger2", args); -} + ASSERT_EQ("test logger", logger->GetName()); +} \ No newline at end of file diff --git a/api/test/logs/logger_provider_test.cc b/api/test/logs/provider_test.cc similarity index 100% rename from api/test/logs/logger_provider_test.cc rename to api/test/logs/provider_test.cc diff --git a/exporters/ostream/test/ostream_log_test.cc b/exporters/ostream/test/ostream_log_test.cc index e91528b20a..b091a71b3d 100644 --- a/exporters/ostream/test/ostream_log_test.cc +++ b/exporters/ostream/test/ostream_log_test.cc @@ -253,7 +253,7 @@ TEST(OStreamLogExporter, IntegrationTest) // Write a log to ostream exporter opentelemetry::core::SystemTimestamp now(std::chrono::system_clock::now()); - logger->Log(opentelemetry::logs::Severity::kDebug, "Hello", now); + logger->Log(opentelemetry::logs::Severity::kDebug, "", "Hello", {}, {}, {}, {}, {}, now); // Restore cout's original streambuf std::cout.rdbuf(original); diff --git a/sdk/include/opentelemetry/sdk/logs/logger.h b/sdk/include/opentelemetry/sdk/logs/logger.h index 385ba3586b..8cf21a09f6 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger.h +++ b/sdk/include/opentelemetry/sdk/logs/logger.h @@ -34,11 +34,17 @@ class Logger final : public opentelemetry::logs::Logger public: /** * Initialize a new logger. + * @param name The name of this logger instance * @param logger_provider The logger provider that owns this logger. */ explicit Logger(opentelemetry::nostd::string_view name, std::shared_ptr logger_provider) noexcept; + /** + * Returns the name of this logger. + */ + const opentelemetry::nostd::string_view GetName() noexcept override; + /** * Writes a log record into the processor. * @param severity the severity level of the log event. diff --git a/sdk/src/logs/logger.cc b/sdk/src/logs/logger.cc index 6e201da04e..ad87ca505a 100644 --- a/sdk/src/logs/logger.cc +++ b/sdk/src/logs/logger.cc @@ -27,6 +27,11 @@ Logger::Logger(opentelemetry::nostd::string_view name, : logger_name_(std::string(name)), logger_provider_(logger_provider) {} +const opentelemetry::nostd::string_view Logger::GetName() noexcept +{ + return logger_name_; +} + /** * Create and populate recordable with the log event's fields passed in. * The timestamp, severity, traceid, spanid, and traceflags, are injected diff --git a/sdk/test/logs/logger_sdk_test.cc b/sdk/test/logs/logger_sdk_test.cc index e1993f15ec..669ae2fbc0 100644 --- a/sdk/test/logs/logger_sdk_test.cc +++ b/sdk/test/logs/logger_sdk_test.cc @@ -31,7 +31,7 @@ TEST(LoggerSDK, LogToNullProcessor) auto logger = lp->GetLogger("logger"); // Log a sample log record to a nullptr processor - logger->Log("Test log"); + logger->Debug("Test log"); } class MockProcessor final : public LogProcessor @@ -56,11 +56,11 @@ class MockProcessor final : public LogProcessor // Cast the recordable received into a concrete LogRecord type auto copy = std::shared_ptr(static_cast(record.release())); - // Copy over the received log record's name, body, timestamp fields over to the recordable + // Copy over the received log record's severity, name, and body fields over to the recordable // passed in the constructor record_received_->SetSeverity(copy->GetSeverity()); + record_received_->SetName(copy->GetName()); record_received_->SetBody(copy->GetBody()); - record_received_->SetTimestamp(copy->GetTimestamp()); } bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept { @@ -92,10 +92,9 @@ TEST(LoggerSDK, LogToAProcessor) ASSERT_EQ(processor, lp->GetProcessor()); // Check that the recordable created by the Log() statement is set properly - opentelemetry::core::SystemTimestamp now(std::chrono::system_clock::now()); - logger->Log(opentelemetry::logs::Severity::kWarn, "Message", now); + logger->Log(opentelemetry::logs::Severity::kWarn, "Log Name", "Log Message"); ASSERT_EQ(shared_recordable->GetSeverity(), opentelemetry::logs::Severity::kWarn); - ASSERT_EQ(shared_recordable->GetBody(), "Message"); - ASSERT_EQ(shared_recordable->GetTimestamp().time_since_epoch(), now.time_since_epoch()); + ASSERT_EQ(shared_recordable->GetName(), "Log Name"); + ASSERT_EQ(shared_recordable->GetBody(), "Log Message"); }