diff --git a/api/include/opentelemetry/logs/log_record.h b/api/include/opentelemetry/logs/log_record.h index c663c1c9c7..f8d905ba6e 100644 --- a/api/include/opentelemetry/logs/log_record.h +++ b/api/include/opentelemetry/logs/log_record.h @@ -65,11 +65,6 @@ enum class Severity : uint8_t kDefault = kInfo // default severity is set to kInfo level, similar to what is done in ILogger }; -/* _nullKV is defined as a private variable that allows "resource" and - "attributes" fields to be instantiated using it as the default value */ -static common::KeyValueIterableView> _nullKV = - common::KeyValueIterableView>{{}}; - /** * A default Event object to be passed in log statements, * matching the 10 fields of the Log Data Model. @@ -82,25 +77,28 @@ struct LogRecord core::SystemTimestamp timestamp; // uint64 nanoseconds since Unix epoch trace::TraceId trace_id; // byte sequence trace::SpanId span_id; // byte sequence - trace::TraceFlags trace_flag; // byte - Severity severity; // Severity enum that combines severity_text and severity_number in the - // LogDataModel (can separate in SDK) + trace::TraceFlags trace_flags; // byte + Severity severity; // Severity enum that combines severity_text and severity_number // other fields that will not be set by default nostd::string_view name; // string nostd::string_view body; // currently a simple string, but should be changed "Any" type - common::KeyValueIterable &resource; // key/value pair list - common::KeyValueIterable &attributes; // key/value pair list + nostd::shared_ptr resource; // key/value pair list + nostd::shared_ptr attributes; // key/value pair list /* Default log record if user does not overwrite this. * TODO: find better data type to represent the type for "body" * Future enhancement: Potentially add other constructors to take default arguments * from the user **/ - LogRecord() : resource(_nullKV), attributes(_nullKV) + LogRecord() { - // TODO: in SDK, assign a default timestamp if not specified - name = ""; + // Assign default values + timestamp = core::SystemTimestamp(std::chrono::seconds(0)); + severity = Severity::kDefault; + trace_id = trace::TraceId(); + span_id = trace::SpanId(); + trace_flags = trace::TraceFlags(); } /* for ease of use; user can use this function to convert a map into a KeyValueIterable for the diff --git a/api/include/opentelemetry/logs/logger.h b/api/include/opentelemetry/logs/logger.h index 5f22066460..ec592c7a54 100644 --- a/api/include/opentelemetry/logs/logger.h +++ b/api/include/opentelemetry/logs/logger.h @@ -39,8 +39,7 @@ class Logger virtual ~Logger() = default; /* Returns the name of the logger */ - // TODO: decide whether this is useful and/or should be kept, as this is not a method required in - // the specification. virtual nostd::string_view getName() = 0; + virtual const nostd::string_view GetName() noexcept = 0; /** * Each of the following overloaded log(...) methods @@ -55,65 +54,129 @@ class Logger * @throws No exceptions under any circumstances. */ - /* The below method is a logging statement that takes in a LogRecord. - * A default LogRecord that will be assigned if no parameters are passed to Logger's .log() method - * which should at minimum assign the trace_id, span_id, and timestamp + /** + * Logs a LogRecord, which contains all the fields of the Log Data Model. Normally called indirectly from other Log() Methods, but can be called directly for high detail. + * @param record A log record filled with information from the user. */ - virtual void log(const LogRecord &record) noexcept = 0; - - /** Overloaded methods for unstructured logging **/ - inline void log(nostd::string_view message) noexcept + virtual void Log(const LogRecord &record) noexcept = 0; + + ///Overloaded Log methods, which are simpler than calling a LogRecord directly + + /** + * Writes a log. + * @param severity The log's severity + * @param message The message to log + */ + inline void Log(Severity severity, nostd::string_view message) noexcept { - // Set severity to the default then call log(Severity, String message) method - log(Severity::kDefault, message); - } + //Create a LogRecord to hold this information + LogRecord r; + r.severity = severity; + r.body = message; - inline void log(Severity severity, nostd::string_view message) noexcept - { - // TODO: set default timestamp later (not in API) - log(severity, message, core::SystemTimestamp(std::chrono::system_clock::now())); + //Call the main Log(LogRecord) method + Log(r); } - inline void log(Severity severity, - nostd::string_view message, - core::SystemTimestamp time) noexcept + /** + * Writes a log. + * @param severity The log's severity + * @param name The name of the log + * @param message The message to log + */ + inline void Log(Severity severity, nostd::string_view name, nostd::string_view message) noexcept { - // creates a LogRecord object with given parameters, then calls log(LogRecord) + //Create a LogRecord to hold this information LogRecord r; - r.severity = severity; - r.body = message; - r.timestamp = time; + r.severity = severity; + r.name = name; + r.body = message; - log(r); + //Call the main Log(LogRecord) method + Log(r); } - /** Overloaded methods for structured logging**/ - // TODO: separate this method into separate methods since it is not useful for user to create - // empty logs + /** + * Writes a log. + * @param severity The severity of the log, from 1 to 24 + * @param attributes A key/value object + */ template ::value> * = nullptr> - inline void log(Severity severity = Severity::kDefault, - nostd::string_view name = "", - const T &attributes = {}) noexcept + nostd::enable_if_t::value> * = nullptr> + inline void Log(Severity severity, const T &attributes) noexcept { - log(severity, name, common::KeyValueIterableView(attributes)); + //Create a LogRecord to hold this information + LogRecord r; + r.severity = severity; + r.attributes = nostd::shared_ptr(new common::KeyValueIterableView{attributes}); + + //Call the main Log(LogRecord) method + Log(r); } - inline void log(Severity severity, - nostd::string_view name, - const common::KeyValueIterable &attributes) noexcept + /** + * Writes a log. + * @param severity The severity of the log, from 1 to 24 + * @param name The name of the log + * @param attributes A key/value object + */ + template ::value> * = nullptr> + inline void Log(Severity severity, nostd::string_view name, const T &attributes) noexcept { - // creates a LogRecord object with given parameters, then calls log(LogRecord) + //Create a LogRecord to hold this information LogRecord r; r.severity = severity; r.name = name; - r.attributes = attributes; + r.attributes = nostd::shared_ptr(new common::KeyValueIterableView{attributes}); + + //Call the main Log(LogRecord) method + Log(r); + } + + ///Trace overloads - log(r); + /** + * Writes a log with a severity of trace. + * @param message The message to log + */ + inline void Trace(nostd::string_view message) noexcept + { + 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 + */ + inline void Trace(nostd::string_view name, nostd::string_view message) noexcept + { + Log(Severity::kTrace, name, message); } - // TODO: add function aliases such as void debug(), void trace(), void info(), etc. for each - // severity level + /** + * Writes a log with a severity of trace. + * @param attributes A key/value object + */ + template ::value> * = nullptr> + inline void Trace(const T &attributes) noexcept + { + Log(Severity::kTrace, attributes); + } + + /** + * Writes a log with a severity of trace. + * @param name The name of the log + * @param attributes A key/value object + */ + template ::value> * = nullptr> + inline void Trace(nostd::string_view name, const T &attributes) noexcept + { + Log(Severity::kTrace, name, attributes); + } /** Future enhancement: templated method for objects / custom types (e.g. JSON, XML, custom * classes, etc) **/ diff --git a/api/include/opentelemetry/logs/noop.h b/api/include/opentelemetry/logs/noop.h index 3184baa3c6..43406771d9 100644 --- a/api/include/opentelemetry/logs/noop.h +++ b/api/include/opentelemetry/logs/noop.h @@ -41,7 +41,8 @@ class NoopLogger final : public Logger public: NoopLogger() = default; - void log(const LogRecord &record) noexcept override {} + void Log(const LogRecord& record) noexcept override {} + const nostd::string_view GetName() noexcept override { return "noop logger"; }; }; /** 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 737edb893c..8f797b97c1 100644 --- a/api/test/logs/CMakeLists.txt +++ b/api/test/logs/CMakeLists.txt @@ -1,6 +1,6 @@ -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} TEST_PREFIX logs. TEST_LIST ${testname}) + gtest_add_tests(TARGET logs_api_${testname} TEST_PREFIX logs. TEST_LIST logs_api_${testname}) endforeach() diff --git a/api/test/logs/logger_test.cc b/api/test/logs/logger_test.cc index 937ece860a..b05e333a93 100644 --- a/api/test/logs/logger_test.cc +++ b/api/test/logs/logger_test.cc @@ -15,43 +15,41 @@ using opentelemetry::nostd::shared_ptr; using opentelemetry::nostd::span; using opentelemetry::nostd::string_view; -TEST(Logger, GetLoggerDefault) +TEST(LoggerTest, GetLoggerDefaultNoop) { auto lp = Provider::GetLoggerProvider(); auto logger = lp->GetLogger("TestLogger"); EXPECT_NE(nullptr, logger); + EXPECT_EQ(logger->GetName(), "noop logger"); } -TEST(Logger, GetNoopLoggerName) -{ - auto lp = Provider::GetLoggerProvider(); - auto logger = lp->GetLogger("TestLogger"); -} - -TEST(Logger, GetNoopLoggerNameWithArgs) +TEST(LoggerTest, GetLogger) { auto lp = Provider::GetLoggerProvider(); + // Get a logger with no arguments + auto logger1 = lp->GetLogger("TestLogger1"); + + // Get a logger with options passed + auto logger2 = lp->GetLogger("TestLogger2", "Options"); + + // Get a logger with arguments 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 + auto logger3 = lp->GetLogger("TestLogger3", args); } -TEST(Logger, NoopLog) -{ - auto lp = Provider::GetLoggerProvider(); - auto logger = lp->GetLogger("TestLogger"); - LogRecord r; - r.name = "Noop log name"; - logger->log(r); -} +// Define a global log record that will be modified when the Log() method is called +static opentelemetry::nostd::shared_ptr record_; // Define a basic Logger class class TestLogger : public Logger { - void log(const LogRecord &record) noexcept override {} + void Log(const LogRecord &record) noexcept override + { + record_ = opentelemetry::nostd::shared_ptr(new LogRecord(record)); + } + const opentelemetry::nostd::string_view GetName() noexcept override { return "test logger"; }; }; // Define a basic LoggerProvider class that returns an instance of the logger class defined above @@ -68,19 +66,67 @@ class TestProvider : public LoggerProvider } }; -TEST(Logger, PushLoggerImplementation) +TEST(LoggerTest, PushLoggerImplementation) { - // Push the new loggerprovider class into the global singleton + // Push the new loggerprovider class into the API auto test_provider = shared_ptr(new TestProvider()); Provider::SetLoggerProvider(test_provider); auto lp = Provider::GetLoggerProvider(); - // GetLogger(name, options) function + // Get a logger instance and check whether it's GetName() method returns + // "test logger" as defined in the custom implementation auto logger = lp->GetLogger("TestLogger"); + ASSERT_EQ("test logger", logger->GetName()); +} - // GetLogger(name, args) function - std::array sv{"string"}; - span args{sv}; - auto logger2 = lp->GetLogger("TestLogger2", args); +TEST(Logger, LogMethodOverloads) +{ + // Use the same TestProvider and TestLogger from the previous test + auto test_provider = shared_ptr(new TestProvider()); + Provider::SetLoggerProvider(test_provider); + + auto lp = Provider::GetLoggerProvider(); + auto logger = lp->GetLogger("TestLogger"); + + // Check that calling the Log() overloads correctly constructs a log record which is automatically put into the static logger_ for testing + + // Test Log(severity, name, message) method + logger->Log(Severity::kError, "Log Name", "This is the log message"); + ASSERT_EQ(record_->severity, Severity::kError); + ASSERT_EQ(record_->name, "Log Name"); + ASSERT_EQ(record_->body, "This is the log message"); + + // Test Trace(name, KVIterable) method + std::map m = {{"key1", "val1"}, {"key2", "val2"}}; + logger->Trace("Logging a map", m); + ASSERT_EQ(record_->severity, Severity::kTrace); + ASSERT_EQ(record_->name, "Logging a map"); + ASSERT_EQ(record_->attributes->size(), 2); +} + +TEST(LogRecord, SetDefault) +{ + LogRecord r; + + // Check that the timestamp is set to 0 by default + ASSERT_EQ(r.timestamp, opentelemetry::core::SystemTimestamp(std::chrono::seconds(0))); + + // Check that the severity is set to kDefault by default + ASSERT_EQ(r.severity, Severity::kDefault); + + // Check that trace_id is set to all zeros by default + char trace_buf[32]; + r.trace_id.ToLowerBase16(trace_buf); + ASSERT_EQ(std::string(trace_buf, sizeof(trace_buf)), "00000000000000000000000000000000"); + + // Check that span_id is set to all zeros by default + char span_buf[16]; + r.span_id.ToLowerBase16(span_buf); + ASSERT_EQ(std::string(span_buf, sizeof(span_buf)), "0000000000000000"); + + // Check that trace_flags is set to all zeros by default + char flags_buf[2]; + r.trace_flags.ToLowerBase16(flags_buf); + ASSERT_EQ(std::string(flags_buf, sizeof(flags_buf)), "00"); } 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/sdk/include/opentelemetry/sdk/logs/logger.h b/sdk/include/opentelemetry/sdk/logs/logger.h index 4b49351030..eb629bd480 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger.h +++ b/sdk/include/opentelemetry/sdk/logs/logger.h @@ -39,20 +39,30 @@ 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(std::shared_ptr logger_provider) noexcept; + 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 record The record to write into the processor. */ - void log(const opentelemetry::logs::LogRecord &record) noexcept override; + void Log(const opentelemetry::logs::LogRecord &record) noexcept override; private: // The logger provider of this Logger. Uses a weak_ptr to avoid cyclic dependancy issues the with // logger provider std::weak_ptr logger_provider_; + + // The name of this logger + opentelemetry::nostd::string_view logger_name_; }; } // namespace logs diff --git a/sdk/include/opentelemetry/sdk/logs/logger_provider.h b/sdk/include/opentelemetry/sdk/logs/logger_provider.h index fdba956624..e6c4f23073 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger_provider.h +++ b/sdk/include/opentelemetry/sdk/logs/logger_provider.h @@ -29,8 +29,8 @@ #include "opentelemetry/sdk/logs/processor.h" // Define the maximum number of loggers that are allowed to be registered to the loggerprovider. -// TODO: Add link to logging spec once this is added to it -#define MAX_LOGGER_COUNT 100 +// References spec issue https://github.com/open-telemetry/opentelemetry-specification/issues/1259 +#define OTEL_MAX_LOGGER_COUNT 1000 OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -95,6 +95,9 @@ class LoggerProvider final : public opentelemetry::logs::LoggerProvider, // A mutex that ensures only one thread is using the map of loggers std::mutex mu_; + + // A noop logger that is returned by GetLogger() when OTEL_MAX_LOGGER_COUNT reached + opentelemetry::nostd::shared_ptr noop_logger_; }; } // namespace logs } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/logs/processor.h b/sdk/include/opentelemetry/sdk/logs/processor.h index d77b7a65d0..42cc3008c8 100644 --- a/sdk/include/opentelemetry/sdk/logs/processor.h +++ b/sdk/include/opentelemetry/sdk/logs/processor.h @@ -26,22 +26,38 @@ namespace sdk namespace logs { /** - * This Log Processor is responsible for conversion of logs to exportable - * representation and passing them to exporters. + * The Log Processor is responsible for passing log records + * to the configured exporter. */ class LogProcessor { public: virtual ~LogProcessor() = default; + /** + * OnReceive is called by the SDK once a log record has been successfully created. + * @param record the log record + */ virtual void OnReceive(std::unique_ptr &&record) noexcept = 0; - virtual void ForceFlush( - std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0; + /** + * 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 + */ + virtual bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0; - virtual void Shutdown( - std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0; + /** + * 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 + */ + virtual bool Shutdown( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0; }; } // namespace logs } // namespace sdk -OPENTELEMETRY_END_NAMESPACE +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/sdk/src/logs/BUILD b/sdk/src/logs/BUILD index c1a0542fa1..4829b3838f 100644 --- a/sdk/src/logs/BUILD +++ b/sdk/src/logs/BUILD @@ -22,5 +22,6 @@ cc_library( deps = [ "//api", "//sdk:headers", + "//sdk/src/trace", ], ) diff --git a/sdk/src/logs/CMakeLists.txt b/sdk/src/logs/CMakeLists.txt index 22260f059d..88380775ca 100644 --- a/sdk/src/logs/CMakeLists.txt +++ b/sdk/src/logs/CMakeLists.txt @@ -1,3 +1,3 @@ add_library(opentelemetry_logs logger_provider.cc logger.cc) -target_link_libraries(opentelemetry_logs opentelemetry_common) +target_link_libraries(opentelemetry_logs opentelemetry_common opentelemetry_trace) diff --git a/sdk/src/logs/logger.cc b/sdk/src/logs/logger.cc index bc19f5d1c1..c88a73de35 100644 --- a/sdk/src/logs/logger.cc +++ b/sdk/src/logs/logger.cc @@ -15,17 +15,25 @@ */ #include "opentelemetry/sdk/logs/logger.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/sdk/trace/span_data.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { namespace logs { -Logger::Logger(std::shared_ptr logger_provider) noexcept - : logger_provider_(logger_provider) +Logger::Logger(opentelemetry::nostd::string_view name, + std::shared_ptr logger_provider) noexcept + : logger_name_(name), logger_provider_(logger_provider) {} -void Logger::log(const opentelemetry::logs::LogRecord &record) noexcept +const opentelemetry::nostd::string_view Logger::GetName() noexcept +{ + return logger_name_; +} + +void Logger::Log(const opentelemetry::logs::LogRecord &record) noexcept { // If this logger does not have a processor, no need to create a log record auto processor = logger_provider_.lock()->GetProcessor(); @@ -36,20 +44,40 @@ void Logger::log(const opentelemetry::logs::LogRecord &record) noexcept // TODO: Sampler logic (should include check for minSeverity) - /** - * Convert the LogRecord to the heap first before sending to processor. - * TODO: Change the API log(LogRecord) function to log(*LogRecord) so the following line - * converting record a heap variable can be removed - */ + // Create a shared pointer to the LogRecord to be passed to the processor(s) auto record_pointer = std::unique_ptr(new opentelemetry::logs::LogRecord(record)); - // TODO: Do not want to overwrite user-set timestamp if there already is one - - // add a flag in the API to check if timestamp is set by user already before setting timestamp + // Inject values into record if not user specified + // Timestamp + if (record_pointer->timestamp == opentelemetry::core::SystemTimestamp(std::chrono::seconds(0))) + { + record_pointer->timestamp = core::SystemTimestamp(std::chrono::system_clock::now()); + } + + auto provider = opentelemetry::trace::Provider::GetTracerProvider(); + auto tracer = provider->GetTracer("foo_library"); + auto span_context = tracer->GetCurrentSpan()->GetContext(); + + // Traceid + if (!record_pointer->trace_id.IsValid()) + { + record_pointer->trace_id = span_context.trace_id(); + } + + // Spanid + if (!record_pointer->span_id.IsValid()) + { + record_pointer->span_id = span_context.span_id(); + } + + // Traceflag + if (!record_pointer->trace_flags.IsSampled()) + { + record_pointer->trace_flags = span_context.trace_flags(); + } - // Inject timestamp if none is set - record_pointer->timestamp = core::SystemTimestamp(std::chrono::system_clock::now()); - // TODO: inject traceid/spanid later + // TODO: Inject logger name into record // Send the log record to the processor processor->OnReceive(std::move(record_pointer)); diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index b040f9baab..697619ba56 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -22,7 +22,11 @@ namespace sdk namespace logs { -LoggerProvider::LoggerProvider() noexcept : processor_{nullptr} {} +LoggerProvider::LoggerProvider() noexcept + : processor_{nullptr}, + noop_logger_{ + nostd::shared_ptr(new opentelemetry::logs::NoopLogger)} +{} opentelemetry::nostd::shared_ptr LoggerProvider::GetLogger( opentelemetry::nostd::string_view name, @@ -39,22 +43,15 @@ opentelemetry::nostd::shared_ptr LoggerProvider::Ge } // Check if creating a new logger would exceed the max number of loggers - // TODO: Remove the noexcept from the API's and SDK's GetLogger(~) - /* - if (loggers_.size() > MAX_LOGGER_COUNT) + if (loggers_.size() >= OTEL_MAX_LOGGER_COUNT) { -#if __EXCEPTIONS - throw std::length_error("Number of loggers exceeds max count"); -#else - std::terminate(); -#endif + // Return a noop logger + return noop_logger_; } - */ // If no logger with that name exists yet, create it and add it to the map of loggers - opentelemetry::nostd::shared_ptr logger( - new Logger(this->shared_from_this())); + new Logger(name, this->shared_from_this())); loggers_[name.data()] = logger; return logger; } diff --git a/sdk/test/logs/BUILD b/sdk/test/logs/BUILD index b58eac0eee..ca09b3d070 100644 --- a/sdk/test/logs/BUILD +++ b/sdk/test/logs/BUILD @@ -1,7 +1,7 @@ cc_test( - name = "logger_provider_sdk_test", + name = "logger_provider_test", srcs = [ - "logger_provider_sdk_test.cc", + "logger_provider_test.cc", ], deps = [ "//api", @@ -11,12 +11,13 @@ cc_test( ) cc_test( - name = "logger_sdk_test", + name = "logger_test", srcs = [ - "logger_sdk_test.cc", + "logger_test.cc", ], deps = [ "//sdk/src/logs", + "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], ) diff --git a/sdk/test/logs/CMakeLists.txt b/sdk/test/logs/CMakeLists.txt index 87f7ae9a96..4bda950b00 100644 --- a/sdk/test/logs/CMakeLists.txt +++ b/sdk/test/logs/CMakeLists.txt @@ -1,4 +1,7 @@ -foreach(testname logger_provider_sdk_test logger_sdk_test) +foreach( + testname + logger_provider_test + logger_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_logs) diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_test.cc similarity index 75% rename from sdk/test/logs/logger_provider_sdk_test.cc rename to sdk/test/logs/logger_provider_test.cc index a2a020c838..29b4e87e06 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_test.cc @@ -23,7 +23,7 @@ using namespace opentelemetry::sdk::logs; -TEST(LoggerProviderSDK, PushToAPI) +TEST(LoggerProvider, PushToAPI) { auto lp = opentelemetry::nostd::shared_ptr( new opentelemetry::sdk::logs::LoggerProvider()); @@ -33,7 +33,7 @@ TEST(LoggerProviderSDK, PushToAPI) ASSERT_EQ(lp, opentelemetry::logs::Provider::GetLoggerProvider()); } -TEST(LoggerProviderSDK, LoggerProviderGetLoggerSimple) +TEST(LoggerProvider, LoggerProviderGetLoggerSimple) { auto lp = std::shared_ptr(new LoggerProvider()); @@ -52,7 +52,7 @@ TEST(LoggerProviderSDK, LoggerProviderGetLoggerSimple) ASSERT_EQ(logger1, logger3); } -TEST(LoggerProviderSDK, LoggerProviderLoggerArguments) +TEST(LoggerProvider, LoggerProviderLoggerArguments) { // Currently, arguments are not supported by the loggers. // TODO: Once the logging spec defines what arguments are allowed, add more @@ -69,12 +69,13 @@ TEST(LoggerProviderSDK, LoggerProviderLoggerArguments) class DummyProcessor : public LogProcessor { - void OnReceive(std::unique_ptr &&record) noexcept {} - void ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept {} - void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept {} + void OnReceive(std::unique_ptr &&record) noexcept + {} + bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept {} + bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept {} }; -TEST(LoggerProviderSDK, GetAndSetProcessor) +TEST(LoggerProvider, GetAndSetProcessor) { // Create a LoggerProvider without a processor LoggerProvider lp; @@ -85,3 +86,19 @@ TEST(LoggerProviderSDK, GetAndSetProcessor) lp.SetProcessor(proc2); ASSERT_EQ(proc2, lp.GetProcessor()); } + +TEST(LoggerProvider, LoggerLimit) +{ + auto lp = std::shared_ptr(new LoggerProvider()); + + // Create as many loggers as the logger provider allows + for (int i = 0; i < OTEL_MAX_LOGGER_COUNT; i++) + { + lp->GetLogger(std::to_string(i)); + } + + // Creating a new logger will return a noop logger + auto logger = lp->GetLogger("Another logger"); + opentelemetry::logs::NoopLogger nooplogger; + ASSERT_EQ(logger->GetName(), nooplogger.GetName()); +} diff --git a/sdk/test/logs/logger_sdk_test.cc b/sdk/test/logs/logger_sdk_test.cc deleted file mode 100644 index 6c36b68c0c..0000000000 --- a/sdk/test/logs/logger_sdk_test.cc +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "opentelemetry/sdk/logs/logger.h" - -#include - -using namespace opentelemetry::sdk::logs; - -TEST(LoggerSDK, LogToNullProcessor) -{ - // Confirm Logger::log() does not have undefined behavior - // even when there is no processor set - // since it calls Processor::OnReceive() - - auto lp = std::shared_ptr(new LoggerProvider()); - auto logger = lp->GetLogger("logger"); - - // Log a sample log record to a nullptr processor - opentelemetry::logs::LogRecord r; - r.name = "Test log"; - logger->log(r); -} - -class DummyProcessor : public LogProcessor -{ - void OnReceive(std::unique_ptr &&record) noexcept {} - void ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept {} - void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept {} -}; - -TEST(LoggerSDK, LogToAProcessor) -{ - // Create an API LoggerProvider and logger - auto api_lp = std::shared_ptr(new LoggerProvider()); - auto logger = api_lp->GetLogger("logger"); - - // Cast the API LoggerProvider to an SDK Logger Provider and assert that it is still the same - // LoggerProvider by checking that getting a logger with the same name as the previously defined - // logger is the same instance - auto lp = static_cast(api_lp.get()); - auto logger2 = lp->GetLogger("logger"); - ASSERT_EQ(logger, logger2); - - // Set a processor for the LoggerProvider - std::shared_ptr processor = std::shared_ptr(new DummyProcessor()); - lp->SetProcessor(processor); - ASSERT_EQ(processor, lp->GetProcessor()); - - // Should later introduce a way to assert that - // the logger's processor is the same as "proc" - // and that the logger's processor is the same as lp's processor - - // Log a sample log record to the processor - opentelemetry::logs::LogRecord r; - r.name = "Test log"; - logger->log(r); -} diff --git a/sdk/test/logs/logger_test.cc b/sdk/test/logs/logger_test.cc new file mode 100644 index 0000000000..bc65050c19 --- /dev/null +++ b/sdk/test/logs/logger_test.cc @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "opentelemetry/sdk/logs/logger.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/sdk/trace/simple_processor.h" + +#include + +using namespace opentelemetry::sdk::logs; +namespace sdktrace = opentelemetry::sdk::trace; + +TEST(Logger, LoggerName) +{ + auto lp = std::shared_ptr(new LoggerProvider()); + auto logger1 = lp->GetLogger("logger1"); + auto logger2 = lp->GetLogger("logger2"); + + ASSERT_EQ("logger1", logger1->GetName()); + ASSERT_EQ("logger2", logger2->GetName()); +} + +TEST(Logger, LogToNullProcessor) +{ + // Confirm Logger::log() does not have undefined behavior + // even when there is no processor set + // since it calls Processor::OnReceive() + + auto lp = std::shared_ptr(new LoggerProvider()); + auto logger = lp->GetLogger("logger"); + + // Log a sample log record to a nullptr processor + opentelemetry::logs::LogRecord r; + r.name = "Test log"; + logger->Log(r); +} + +class DummyProcessor : public LogProcessor +{ + void OnReceive(opentelemetry::nostd::shared_ptr record) noexcept + {} + bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept {} + bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept {} +}; + + +TEST(Logger, DefaultValueInjection) +{ + // TODO: once a Log Exporter is implemented, check that + // timestamp, traceid, spanid, and traceflags were + // injected from the span context properly +} +