Skip to content

Commit

Permalink
Add logger builder utility
Browse files Browse the repository at this point in the history
  • Loading branch information
albin-johansson committed Oct 25, 2023
1 parent de6f90a commit 153d70a
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 34 deletions.
3 changes: 2 additions & 1 deletion modules/core/inc/tactile/core/debug/log/logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <fmt/core.h>

#include "tactile/core/api.hpp"
#include "tactile/core/container/smart_ptr.hpp"
#include "tactile/core/container/string.hpp"
#include "tactile/core/container/vector.hpp"
#include "tactile/core/debug/log/log_level.hpp"
Expand Down Expand Up @@ -115,7 +116,7 @@ class TACTILE_CORE_API Logger final {
private:
LogLevel mMinLevel {LogLevel::kInfo};
LogLevel mFlushLevel {LogLevel::kError};
Vector<ILoggerSink*> mSinks;
Vector<Managed<ILoggerSink>> mSinks;
Maybe<SteadyClockInstant> mReferenceInstant;

[[nodiscard]]
Expand Down
85 changes: 85 additions & 0 deletions modules/core/inc/tactile/core/debug/log/logger_builder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (C) 2023 Albin Johansson (GNU General Public License v3.0)

#pragma once

#include "tactile/core/api.hpp"
#include "tactile/core/debug/log/log_level.hpp"
#include "tactile/core/debug/log/logger.hpp"
#include "tactile/core/functional/maybe.hpp"
#include "tactile/core/io/filesystem.hpp"
#include "tactile/core/prelude.hpp"

namespace tactile {

/**
* \brief Builder class for constructing `Logger` instances.
*/
class TACTILE_CORE_API LoggerBuilder final {
public:
using Self = LoggerBuilder;

/**
* \brief Sets the initial minimum log level of log messages.
*
* \param level the minimum log level.
*
* \return the builder instance.
*/
auto min_level(LogLevel level) -> Self&;

/**
* \brief Sets the minimum level of messages that would trigger a flush.
*
* \param level the minimum flush log level.
*
* \return the builder instance.
*/
auto flush_on(LogLevel level) -> Self&;

/**
* \brief Uses the time of the logger initialization as the reference timepoint.
*
* \return the builder instance.
*/
auto use_initialization_time_as_reference_instant() -> Self&;

/**
* \brief Enables colored terminal output.
*
* \note This function only has an effect if the terminal sink is included.
*
* \return the builder instance.
*/
auto use_colored_terminal_output() -> Self&;

/**
* \brief Includes a terminal sink with the logger.
*
* \return the builder instance.
*/
auto with_terminal_sink() -> Self&;

/**
* \brief Includes a log file sink with the logger.
*
* \return the builder instance.
*/
auto with_file_sink(FilePath file_path) -> Self&;

/**
* \brief Constructs the described logger.
*
* \return a logger instance.
*/
auto build() -> Logger;

private:
LogLevel mMinLevel {LogLevel::kTrace};
LogLevel mFlushLevel {LogLevel::kError};
Maybe<FilePath> mLogFilePath;
bool mUseStartupTimeAsReferenceInstant : 1 {};
bool mUseTerminalSink : 1 {};
bool mUseColoredTerminalOutput : 1 {};
};

} // namespace tactile
12 changes: 6 additions & 6 deletions modules/core/src/tactile/core/debug/log/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
namespace tactile {
namespace {

constinit Logger* gLogger = nullptr;
constinit Logger* gDefaultLogger = nullptr;

} // namespace

Expand Down Expand Up @@ -44,7 +44,7 @@ void Logger::log(const LogLevel level,

const auto will_flush = would_flush(level);

for (auto* sink : mSinks) {
for (const Managed<ILoggerSink>& sink : mSinks) {
sink->log(msg);

if (will_flush) {
Expand All @@ -71,10 +71,10 @@ void Logger::flush_on(const LogLevel level) noexcept
mFlushLevel = level;
}

void Logger::add_sink(ILoggerSink* sink)
void Logger::add_sink(Managed<ILoggerSink> sink)
{
if (sink) {
mSinks.push_back(sink);
mSinks.push_back(std::move(sink));
}
}

Expand Down Expand Up @@ -129,12 +129,12 @@ auto Logger::_to_elapsed_time(const SteadyClockInstant instant) const -> Microse

void set_default_logger(Logger* logger) noexcept
{
gLogger = logger;
gDefaultLogger = logger;
}

auto get_default_logger() noexcept -> Logger*
{
return gLogger;
return gDefaultLogger;
}

} // namespace tactile
2 changes: 1 addition & 1 deletion modules/core/src/tactile/core/debug/profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ScopeProfiler::~ScopeProfiler() noexcept
try {
const auto end = SteadyClock::now();
const auto duration = duration_cast<Microseconds>(end - mStartInstant);
TACTILE_LOG_DEBUG("[PROFILER] Scope '{}' took {}", mDescription, duration);
TACTILE_LOG_DEBUG("Scope '{}' took {}", mDescription, duration);
}
catch (const std::exception& ex) {
TACTILE_LOG_ERROR("Scope profiler destructor threw unexpected exception: {}",
Expand Down
19 changes: 9 additions & 10 deletions modules/core/test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,22 @@

#include <gtest/gtest.h>

#include "tactile/core/debug/log/logger.hpp"
#include "tactile/core/debug/log/terminal_logger_sink.hpp"
#include "tactile/core/debug/log/logger_builder.hpp"
#include "tactile/core/math/rng.hpp"
#include "tactile/core/misc/scope_guard.hpp"

using namespace tactile;

auto main(int argc, char* argv[]) -> int
{
Logger logger;
logger.set_reference_instant(SteadyClock::now());
logger.set_min_level(LogLevel::kTrace);
logger.flush_on(LogLevel::kError);

TerminalLoggerSink terminal_logger_sink;
terminal_logger_sink.use_ansi_colors(true);
logger.add_sink(&terminal_logger_sink);
auto logger = LoggerBuilder {}
.use_initialization_time_as_reference_instant()
.min_level(LogLevel::kDebug)
.flush_on(LogLevel::kError)
.with_file_sink("core_test_log.txt")
.with_terminal_sink()
.use_colored_terminal_output()
.build();

set_default_logger(&logger);
const ScopeGuard logger_guard {[] { set_default_logger(nullptr); }};
Expand Down
17 changes: 17 additions & 0 deletions modules/editor/test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@

#include <gtest/gtest.h>

#include "tactile/core/debug/log/logger_builder.hpp"
#include "tactile/core/misc/scope_guard.hpp"

using namespace tactile;

auto main(int argc, char* argv[]) -> int
{
auto logger = LoggerBuilder {}
.use_initialization_time_as_reference_instant()
.min_level(LogLevel::kDebug)
.flush_on(LogLevel::kError)
.with_file_sink("editor_test_log.txt")
.with_terminal_sink()
.use_colored_terminal_output()
.build();

set_default_logger(&logger);
const ScopeGuard logger_guard {[] { set_default_logger(nullptr); }};

testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
26 changes: 10 additions & 16 deletions modules/main/src/tactile/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
#include <exception> // exception, set_terminate
#include <filesystem> // current_path, create_directories

#include "tactile/core/debug/log/file_logger_sink.hpp"
#include "tactile/core/debug/log/logger.hpp"
#include "tactile/core/debug/log/terminal_logger_sink.hpp"
#include "tactile/core/debug/log/logger_builder.hpp"
#include "tactile/core/debug/terminate_handler.hpp"
#include "tactile/core/io/save/save_format_manager.hpp"
#include "tactile/core/misc/scope_guard.hpp"
Expand All @@ -30,19 +28,18 @@ auto main(const int argc, char* argv[]) -> int

const auto log_dir = app_dir / "logs"; // FIXME
std::filesystem::create_directories(log_dir);
tactile::FileLoggerSink file_sink {log_dir / "log.txt"};

tactile::TerminalLoggerSink console_sink;
console_sink.use_ansi_colors(true);
auto logger = tactile::LoggerBuilder {}
.use_initialization_time_as_reference_instant()
.min_level(tactile::LogLevel::kTrace)
.flush_on(tactile::LogLevel::kError)
.with_file_sink(log_dir / "log.txt")
.with_terminal_sink()
.use_colored_terminal_output()
.build();

tactile::Logger logger;
const tactile::ScopeGuard logger_guard {[] { tactile::set_default_logger(nullptr); }};

logger.set_reference_instant(startup_instant);
logger.set_min_level(tactile::LogLevel::kTrace);
logger.add_sink(&file_sink);
logger.add_sink(&console_sink);

tactile::set_default_logger(&logger);

TACTILE_LOG_DEBUG("Initialized logger");
Expand All @@ -58,16 +55,13 @@ auto main(const int argc, char* argv[]) -> int
}
catch (const tactile::Error& err) {
TACTILE_LOG_FATAL("Unhandled exception: {}\n{}", err.what(), err.get_trace());
return EXIT_FAILURE;
}
catch (const std::exception& ex) {
TACTILE_LOG_FATAL("Unhandled exception: {}", ex.what());
return EXIT_FAILURE;
}
catch (...) {
TACTILE_LOG_FATAL("Unhandled exception");
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
return EXIT_FAILURE;
}
17 changes: 17 additions & 0 deletions modules/tmj-format/test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@

#include <gtest/gtest.h>

#include "tactile/core/debug/log/logger_builder.hpp"
#include "tactile/core/misc/scope_guard.hpp"

using namespace tactile;

auto main(int argc, char* argv[]) -> int
{
auto logger = LoggerBuilder {}
.use_initialization_time_as_reference_instant()
.min_level(LogLevel::kDebug)
.flush_on(LogLevel::kError)
.with_file_sink("tmj_format_test_log.txt")
.with_terminal_sink()
.use_colored_terminal_output()
.build();

set_default_logger(&logger);
const ScopeGuard logger_guard {[] { set_default_logger(nullptr); }};

testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

0 comments on commit 153d70a

Please sign in to comment.