Skip to content

Commit

Permalink
Add log level for internal log of sdk (#1147)
Browse files Browse the repository at this point in the history
  • Loading branch information
owent authored Jan 4, 2022
1 parent 4bffa63 commit baab88f
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 45 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Increment the:

## [Unreleased]

## [1.1.1] 2021-12-20
* [SDK] Add LogLevel to internal_log ([#1147](https:/open-telemetry/opentelemetry-cpp/pull/1147))

## [1.1.1] 2021-12-

* [SDK] Rename OTEL_CPP_GET_ATTR macro, and define it using fully qualified attr function ([#1140](https:/open-telemetry/opentelemetry-cpp/pull/1140))
* [SDK] Default resource attributes and attributes in OTEL_RESOURCE_ATTRIBUTES are missing when using Otlp*LogExporter ([#1082](https:/open-telemetry/opentelemetry-cpp/pull/1082))
Expand Down
24 changes: 13 additions & 11 deletions docs/public/sdk/GettingStarted.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,27 +195,29 @@ and it can be changed at compile time.

.. code:: cpp
OTEL_INTERNAL_LOG_ERROR
(" Connection failed. Error string " << error_str << " Error Num: " << errorno);
OTEL_INTERNAL_LOG_ERROR
(" Connection failed." , {{"error message: " : error_str},{"error number": errorno}});
OTEL_INTERNAL_LOG_DEBUG
(" Connection Established Successfully. Headers:", {{"url", url},{"content-length", len}, {"content-type", type}});
OTEL_INTERNAL_LOG_ERROR(" Connection failed. Error string " << error_str << " Error Num: " << errorno);
opentelemetry::sdk::common::AttributeMap error_attributes = {
{"url", url}, {"content-length", len}, {"content-type", type}};
OTEL_INTERNAL_LOG_ERROR(" Connection failed." , error_attributes);
opentelemetry::sdk::common::AttributeMap http_attributes = {
{"url", url}, {"content-length", len}, {"content-type", type}};
OTEL_INTERNAL_LOG_DEBUG(" Connection Established Successfully. Headers:", http_attributes);
The custom log handler can be defined by inheriting from `sdk::common::internal_log::LogHandler` class.
The custom log handler can be defined by inheriting from `opentelemetry::sdk::common::internal_log::LogHandler` class.

.. code:: cpp
class CustomLogHandler : public sdk::common::internal_log::LogHandler
class CustomLogHandler : public opentelemetry::sdk::common::internal_log::LogHandler
{
void Handle(Loglevel level,
void Handle(opentelemetry::sdk::common::internal_log::LogLevel level,
const char \*file,
int line,
const char \*msg,
const sdk::common::AttributeMap &attributes)
const opentelemetry::sdk::common::AttributeMap &attributes) noexcept override
{
// add implementation here
}
};
sdk::common::internal_log::GlobalLogHandler::SetLogHandler(CustomLogHandler());
opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogHandler(CustomLogHandler());
opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogLevel(opentelemetry::sdk::common::internal_log::LogLevel::Debug);
96 changes: 66 additions & 30 deletions sdk/include/opentelemetry/sdk/common/global_log_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <iostream>
#include <sstream>
#include <utility>

#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/sdk/common/attribute_utils.h"
Expand All @@ -13,10 +14,10 @@
#define OTEL_INTERNAL_LOG_LEVEL_ERROR 0
#define OTEL_INTERNAL_LOG_LEVEL_WARN 1
#define OTEL_INTERNAL_LOG_LEVEL_INFO 2
#define OTEL_INTERNAL_LOG_LEVEL_DEBUG 3 // to be disabled in release

#define OTEL_INTERNAL_LOG_LEVEL_DEBUG 3
#ifndef OTEL_INTERNAL_LOG_LEVEL
# define OTEL_INTERNAL_LOG_LEVEL OTEL_INTERNAL_LOG_LEVEL_WARN // ERROR and WARN
// DEBUG by default, we can change log level on runtime
# define OTEL_INTERNAL_LOG_LEVEL OTEL_INTERNAL_LOG_LEVEL_DEBUG
#endif

OPENTELEMETRY_BEGIN_NAMESPACE
Expand Down Expand Up @@ -54,6 +55,8 @@ inline std::string LevelToString(LogLevel level)
class LogHandler
{
public:
virtual ~LogHandler() = default;

virtual void Handle(LogLevel level,
const char *file,
int line,
Expand Down Expand Up @@ -108,26 +111,43 @@ class GlobalLogHandler
/**
* Returns the singleton LogHandler.
*
* By default, a default LogHandler is returned. This will never return a
* nullptr LogHandler.
* By default, a default LogHandler is returned.
*/
static nostd::shared_ptr<LogHandler> GetLogHandler() noexcept
static const nostd::shared_ptr<LogHandler> &GetLogHandler() noexcept
{
return nostd::shared_ptr<LogHandler>(GetHandler());
return GetHandlerAndLevel().first;
}

/**
* Changes the singleton LogHandler.
* This should be called once at the start of application before creating TracerProvider
* This should be called once at the start of application before creating any Provider
* instance.
*/
static void SetLogHandler(nostd::shared_ptr<LogHandler> eh) noexcept { GetHandler() = eh; }
static void SetLogHandler(nostd::shared_ptr<LogHandler> eh) noexcept
{
GetHandlerAndLevel().first = eh;
}

/**
* Returns the singleton log level.
*
* By default, a default log level is returned.
*/
static LogLevel GetLogLevel() noexcept { return GetHandlerAndLevel().second; }

/**
* Changes the singleton Log level.
* This should be called once at the start of application before creating any Provider
* instance.
*/
static void SetLogLevel(LogLevel level) noexcept { GetHandlerAndLevel().second = level; }

private:
static nostd::shared_ptr<LogHandler> &GetHandler() noexcept
static std::pair<nostd::shared_ptr<LogHandler>, LogLevel> &GetHandlerAndLevel() noexcept
{
static nostd::shared_ptr<LogHandler> handler(new DefaultLogHandler);
return handler;
static std::pair<nostd::shared_ptr<LogHandler>, LogLevel> handler_and_level{
nostd::shared_ptr<LogHandler>(new DefaultLogHandler), LogLevel::Warning};
return handler_and_level;
}
};

Expand All @@ -136,15 +156,31 @@ class GlobalLogHandler
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE

#define OTEL_INTERNAL_LOG_DISPATCH(level, message, attributes) \
do \
{ \
using namespace opentelemetry::sdk::common::internal_log; \
std::stringstream tmp_stream; \
tmp_stream << message; \
GlobalLogHandler::GetLogHandler()->Handle(level, __FILE__, __LINE__, tmp_stream.str().c_str(), \
attributes); \
} while (0)
/**
* We can not decide the destroying order of signaltons.
* Which means, the destructors of other singletons (GlobalLogHandler,TracerProvider and etc.)
* may be called after destroying of global LogHandler and use OTEL_INTERNAL_LOG_* in it.We can do
* nothing but ignore the log in this situation.
*/
#define OTEL_INTERNAL_LOG_DISPATCH(level, message, attributes) \
do \
{ \
using opentelemetry::sdk::common::internal_log::GlobalLogHandler; \
using opentelemetry::sdk::common::internal_log::LogHandler; \
if (level > GlobalLogHandler::GetLogLevel()) \
{ \
break; \
} \
const opentelemetry::nostd::shared_ptr<LogHandler> &log_handler = \
GlobalLogHandler::GetLogHandler(); \
if (!log_handler) \
{ \
break; \
} \
std::stringstream tmp_stream; \
tmp_stream << message; \
log_handler->Handle(level, __FILE__, __LINE__, tmp_stream.str().c_str(), attributes); \
} while (false);

#define OTEL_INTERNAL_LOG_GET_3RD_ARG(arg1, arg2, arg3, ...) arg3

Expand Down Expand Up @@ -182,9 +218,9 @@ OPENTELEMETRY_END_NAMESPACE
# define OTEL_INTERNAL_LOG_DEBUG_1_ARGS(message) \
OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Debug, message, \
{})
# define OTEL_INTERNAL_LOG_DEBUG_2_ARGS(message, attributes) \
OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_logg::LogLevel::Debug, \
message, attributes)
# define OTEL_INTERNAL_LOG_DEBUG_2_ARGS(message, attributes) \
OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Debug, message, \
attributes)
# define OTEL_INTERNAL_LOG_DEBUG_MACRO(...) \
OTEL_INTERNAL_LOG_GET_3RD_ARG(__VA_ARGS__, OTEL_INTERNAL_LOG_DEBUG_2_ARGS, \
OTEL_INTERNAL_LOG_DEBUG_1_ARGS)
Expand All @@ -194,12 +230,12 @@ OPENTELEMETRY_END_NAMESPACE
#endif

#if OTEL_INTERNAL_LOG_LEVEL >= OTEL_INTERNAL_LOG_LEVEL_INFO
# define OTEL_INTERNAL_LOG_INFO_1_ARGS(message) \
OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_logger::LogLevel::Info, \
message, {})
# define OTEL_INTERNAL_LOG_INFO_2_ARGS(message, attributes) \
OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_logger::LogLevel::Info, \
message, attributes)
# define OTEL_INTERNAL_LOG_INFO_1_ARGS(message) \
OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Info, message, \
{})
# define OTEL_INTERNAL_LOG_INFO_2_ARGS(message, attributes) \
OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Info, message, \
attributes)
# define OTEL_INTERNAL_LOG_INFO_MACRO(...) \
OTEL_INTERNAL_LOG_GET_3RD_ARG(__VA_ARGS__, OTEL_INTERNAL_LOG_ERROR_2_ARGS, \
OTEL_INTERNAL_LOG_ERROR_1_ARGS)
Expand Down
13 changes: 13 additions & 0 deletions sdk/test/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,16 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "global_log_handle_test",
srcs = [
"global_log_handle_test.cc",
],
tags = ["test"],
deps = [
"//api",
"//sdk:headers",
"@com_google_googletest//:gtest_main",
],
)
12 changes: 9 additions & 3 deletions sdk/test/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
foreach(testname
random_test fast_random_number_generator_test atomic_unique_ptr_test
circular_buffer_range_test circular_buffer_test attribute_utils_test)
foreach(
testname
random_test
fast_random_number_generator_test
atomic_unique_ptr_test
circular_buffer_range_test
circular_buffer_test
attribute_utils_test
global_log_handle_test)

add_executable(${testname} "${testname}.cc")
target_link_libraries(
Expand Down
57 changes: 57 additions & 0 deletions sdk/test/common/global_log_handle_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/sdk/common/global_log_handler.h"

#include <gtest/gtest.h>

#include <cstring>

class CustomLogHandler : public opentelemetry::sdk::common::internal_log::LogHandler
{
public:
void Handle(opentelemetry::sdk::common::internal_log::LogLevel level,
const char *,
int,
const char *msg,
const opentelemetry::sdk::common::AttributeMap &) noexcept override
{
if (level == opentelemetry::sdk::common::internal_log::LogLevel::Debug)
{
EXPECT_EQ(0, strncmp(msg, "Debug message", 13));
}
else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Error)
{
EXPECT_EQ(0, strncmp(msg, "Error message", 13));
}
++count;
}

size_t count = 0;
};

TEST(GlobalLogHandleTest, CustomLogHandler)
{
using opentelemetry::sdk::common::internal_log::LogHandler;
auto backup_log_handle =
opentelemetry::sdk::common::internal_log::GlobalLogHandler::GetLogHandler();
auto backup_log_level = opentelemetry::sdk::common::internal_log::GlobalLogHandler::GetLogLevel();

auto custom_log_handler = opentelemetry::nostd::shared_ptr<LogHandler>(new CustomLogHandler{});
opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogHandler(custom_log_handler);
auto before_count = static_cast<CustomLogHandler *>(custom_log_handler.get())->count;
opentelemetry::sdk::common::AttributeMap attributes = {
{"url", "https://opentelemetry.io/"}, {"content-length", 0}, {"content-type", "text/html"}};
OTEL_INTERNAL_LOG_ERROR("Error message");
OTEL_INTERNAL_LOG_DEBUG("Debug message. Headers:", attributes);
EXPECT_EQ(before_count + 1, static_cast<CustomLogHandler *>(custom_log_handler.get())->count);

opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogLevel(
opentelemetry::sdk::common::internal_log::LogLevel::Debug);
OTEL_INTERNAL_LOG_ERROR("Error message");
OTEL_INTERNAL_LOG_DEBUG("Debug message. Headers:", attributes);
EXPECT_EQ(before_count + 3, static_cast<CustomLogHandler *>(custom_log_handler.get())->count);

opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogHandler(backup_log_handle);
opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogLevel(backup_log_level);
}

0 comments on commit baab88f

Please sign in to comment.