Skip to content

Commit

Permalink
Add console_log and file_log classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjhoward committed Sep 21, 2024
1 parent 32e6b36 commit 1a1870f
Show file tree
Hide file tree
Showing 13 changed files with 360 additions and 197 deletions.
28 changes: 19 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,17 @@ file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS
EXCLUDE_DIR "${PROJECT_SOURCE_DIR}/src/game/platform"
)

# Collect platform-independent header files
file(GLOB_RECURSE HEADER_FILES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/src/*.hpp
EXCLUDE_DIR "${PROJECT_SOURCE_DIR}/src/game/platform"
)

# Collect module files
# file(GLOB_RECURSE MODULE_FILES CONFIGURE_DEPENDS
# ${PROJECT_SOURCE_DIR}/src/*.ixx
# ${PROJECT_SOURCE_DIR}/src/*.cxx
# )
#file(GLOB_RECURSE MODULE_FILES CONFIGURE_DEPENDS
# ${PROJECT_SOURCE_DIR}/src/*.ixx
# ${PROJECT_SOURCE_DIR}/src/*.cxx
#)

if(CMAKE_SYSTEM_NAME MATCHES "Windows")

Expand All @@ -310,17 +316,18 @@ if(CMAKE_SYSTEM_NAME MATCHES "Windows")

endif()

source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCE_FILES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCE_FILES} ${HEADER_FILES} ${MODULE_FILES})

# Add executable target
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})

# Set executable module files
# target_sources(${PROJECT_NAME}
# PUBLIC
# FILE_SET CXX_MODULES FILES ${MODULE_FILES}
# )
target_sources(${PROJECT_NAME}
PUBLIC
FILE_SET HEADERS FILES ${HEADER_FILES}
#FILE_SET CXX_MODULES FILES ${MODULE_FILES}
)

# Set target properties
set_target_properties(${PROJECT_NAME}
Expand Down Expand Up @@ -373,6 +380,9 @@ target_compile_options(${PROJECT_NAME}
# Disable RTTI
/GR-

# Enable experimental modules
#/experimental:module

# Set Debug configuration options
$<$<CONFIG:Debug>:
/ZI # Enable Edit and Continue
Expand Down
118 changes: 118 additions & 0 deletions src/engine/debug/console-log.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// SPDX-FileCopyrightText: 2023 C. J. Howard
// SPDX-License-Identifier: GPL-3.0-or-later

#include <engine/debug/console-log.hpp>
#include <engine/debug/log.hpp>
#include <engine/debug/logger.hpp>
#include <engine/debug/contract.hpp>
#include <algorithm>
#include <filesystem>
#include <format>
#include <iostream>
#include <syncstream>

#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

namespace
{
/// Maps log message severity to ANSI color codes.
const char* console_log_colors[] =
{
"\33[37m", // trace: FG_WHITE
"\33[34;1m", // debug: FG_BRIGHT_BLUE
"\33[32;1m", // info: FG_BRIGHT_GREEN
"\33[33m", // warning: FG_YELLOW
"\33[31m", // error: FG_RED
"\33[37;\33[41;1m" // fatal: FG_WHITE, BG_BRIGHT_RED
};

/// ANSI color reset code.
const char* ansi_reset = "\33[0m";

#if defined(_WIN32)

/// Enables UTF-8 output.
void enable_utf8()
{
SetConsoleOutputCP(CP_UTF8);
}

/// Enables VT100 virtual terminal sequences.
void enable_vt100()
{
DWORD mode = 0;
HANDLE std_output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(std_output_handle, &mode);
SetConsoleMode(std_output_handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
}

/// Disables VT100 virtual terminal sequences.
void disable_vt100()
{
DWORD mode = 0;
HANDLE std_output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(std_output_handle, &mode);
SetConsoleMode(std_output_handle, mode & (~ENABLE_VIRTUAL_TERMINAL_PROCESSING));
}

#endif
}

namespace debug {

console_log::console_log()
{
// Get current time zone
m_time_zone = std::chrono::current_zone();

// Subscribe to log messages from default logger
m_message_logged_subscription = default_logger().message_logged_channel().subscribe
(
[this](const auto& event)
{
this->message_logged(event);
}
);

// Enable UTF-8 output and VT100 sequences on Windows
#if defined(_WIN32)
enable_utf8();
enable_vt100();
#endif

debug::postcondition(m_time_zone);
}

console_log::~console_log()
{}

void console_log::message_logged(const message_logged_event& event)
{
debug::precondition(m_time_zone);

// Clamp severity index to valid range
const auto severity_index = std::to_underlying(std::clamp(event.severity, log_message_severity::trace, log_message_severity::fatal));

// Round time to the millisecond and convert to local time zone
const std::chrono::zoned_time zoned_time{m_time_zone, std::chrono::floor<std::chrono::milliseconds>(event.time)};

// Select and synchronize output stream based on severity
std::osyncstream output_stream(event.severity >= log_message_severity::error ? std::cerr : std::cout);

// Format and output log message
output_stream << std::format
(
"[{:%T}] {}{:7}: {}:{}: {}\33[0m\n",
zoned_time,
console_log_colors[severity_index],
log_message_severity_to_string(event.severity),
std::filesystem::path(event.location.file_name()).filename().string(),
event.location.line(),
event.message
);
}

} // namespace debug
49 changes: 49 additions & 0 deletions src/engine/debug/console-log.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: 2023 C. J. Howard
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef ANTKEEPER_DEBUG_CONSOLE_LOG_HPP
#define ANTKEEPER_DEBUG_CONSOLE_LOG_HPP

#include <engine/debug/log-events.hpp>
#include <engine/event/subscription.hpp>
#include <chrono>
#include <memory>

namespace debug {

/// @name Logging
/// @{

/**
* Logs messages to the console.
*/
class console_log
{
public:
/**
* Opens a console log.
*
* @exception std::runtime_error Failed to get current time zone.
*/
console_log();

/// Closes a console log.
~console_log();

private:
void message_logged(const message_logged_event& event);

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

const std::chrono::time_zone* m_time_zone{};
std::shared_ptr<event::subscription> m_message_logged_subscription;
};

/// @}

} // namespace debug

#endif // ANTKEEPER_DEBUG_CONSOLE_LOG_HPP
42 changes: 0 additions & 42 deletions src/engine/debug/console.cpp

This file was deleted.

26 changes: 0 additions & 26 deletions src/engine/debug/console.hpp

This file was deleted.

69 changes: 69 additions & 0 deletions src/engine/debug/file-log.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-FileCopyrightText: 2023 C. J. Howard
// SPDX-License-Identifier: GPL-3.0-or-later

#include <engine/debug/file-log.hpp>
#include <engine/debug/logger.hpp>
#include <engine/debug/contract.hpp>
#include <algorithm>
#include <filesystem>
#include <format>
#include <syncstream>
#include <stdexcept>

namespace debug {

file_log::file_log(const std::filesystem::path& path)
{
// Open log file
m_output_stream.open(path.string());
if (!m_output_stream.is_open())
{
throw std::runtime_error(std::format("Failed to open log file \"{}\"", path.string()));
}

// Write log file header
m_output_stream << "time\tseverity\tfile\tline\tthread\tmessage";
if (!m_output_stream.good())
{
throw std::runtime_error(std::format("Failed to write to log file \"{}\"", path.string()));
}

// Get current time zone
m_time_zone = std::chrono::current_zone();

// Subscribe to log messages from default logger
m_message_logged_subscription = default_logger().message_logged_channel().subscribe
(
[this](const auto& event)
{
this->message_logged(event);
}
);

debug::postcondition(m_time_zone);
}

file_log::~file_log()
{}

void file_log::message_logged(const message_logged_event& event)
{
debug::precondition(m_time_zone);

// Round time to the millisecond and convert to local time zone
const std::chrono::zoned_time zoned_time{m_time_zone, std::chrono::floor<std::chrono::milliseconds>(event.time)};

// Format and output log message
std::osyncstream(m_output_stream) << std::format
(
"\n{:%FT%T%Ez}\t{}\t{}\t{}\t{}\t{}",
zoned_time,
log_message_severity_to_string(event.severity),
std::filesystem::path(event.location.file_name()).filename().string(),
event.location.line(),
event.thread_id,
event.message
);
}

} // namespace debug
Loading

0 comments on commit 1a1870f

Please sign in to comment.