Logger
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
set(SRC_FILES
|
||||
"imp/cpp/IACore.cpp"
|
||||
"imp/cpp/Logger.cpp"
|
||||
)
|
||||
|
||||
add_library(IACore STATIC ${SRC_FILES})
|
||||
|
||||
61
Src/IACore/imp/cpp/Logger.cpp
Normal file
61
Src/IACore/imp/cpp/Logger.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IACore/Logger.hpp>
|
||||
#include <IACore/File.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
Logger::ELogLevel Logger::s_logLevel{Logger::ELogLevel::WARN};
|
||||
HRTimePoint Logger::s_startTime{};
|
||||
IACore::File *Logger::s_logFile{};
|
||||
|
||||
VOID Logger::Initialize()
|
||||
{
|
||||
s_startTime = HRClock::now();
|
||||
}
|
||||
|
||||
VOID Logger::Terminate()
|
||||
{
|
||||
if (s_logFile)
|
||||
{
|
||||
s_logFile->Close();
|
||||
delete s_logFile;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Logger::EnableLoggingToDisk(IN PCCHAR filePath)
|
||||
{
|
||||
if (s_logFile)
|
||||
return true;
|
||||
s_logFile = new IACore::File(filePath, IACore::File::EOpenFlags::Write);
|
||||
return s_logFile->IsOpen();
|
||||
}
|
||||
|
||||
VOID Logger::SetLogLevel(IN ELogLevel logLevel)
|
||||
{
|
||||
s_logLevel = logLevel;
|
||||
}
|
||||
|
||||
VOID Logger::LogInternal(IN PCCHAR prefix, IN String&& msg)
|
||||
{
|
||||
std::chrono::duration<double> elapsed = HRClock::now() - s_startTime;
|
||||
double timestamp = elapsed.count();
|
||||
const auto outLine = std::format("[{:>8.3f}]: [{}]: {}\n", timestamp, prefix, msg);
|
||||
const auto outStream = s_logFile ? s_logFile->GetStreamHandle() : &std::cout;
|
||||
outStream->write(outLine.data(), outLine.size());
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,16 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
@ -21,47 +21,54 @@
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
namespace IACore {
|
||||
namespace IACore
|
||||
{
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class File {
|
||||
public:
|
||||
class File
|
||||
{
|
||||
public:
|
||||
// Modern mapping of flags to standard IO streams
|
||||
enum class EOpenFlags : UINT32 {
|
||||
Read = 1 << 0, // std::ios::in
|
||||
Write = 1 << 1, // std::ios::out
|
||||
enum class EOpenFlags : UINT32
|
||||
{
|
||||
Read = 1 << 0, // std::ios::in
|
||||
Write = 1 << 1, // std::ios::out
|
||||
Binary = 1 << 2, // std::ios::binary
|
||||
Append = 1 << 3, // std::ios::app
|
||||
Trunc = 1 << 4 // std::ios::trunc
|
||||
Trunc = 1 << 4 // std::ios::trunc
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Static Helper API (The "One-Liners")
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
// Reads entire file into a binary vector
|
||||
NO_DISCARD("Handle the error")
|
||||
STATIC tl::expected<Vector<UINT8>, String> ReadToVector(CONST String& path) {
|
||||
|
||||
STATIC tl::expected<Vector<UINT8>, String> ReadToVector(CONST String &path)
|
||||
{
|
||||
// 1. Check File Existence & Size
|
||||
std::error_code ec;
|
||||
auto fileSize = fs::file_size(path, ec);
|
||||
|
||||
if (ec) {
|
||||
|
||||
if (ec)
|
||||
{
|
||||
return tl::make_unexpected(String("File not found or inaccessible: ") + path);
|
||||
}
|
||||
|
||||
// 2. Open Stream
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
if (!file.is_open())
|
||||
{
|
||||
return tl::make_unexpected(String("Failed to open file handle: ") + path);
|
||||
}
|
||||
|
||||
// 3. Read
|
||||
Vector<UINT8> buffer;
|
||||
buffer.resize(CAST(fileSize, SIZE_T));
|
||||
file.read(REINTERPRET(buffer.data(), char*), fileSize);
|
||||
if(file.fail())
|
||||
file.read(REINTERPRET(buffer.data(), char *), fileSize);
|
||||
if (file.fail())
|
||||
return tl::make_unexpected(String("Read error: ") + path);
|
||||
|
||||
return buffer;
|
||||
@ -69,10 +76,13 @@ namespace IACore {
|
||||
|
||||
// Reads entire file into a String
|
||||
NO_DISCARD("Handle the error")
|
||||
STATIC tl::expected<String, String> ReadToString(CONST String& path) {
|
||||
|
||||
STATIC tl::expected<String, String> ReadToString(CONST String &path)
|
||||
{
|
||||
// Reuse the binary logic to avoid code duplication, then cast
|
||||
auto result = ReadToVector(path);
|
||||
if (!result) {
|
||||
if (!result)
|
||||
{
|
||||
return tl::make_unexpected(result.error());
|
||||
}
|
||||
|
||||
@ -89,86 +99,117 @@ namespace IACore {
|
||||
|
||||
// Old: ExtractFilenameFromPath<true/false>
|
||||
// New: true -> filename(), false -> stem()
|
||||
template<BOOL includeExtension = true>
|
||||
STATIC String ExtractFilename(CONST String& pathStr) {
|
||||
template<BOOL includeExtension = true> STATIC String ExtractFilename(CONST String &pathStr)
|
||||
{
|
||||
fs::path p(pathStr);
|
||||
if CONSTEXPR (includeExtension) {
|
||||
if CONSTEXPR (includeExtension)
|
||||
{
|
||||
return p.filename().string(); // "sprite.png"
|
||||
} else {
|
||||
return p.stem().string(); // "sprite"
|
||||
}
|
||||
else
|
||||
{
|
||||
return p.stem().string(); // "sprite"
|
||||
}
|
||||
}
|
||||
|
||||
// Old: ExtractDirectoryFromPath
|
||||
STATIC String ExtractDirectory(CONST String& pathStr) {
|
||||
STATIC String ExtractDirectory(CONST String &pathStr)
|
||||
{
|
||||
fs::path p(pathStr);
|
||||
return p.parent_path().string(); // "assets/textures"
|
||||
}
|
||||
|
||||
STATIC BOOL Exists(CONST String& pathStr) {
|
||||
STATIC BOOL Exists(CONST String &pathStr)
|
||||
{
|
||||
std::error_code ec;
|
||||
return fs::exists(pathStr, ec);
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
// ---------------------------------------------------------------------
|
||||
// Instance API (For streaming/partial reads)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
File() = default;
|
||||
|
||||
// RAII Constructor
|
||||
File(CONST String& path, UINT32 flags) {
|
||||
#ifdef __cplusplus
|
||||
File(CONST String &path, EOpenFlags flags)
|
||||
#else
|
||||
File(CONST String &path, UINT32 flags)
|
||||
#endif
|
||||
{
|
||||
UNUSED(Open(path, flags));
|
||||
}
|
||||
|
||||
~File() {
|
||||
~File()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
// Returns void (success) or error String
|
||||
tl::expected<void, String> Open(CONST String& path, UINT32 flags) {
|
||||
#ifdef __cplusplus
|
||||
tl::expected<void, String> Open(CONST String &path, EOpenFlags flags)
|
||||
#else
|
||||
tl::expected<void, String> Open(CONST String &path, UINT32 flags)
|
||||
#endif
|
||||
{
|
||||
Close(); // Ensure previous handle is closed
|
||||
|
||||
std::ios_base::openmode mode = static_cast<std::ios_base::openmode>(0);
|
||||
if (flags & (UINT32)EOpenFlags::Read) mode |= std::ios::in;
|
||||
if (flags & (UINT32)EOpenFlags::Write) mode |= std::ios::out;
|
||||
if (flags & (UINT32)EOpenFlags::Binary) mode |= std::ios::binary;
|
||||
if (flags & (UINT32)EOpenFlags::Append) mode |= std::ios::app;
|
||||
if (flags & (UINT32)EOpenFlags::Trunc) mode |= std::ios::trunc;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Read)
|
||||
mode |= std::ios::in;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Write)
|
||||
mode |= std::ios::out;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Binary)
|
||||
mode |= std::ios::binary;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Append)
|
||||
mode |= std::ios::app;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Trunc)
|
||||
mode |= std::ios::trunc;
|
||||
|
||||
m_fs.open(path, mode);
|
||||
|
||||
if (!m_fs.is_open()) {
|
||||
if (!m_fs.is_open())
|
||||
{
|
||||
return tl::make_unexpected(String("Failed to open file: ") + path);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
VOID Close() {
|
||||
if (m_fs.is_open()) {
|
||||
VOID Close()
|
||||
{
|
||||
if (m_fs.is_open())
|
||||
{
|
||||
m_fs.close();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL IsOpen() CONST {
|
||||
BOOL IsOpen() CONST
|
||||
{
|
||||
return m_fs.is_open();
|
||||
}
|
||||
|
||||
// Returns number of bytes read
|
||||
SIZE_T Read(PVOID buffer, SIZE_T size) {
|
||||
if (!m_fs.is_open()) return 0;
|
||||
m_fs.read(REINTERPRET(buffer, char*), size);
|
||||
SIZE_T Read(PVOID buffer, SIZE_T size)
|
||||
{
|
||||
if B_UNLIKELY (!m_fs.is_open())
|
||||
return 0;
|
||||
m_fs.read(REINTERPRET(buffer, char *), size);
|
||||
return static_cast<SIZE_T>(m_fs.gcount());
|
||||
}
|
||||
|
||||
VOID Write(CONST PVOID buffer, SIZE_T size) {
|
||||
if (m_fs.is_open()) {
|
||||
m_fs.write(REINTERPRET(buffer, const char*), size);
|
||||
}
|
||||
VOID Write(CONST PVOID buffer, SIZE_T size)
|
||||
{
|
||||
if B_UNLIKELY (!m_fs.is_open())
|
||||
return;
|
||||
m_fs.write(REINTERPRET(buffer, const char *), size);
|
||||
}
|
||||
|
||||
private:
|
||||
std::fstream *GetStreamHandle()
|
||||
{
|
||||
return &m_fs;
|
||||
}
|
||||
|
||||
private:
|
||||
std::fstream m_fs;
|
||||
};
|
||||
}
|
||||
} // namespace IACore
|
||||
@ -22,29 +22,6 @@
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
template<typename... Args>
|
||||
VOID LogInfo(Args... args)
|
||||
{
|
||||
StringStream ss;
|
||||
UNUSED((ss << ... << args));
|
||||
printf( __CC_WHITE "[INFO]: %s" __CC_DEFAULT "\n", ss.str().c_str());
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
VOID LogWarn(Args... args)
|
||||
{
|
||||
StringStream ss;
|
||||
UNUSED((ss << ... << args));
|
||||
printf( __CC_YELLOW "[WARN]: %s" __CC_DEFAULT "\n", ss.str().c_str());
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
VOID LogError(Args... args)
|
||||
{
|
||||
StringStream ss;
|
||||
UNUSED((ss << ... << args));
|
||||
printf( __CC_RED "[ERROR]: %s" __CC_DEFAULT "\n", ss.str().c_str());
|
||||
}
|
||||
} // namespace IACore
|
||||
|
||||
#endif
|
||||
|
||||
117
Src/IACore/inc/IACore/Logger.hpp
Normal file
117
Src/IACore/inc/IACore/Logger.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
class File;
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
enum class ELogLevel
|
||||
{
|
||||
VERBOSE,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR
|
||||
};
|
||||
|
||||
public:
|
||||
STATIC VOID Initialize();
|
||||
STATIC VOID Terminate();
|
||||
|
||||
STATIC BOOL EnableLoggingToDisk(IN PCCHAR filePath);
|
||||
STATIC VOID SetLogLevel(IN ELogLevel logLevel);
|
||||
|
||||
template<typename... Args> STATIC VOID Status(FormatterString<Args...> fmt, Args &&...args)
|
||||
{
|
||||
LogStatus(std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
}
|
||||
|
||||
template<typename... Args> STATIC VOID Info(FormatterString<Args...> fmt, Args &&...args)
|
||||
{
|
||||
LogInfo(std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
}
|
||||
|
||||
template<typename... Args> STATIC VOID Warn(FormatterString<Args...> fmt, Args &&...args)
|
||||
{
|
||||
LogWarn(std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
}
|
||||
|
||||
template<typename... Args> STATIC VOID Error(FormatterString<Args...> fmt, Args &&...args)
|
||||
{
|
||||
LogError(std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||
}
|
||||
|
||||
private:
|
||||
#if IA_ENABLE_LOGGING > 0
|
||||
STATIC VOID LogStatus(IN String &&msg)
|
||||
{
|
||||
if (s_logLevel <= ELogLevel::VERBOSE)
|
||||
LogInternal("STATUS", IA_MOVE(msg));
|
||||
}
|
||||
|
||||
STATIC VOID LogInfo(IN String &&msg)
|
||||
{
|
||||
if (s_logLevel <= ELogLevel::INFO)
|
||||
LogInternal("INFO", IA_MOVE(msg));
|
||||
}
|
||||
|
||||
STATIC VOID LogWarn(IN String &&msg)
|
||||
{
|
||||
if (s_logLevel <= ELogLevel::WARN)
|
||||
LogInternal("WARN", IA_MOVE(msg));
|
||||
}
|
||||
|
||||
STATIC VOID LogError(IN String &&msg)
|
||||
{
|
||||
if (s_logLevel <= ELogLevel::ERROR)
|
||||
LogInternal("ERROR", IA_MOVE(msg));
|
||||
}
|
||||
#else
|
||||
STATIC VOID LogStatus(IN String &&msg)
|
||||
{
|
||||
UNUSED(msg);
|
||||
}
|
||||
|
||||
STATIC VOID LogInfo(IN String &&msg)
|
||||
{
|
||||
UNUSED(msg);
|
||||
}
|
||||
|
||||
STATIC VOID LogWarn(IN String &&msg)
|
||||
{
|
||||
UNUSED(msg);
|
||||
}
|
||||
|
||||
STATIC VOID LogError(IN String &&msg)
|
||||
{
|
||||
UNUSED(msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC VOID LogInternal(IN PCCHAR prefix, IN String &&msg);
|
||||
|
||||
private:
|
||||
STATIC ELogLevel s_logLevel;
|
||||
STATIC HRTimePoint s_startTime;
|
||||
STATIC IACore::File *s_logFile;
|
||||
};
|
||||
}
|
||||
@ -29,6 +29,8 @@
|
||||
# include <limits>
|
||||
# include <cstring>
|
||||
# include <cstddef>
|
||||
# include <chrono>
|
||||
# include <iostream>
|
||||
# include <concepts>
|
||||
# include <functional>
|
||||
# include <type_traits>
|
||||
@ -526,11 +528,9 @@ using String = std::string;
|
||||
using StringView = std::string_view;
|
||||
using StringStream = std::stringstream;
|
||||
|
||||
template<typename... Args> STATIC String BuildString(Args &&...args)
|
||||
{
|
||||
std::stringstream ss;
|
||||
(ss << ... << args);
|
||||
return ss.str();
|
||||
}
|
||||
using HRClock = std::chrono::high_resolution_clock;
|
||||
using HRTimePoint = std::chrono::time_point<HRClock>;
|
||||
|
||||
template<typename... Args> using FormatterString = std::format_string<Args...>;
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user