Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
Logger.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** R-Type
4** File description:
5** Logger.cpp, Logger class implementation
6*/
7
8/*
9** MIT License
10**
11** Copyright (c) 2025 Robin Toillon
12**
13** Permission is hereby granted, free of charge, to any person obtaining
14** a copy of this software and associated documentation files (the
15** "Software"), to deal in the Software without restriction, including
16** without limitation the rights to use, copy, modify, merge, publish,
17** distribute, sublicense, and/or sell copies of the Software, and to
18** permit persons to whom the Software is furnished to do so, subject to
19** the following conditions:
20**
21** The above copyright notice and this permission notice shall be
22** included in all copies or substantial portions of the Software.
23**
24** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31*/
32
42#include "RType/Logger.hpp"
43
44#include <chrono>
45#include <filesystem>
46#include <fstream>
47#include <iomanip>
48#include <iostream>
49#include <mutex>
50#include <print>
51
52namespace rtp::log
53{
55 // Private API
57
58 namespace detail
59 {
61 public:
62 explicit LoggerBackend(void) noexcept
63 {
64 }
65
66 ~LoggerBackend() noexcept {
67 if (this->_file.is_open()) {
68 this->_file.close();
69 }
70 }
71
72 void setOutputFile(std::string_view filename)
73 {
74 std::lock_guard lock(this->_mutex);
75 if (this->_file.is_open())
76 this->_file.close();
77 this->_file.open(std::string(filename), std::ios::app);
78 }
79
80 void write(Level level, std::string_view msg,
81 const std::source_location &loc)
82 {
83 auto now = std::chrono::system_clock::now();
84 auto timePoint = std::chrono::floor<std::chrono::seconds>(
85 now);
86 auto cleanFileName = std::filesystem::path(
87 loc.file_name()).filename().string();
88
89 std::string_view color = "";
90
91 switch (level) {
92 using enum Level;
93 case Debug:
94 color = "\033[36m";
95 break;
96 case Info:
97 color = "\033[32m";
98 break;
99 case Warning:
100 color = "\033[33m";
101 break;
102 case Error:
103 color = "\033[31m";
104 break;
105 case Fatal:
106 color = "\033[1;31m";
107 break;
108 case None:
109 color = "\033[90m";
110 break;
111 }
112
113 std::lock_guard lock{this->_mutex};
114
115 std::println(std::cout, "{}[{:%T}] [{}] {} \033[0m "
116 "\t({}:{})",
117 color, timePoint, level, msg,
118 loc.file_name(), loc.line());
119 if (this->_file.is_open()) {
120 std::println(this->_file, "[{:%T}] [{}] {} ({}:{})",
121 timePoint, level, msg,
122 cleanFileName, loc.line());
123 }
124 }
125
126 private:
127 std::mutex _mutex;
128 std::ofstream _file;
129 };
130
131 static LoggerBackend &getBackend(void) noexcept
132 {
133 static LoggerBackend instance;
134 return instance;
135 }
136
137 void logImpl(Level level, std::string_view message,
138 const std::source_location &loc)
139 {
140 try {
141 getBackend().write(level, message, loc);
142 } catch (...) {
143 std::println(std::cerr, "\033[31m[LOGGER FAILURE] {} \033[0m",
144 message);
145 }
146 }
147 }
148
150 // Public API
152
153 auto configure(std::string_view logFilePath) noexcept
154 -> std::expected<void, rtp::Error>
155 {
156 try {
157 detail::getBackend().setOutputFile(logFilePath);
158 } catch (const std::exception &e) {
159 return std::unexpected{
161 "Logger configuration failed: {}", e.what())};
162 } catch (...) {
163 return std::unexpected{
165 "Logger configuration failed: unknown error")};
166 }
167
168 return {};
169 }
170}
Logger declaration with support for multiple log levels.
static auto failure(ErrorCode code, std::format_string< Args... > fmt, Args &&...args) -> Error
Create a failure-level error.
void write(Level level, std::string_view msg, const std::source_location &loc)
Definition Logger.cpp:80
void setOutputFile(std::string_view filename)
Definition Logger.cpp:72
void logImpl(Level level, std::string_view message, const std::source_location &loc)
Definition Logger.cpp:137
static LoggerBackend & getBackend(void) noexcept
Definition Logger.cpp:131
Level
Severity levels for log messages.
Definition LogLevel.hpp:57
@ Warning
Warning messages for potentially harmful situations.
@ Info
General informational messages.
@ None
No logging (used to disable logging)
@ Fatal
Fatal error messages indicating critical failures.
@ Error
Error messages for error events.
@ Debug
Detailed information for debugging purposes.
auto configure(std::string_view logFilePath) noexcept -> std::expected< void, rtp::Error >
Configure the logger using a configuration file.
Definition Logger.cpp:153
@ InvalidParameter
Invalid function parameter provided.
@ Unknown
Unknown or unspecified error.