AYON Cpp Dev Tools  0.1.0
Loading...
Searching...
No Matches
AyonLogger.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "spdlog/async.h"
4#include "spdlog/common.h"
5#include "spdlog/sinks/basic_file_sink.h"
6#include "spdlog/sinks/stdout_color_sinks.h"
7
8#include <algorithm>
9#include <cctype>
10#include <filesystem>
11#include <fstream>
12#include <iostream>
13#include <memory>
14#include <mutex>
15#include <set>
16#include <spdlog/spdlog.h>
17#include <string>
18#include <utility>
19
32public:
34 // Keep the logger alive until process exit. DLL-local static destruction
35 // order in host applications can be unsafe during shutdown on Windows.
36 static auto* instance = new AyonLogger();
37 return *instance;
38 }
39
40 // Explicit Initialization for File Logging
41 // @param filepath: Path to the log file
42 // @param flushIntervalSeconds: 0 = flush on warn/error only, >0 = flush every n seconds
43 void initFileLogger(const std::string& filepath, unsigned int flushIntervalSeconds = 0) {
44 std::lock_guard<std::mutex> lock(m_initMutex);
45
47 std::cout << "[AyonLogger] File logger already enabled. Ignoring new path: "
48 << filepath << std::endl;
49 return;
50 }
51
52 if (filepath.empty()) return;
53
54 std::cout << "[AyonLogger] Initializing async file logger at: " << filepath << std::endl;
55 try {
56 auto abs_path = std::filesystem::absolute(filepath).string();
57 {
58 std::ofstream probe(abs_path, std::ios::app);
59 if (!probe.is_open()) {
60 throw std::runtime_error("Failed opening file " + abs_path + " for writing");
61 }
62 }
63
64 // Initialize async thread pool only if not already initialized
65 // (another component may have already called spdlog::init_thread_pool)
66 if (!spdlog::thread_pool()) {
67 spdlog::init_thread_pool(8192, 1);
68 }
69 m_fileLoggerThreadPool = spdlog::thread_pool();
70
71 std::string logger_name = std::string("AyonLogger_file_logger_") + abs_path;
72
73 m_fileLogger = spdlog::basic_logger_mt<spdlog::async_factory>(
74 logger_name, abs_path);
75
76 m_fileLogger->set_pattern(
77 "{\"timestamp\":\"%Y-%m-%d %H:%M:%S.%e\",\"level\":\"%l\","
78 "\"thread_id\":\"%t\",\"process_id\":\"%P\",\"message\":\"%v\"}");
79 m_fileLogger->set_level(spdlog::level::info);
80
81 if (flushIntervalSeconds > 0) {
82 // Periodic flush - better throughput for async logging
83 spdlog::flush_every(std::chrono::seconds(flushIntervalSeconds));
84 } else {
85 // Flush only on warn or above - avoids flushing on every info log
86 m_fileLogger->flush_on(spdlog::level::warn);
87 }
88
90 std::cout << "[AyonLogger] Async file logger initialized successfully." << std::endl;
91 }
92 catch (const std::exception& e) {
93 std::cerr << "[AyonLogger] Failed to init async file logger: " << e.what() << std::endl;
94 m_enableFileLogging = false;
95 }
96 }
97
98 // --- Singleton Safety ---
99 AyonLogger(const AyonLogger&) = delete;
100 AyonLogger& operator=(const AyonLogger&) = delete;
101
102 std::set<std::string>::iterator key(const std::string& key) {
103 return m_enabledLoggingKeys.find(key);
104 }
105
106 bool registerLoggingKey(const std::string& keyName) {
107 auto insertion = m_enabledLoggingKeys.insert(keyName);
108 return insertion.second;
109 }
110
111 bool unregisterLoggingKey(const std::string& keyName) {
112 auto it = m_enabledLoggingKeys.find(keyName);
113 if (it != m_enabledLoggingKeys.end()) {
114 m_enabledLoggingKeys.erase(it);
115 return true;
116 }
117 return false;
118 }
119
120 bool isKeyActive(const std::set<std::string>::iterator& loggingIterator) {
121 return loggingIterator != m_enabledLoggingKeys.end();
122 }
123
124 template<typename... Args>
125 void error(fmt::format_string<Args...> fmt, Args&&... args) {
126 log(spdlog::level::err, fmt, std::forward<Args>(args)...);
127 }
128
129 template<typename... Args>
130 void error(const std::set<std::string>::iterator& it,
131 fmt::format_string<Args...> fmt, Args&&... args) {
132 if (isKeyActive(it))
133 log(spdlog::level::err, fmt, std::forward<Args>(args)...);
134 }
135
136 template<typename... Args>
137 void info(fmt::format_string<Args...> fmt, Args&&... args) {
138 log(spdlog::level::info, fmt, std::forward<Args>(args)...);
139 }
140
141 template<typename... Args>
142 void info(const std::set<std::string>::iterator& it,
143 fmt::format_string<Args...> fmt, Args&&... args) {
144 if (isKeyActive(it))
145 log(spdlog::level::info, fmt, std::forward<Args>(args)...);
146 }
147
148 template<typename... Args>
149 void warn(fmt::format_string<Args...> fmt, Args&&... args) {
150 log(spdlog::level::warn, fmt, std::forward<Args>(args)...);
151 }
152
153 template<typename... Args>
154 void warn(const std::set<std::string>::iterator& it,
155 fmt::format_string<Args...> fmt, Args&&... args) {
156 if (isKeyActive(it))
157 log(spdlog::level::warn, fmt, std::forward<Args>(args)...);
158 }
159
160 template<typename... Args>
161 void critical(fmt::format_string<Args...> fmt, Args&&... args) {
162 log(spdlog::level::critical, fmt, std::forward<Args>(args)...);
163 }
164
165 template<typename... Args>
166 void critical(const std::set<std::string>::iterator& it,
167 fmt::format_string<Args...> fmt, Args&&... args) {
168 if (isKeyActive(it))
169 log(spdlog::level::critical, fmt, std::forward<Args>(args)...);
170 }
171
172 void setLogLevel(spdlog::level::level_enum lvl, bool applyToFile = false) {
173 setLevel(lvl, applyToFile);
174 }
175
176 void setLogLevel(const std::string& levelStr, bool applyToFile = false) {
177 auto normalizedLevel = levelStr;
178 std::transform(
179 normalizedLevel.begin(),
180 normalizedLevel.end(),
181 normalizedLevel.begin(),
182 [](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
183 auto lvl = spdlog::level::from_str(normalizedLevel);
184 setLevel(lvl, applyToFile);
185 }
186
187 void setLogLevelFromEnv(const std::string& envKey = "AYON_USD_RESOLVER_LOG_LVL", bool applyToFile = false) {
188 auto envVal = std::getenv(envKey.c_str());
189 if (envVal) {
190 setLogLevel(std::string(envVal), applyToFile);
191 std::cout << "[AyonLogger] Log level set from environment variable '" << envKey
192 << "' with value '" << envVal << "'" << std::endl;
193 }
194 }
195
196 void setLogLevelInfo(bool applyToFile = false) {
197 setLevel(spdlog::level::info, applyToFile);
198 }
199 void setLogLevelError(bool applyToFile = false) {
200 setLevel(spdlog::level::err, applyToFile);
201 }
202 void setLogLevelWarn(bool applyToFile = false) {
203 setLevel(spdlog::level::warn, applyToFile);
204 }
205 void setLogLevelCritical(bool applyToFile = false) {
206 setLevel(spdlog::level::critical, applyToFile);
207 }
208 void setLogLevelOff(bool applyToFile = false) {
209 setLevel(spdlog::level::off, applyToFile);
210 }
211
212 // Explicit flush for async loggers
213 void flush() {
214 if (m_consoleLogger) m_consoleLogger->flush();
215 if (canUseAsyncFileLogger()) m_fileLogger->flush();
216 }
217
218private:
219 // Private Constructor (Runs once)
221 std::cout << "[AyonLogger] Singleton Constructor Started." << std::endl;
222
223 // Console logger (synchronous for immediate feedback)
224 auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
225 console_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v");
226 m_consoleLogger = std::make_shared<spdlog::logger>("console", console_sink);
227 m_consoleLogger->set_level(spdlog::level::info);
228
229 std::cout << "[AyonLogger] Singleton Constructor Finished." << std::endl;
230 }
231
233 if (m_consoleLogger) {
234 m_consoleLogger->flush();
235 }
237 spdlog::drop(m_fileLogger->name());
238 m_fileLogger.reset();
240 m_enableFileLogging = false;
241 }
242 if (m_consoleLogger) {
243 spdlog::drop(m_consoleLogger->name());
244 m_consoleLogger.reset();
245 }
246 }
247
248 template<typename... Args>
249 void log(spdlog::level::level_enum lvl,
250 fmt::format_string<Args...> fmt,
251 Args&&... args)
252 {
253 if (m_consoleLogger)
254 m_consoleLogger->log(lvl, fmt, std::forward<Args>(args)...);
255
257 m_fileLogger->log(lvl, fmt, std::forward<Args>(args)...);
258 }
259
262 }
263
264 void setLevel(spdlog::level::level_enum lvl, bool applyToFile) {
265 if (m_consoleLogger)
266 m_consoleLogger->set_level(lvl);
267 if (applyToFile && m_fileLogger)
268 m_fileLogger->set_level(lvl);
269 }
270
271 std::shared_ptr<spdlog::logger> m_consoleLogger;
272 std::shared_ptr<spdlog::logger> m_fileLogger;
273 std::weak_ptr<spdlog::details::thread_pool> m_fileLoggerThreadPool;
274
276 std::mutex m_initMutex;
277 std::set<std::string> m_enabledLoggingKeys;
278};
Simple Logger Class that wraps around spdlog in order to expose easy logging functions.
Definition: AyonLogger.hpp:31
bool canUseAsyncFileLogger() const
Definition: AyonLogger.hpp:260
void warn(fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:149
void info(const std::set< std::string >::iterator &it, fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:142
void setLogLevel(const std::string &levelStr, bool applyToFile=false)
Definition: AyonLogger.hpp:176
void setLogLevelWarn(bool applyToFile=false)
Definition: AyonLogger.hpp:202
void error(fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:125
AyonLogger()
Definition: AyonLogger.hpp:220
bool isKeyActive(const std::set< std::string >::iterator &loggingIterator)
Definition: AyonLogger.hpp:120
void warn(const std::set< std::string >::iterator &it, fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:154
void info(fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:137
std::set< std::string >::iterator key(const std::string &key)
Definition: AyonLogger.hpp:102
void setLogLevelOff(bool applyToFile=false)
Definition: AyonLogger.hpp:208
void initFileLogger(const std::string &filepath, unsigned int flushIntervalSeconds=0)
Definition: AyonLogger.hpp:43
std::weak_ptr< spdlog::details::thread_pool > m_fileLoggerThreadPool
Definition: AyonLogger.hpp:273
void critical(fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:161
void error(const std::set< std::string >::iterator &it, fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:130
bool m_enableFileLogging
Definition: AyonLogger.hpp:275
void critical(const std::set< std::string >::iterator &it, fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:166
AyonLogger(const AyonLogger &)=delete
void setLogLevelError(bool applyToFile=false)
Definition: AyonLogger.hpp:199
void flush()
Definition: AyonLogger.hpp:213
void setLevel(spdlog::level::level_enum lvl, bool applyToFile)
Definition: AyonLogger.hpp:264
static AyonLogger & getInstance()
Definition: AyonLogger.hpp:33
std::shared_ptr< spdlog::logger > m_consoleLogger
Definition: AyonLogger.hpp:271
std::mutex m_initMutex
Definition: AyonLogger.hpp:276
void log(spdlog::level::level_enum lvl, fmt::format_string< Args... > fmt, Args &&... args)
Definition: AyonLogger.hpp:249
std::set< std::string > m_enabledLoggingKeys
Definition: AyonLogger.hpp:277
bool unregisterLoggingKey(const std::string &keyName)
Definition: AyonLogger.hpp:111
bool registerLoggingKey(const std::string &keyName)
Definition: AyonLogger.hpp:106
void setLogLevel(spdlog::level::level_enum lvl, bool applyToFile=false)
Definition: AyonLogger.hpp:172
void setLogLevelCritical(bool applyToFile=false)
Definition: AyonLogger.hpp:205
std::shared_ptr< spdlog::logger > m_fileLogger
Definition: AyonLogger.hpp:272
AyonLogger & operator=(const AyonLogger &)=delete
void setLogLevelInfo(bool applyToFile=false)
Definition: AyonLogger.hpp:196
void setLogLevelFromEnv(const std::string &envKey="AYON_USD_RESOLVER_LOG_LVL", bool applyToFile=false)
Definition: AyonLogger.hpp:187
~AyonLogger()
Definition: AyonLogger.hpp:232