Skip to content

Commit

Permalink
Merge branch 'main' into 3118-devcontainer
Browse files Browse the repository at this point in the history
  • Loading branch information
marcalff authored Jan 15, 2025
2 parents 627a357 + 95baed7 commit 5f5909b
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 35 deletions.
52 changes: 21 additions & 31 deletions sdk/include/opentelemetry/sdk/common/global_log_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,37 +99,28 @@ class GlobalLogHandler
*
* By default, a default LogHandler is returned.
*/
static inline const nostd::shared_ptr<LogHandler> &GetLogHandler() noexcept
{
return GetHandlerAndLevel().first;
}
static nostd::shared_ptr<LogHandler> GetLogHandler() noexcept;

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

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

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

private:
static std::pair<nostd::shared_ptr<LogHandler>, LogLevel> &GetHandlerAndLevel() noexcept;
static void SetLogLevel(LogLevel level) noexcept;
};

} // namespace internal_log
Expand All @@ -142,24 +133,23 @@ OPENTELEMETRY_END_NAMESPACE
* To ensure that GlobalLogHandler is the first one to be initialized (and so last to be
* destroyed), it is first used inside the constructors of TraceProvider, MeterProvider
* and LoggerProvider for debug logging. */
#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); \
#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; \
} \
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
72 changes: 68 additions & 4 deletions sdk/src/common/global_log_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,38 @@ namespace common
namespace internal_log
{

namespace
{
struct GlobalLogHandlerData
{
nostd::shared_ptr<LogHandler> handler;
LogLevel log_level;

GlobalLogHandlerData()
: handler(nostd::shared_ptr<LogHandler>(new DefaultLogHandler)), log_level(LogLevel::Warning)
{}
~GlobalLogHandlerData() { is_singleton_destroyed = true; }

GlobalLogHandlerData(const GlobalLogHandlerData &) = delete;
GlobalLogHandlerData(GlobalLogHandlerData &&) = delete;

GlobalLogHandlerData &operator=(const GlobalLogHandlerData &) = delete;
GlobalLogHandlerData &operator=(GlobalLogHandlerData &&) = delete;

static GlobalLogHandlerData &Instance() noexcept;
static bool is_singleton_destroyed;
};

bool GlobalLogHandlerData::is_singleton_destroyed = false;

GlobalLogHandlerData &GlobalLogHandlerData::Instance() noexcept
{
static GlobalLogHandlerData instance;
return instance;
}

} // namespace

LogHandler::~LogHandler() {}

void DefaultLogHandler::Handle(LogLevel level,
Expand Down Expand Up @@ -57,11 +89,43 @@ void NoopLogHandler::Handle(LogLevel,
const sdk::common::AttributeMap &) noexcept
{}

std::pair<nostd::shared_ptr<LogHandler>, LogLevel> &GlobalLogHandler::GetHandlerAndLevel() noexcept
nostd::shared_ptr<LogHandler> GlobalLogHandler::GetLogHandler() noexcept
{
if OPENTELEMETRY_UNLIKELY_CONDITION (GlobalLogHandlerData::is_singleton_destroyed)
{
return nostd::shared_ptr<LogHandler>();
}

return GlobalLogHandlerData::Instance().handler;
}

void GlobalLogHandler::SetLogHandler(const nostd::shared_ptr<LogHandler> &eh) noexcept
{
if OPENTELEMETRY_UNLIKELY_CONDITION (GlobalLogHandlerData::is_singleton_destroyed)
{
return;
}

GlobalLogHandlerData::Instance().handler = eh;
}

LogLevel GlobalLogHandler::GetLogLevel() noexcept
{
static std::pair<nostd::shared_ptr<LogHandler>, LogLevel> handler_and_level{
nostd::shared_ptr<LogHandler>(new DefaultLogHandler), LogLevel::Warning};
return handler_and_level;
if OPENTELEMETRY_UNLIKELY_CONDITION (GlobalLogHandlerData::is_singleton_destroyed)
{
return LogLevel::None;
}

return GlobalLogHandlerData::Instance().log_level;
}

void GlobalLogHandler::SetLogLevel(LogLevel level) noexcept
{
if OPENTELEMETRY_UNLIKELY_CONDITION (GlobalLogHandlerData::is_singleton_destroyed)
{
return;
}
GlobalLogHandlerData::Instance().log_level = level;
}

} // namespace internal_log
Expand Down
14 changes: 14 additions & 0 deletions sdk/test/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,20 @@ cc_test(
],
)

cc_test(
name = "global_log_handle_singleton_lifetime_test",
srcs = [
"global_log_handle_singleton_lifetime_test.cc",
],
tags = ["test"],
deps = [
"//api",
"//sdk:headers",
"//sdk/src/common:global_log_handler",
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "attributemap_hash_test",
srcs = [
Expand Down
1 change: 1 addition & 0 deletions sdk/test/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ foreach(
attribute_utils_test
attributemap_hash_test
global_log_handle_test
global_log_handle_singleton_lifetime_test
env_var_test)

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

#include <gtest/gtest.h>
#include <cstdlib>
#include <cstring>
#include <iostream>

#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/sdk/common/attribute_utils.h"
#include "opentelemetry/sdk/common/global_log_handler.h"

class GlobalLogHandlerChecker
{
public:
GlobalLogHandlerChecker() {}
~GlobalLogHandlerChecker()
{
using opentelemetry::sdk::common::internal_log::GlobalLogHandler;
auto handle = GlobalLogHandler::GetLogHandler();
if (handle && custom_handler_destroyed)
{
OTEL_INTERNAL_LOG_ERROR("GlobalLogHandler should be destroyed here");
abort();
}
std::cout << "GlobalLogHandlerChecker destroyed and check pass.\n";
}

void Print() { std::cout << "GlobalLogHandlerChecker constructed\n"; }

GlobalLogHandlerChecker(const GlobalLogHandlerChecker &) = delete;
GlobalLogHandlerChecker(GlobalLogHandlerChecker &&) = delete;
GlobalLogHandlerChecker &operator=(const GlobalLogHandlerChecker &) = delete;
GlobalLogHandlerChecker &operator=(GlobalLogHandlerChecker &&) = delete;

static bool custom_handler_destroyed;
};
bool GlobalLogHandlerChecker::custom_handler_destroyed = false;

namespace
{
static GlobalLogHandlerChecker &ConstructChecker()
{
static GlobalLogHandlerChecker checker;
return checker;
}
} // namespace

class CustomLogHandler : public opentelemetry::sdk::common::internal_log::LogHandler
{
public:
~CustomLogHandler() override
{
GlobalLogHandlerChecker::custom_handler_destroyed = true;
std::cout << "Custom Gobal Log Handle destroyed\n";
}

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)
{
std::cout << "Custom Gobal Log Handle[Debug]: " << msg << "\n";
}
else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Error)
{
std::cout << "Custom Gobal Log Handle[Error]: " << msg << "\n";
}
else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Info)
{
std::cout << "Custom Gobal Log Handle[Info]: " << msg << "\n";
}
else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Warning)
{
std::cout << "Custom Gobal Log Handle[Warning]: " << msg << "\n";
}
++count;
}

size_t count = 0;
};

TEST(GlobalLogHandleSingletonTest, Lifetime)
{
// Setup a new static variable which will be destroyed after the global handle
ConstructChecker().Print();

using opentelemetry::sdk::common::internal_log::GlobalLogHandler;
using opentelemetry::sdk::common::internal_log::LogHandler;

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);

{
auto handle = GlobalLogHandler::GetLogHandler();
EXPECT_TRUE(!!handle);
}
}

0 comments on commit 5f5909b

Please sign in to comment.