eOn client
Long-timescale dynamics: aKMC, NEB, parallel replica
☾
Toggle main menu visibility
Loading...
Searching...
No Matches
EonLogger.h
Go to the documentation of this file.
1
/*
2
** This file is part of eOn.
3
**
4
** SPDX-License-Identifier: BSD-3-Clause
5
**
6
** Copyright (c) 2010--present, eOn Development Team
7
** All rights reserved.
8
**
9
** Repo:
10
** https://github.com/TheochemUI/eOn
11
*/
12
#pragma once
13
14
#include "quill/Backend.h"
15
#include "quill/Frontend.h"
16
#include "quill/LogMacros.h"
17
#include "quill/Logger.h"
18
#include "quill/sinks/ConsoleSink.h"
19
#include "quill/sinks/FileSink.h"
20
#include <atomic>
21
#include <filesystem>
22
#include <mutex>
23
#include <source_location>
24
#include <string>
25
#include <string_view>
26
#include <system_error>
27
28
namespace
eonc::log
{
29
30
// Logger name constants for internal use
31
namespace
detail
{
32
inline
constexpr
std::string_view
kDefaultLoggerName
{
"combi"
};
33
inline
constexpr
std::string_view
kTracebackLoggerName
{
"_traceback"
};
34
}
// namespace detail
35
44
[[nodiscard]]
inline
quill::Logger *
get
() noexcept {
45
static
std::atomic<quill::Logger *> cached_logger{
nullptr
};
46
if
(quill::Logger *l = cached_logger.load(std::memory_order_relaxed)) {
47
return
l;
48
}
49
50
if
(
auto
*logger = quill::Frontend::get_logger(
51
std::string(
detail::kDefaultLoggerName
))) {
52
cached_logger.store(logger, std::memory_order_relaxed);
53
return
logger;
54
}
55
56
// Fallback for Python bindings/tests that didn't run ClientEON's main()
57
static
quill::Logger *fallback = []() -> quill::Logger * {
58
try
{
59
quill::Backend::start();
60
}
catch
(...) {
61
}
// Ignore if backend already started
62
63
try
{
64
auto
console_sink =
65
quill::Frontend::create_or_get_sink<quill::ConsoleSink>(
66
"fallback_console"
);
67
return
quill::Frontend::create_or_get_logger(
68
"combi"
, std::move(console_sink),
69
quill::PatternFormatterOptions{
"%(message)"
},
70
quill::ClockSourceType::System);
71
}
catch
(...) {
72
return
nullptr
;
73
}
74
}();
75
if
(fallback)
76
cached_logger.store(fallback, std::memory_order_relaxed);
77
return
fallback;
78
}
79
88
[[nodiscard]]
inline
quill::Logger *
traceback
() noexcept {
89
static
std::atomic<quill::Logger *> cached{
nullptr
};
90
if
(quill::Logger *l = cached.load(std::memory_order_relaxed)) {
91
return
l;
92
}
93
if
(
auto
*logger = quill::Frontend::get_logger(
94
std::string(
detail::kTracebackLoggerName
))) {
95
cached.store(logger, std::memory_order_relaxed);
96
return
logger;
97
}
98
return
nullptr
;
99
}
100
110
[[nodiscard]]
inline
quill::Logger *
111
get_file
(std::string_view name, std::string_view filename,
112
std::string_view pattern =
"%(message)"
) {
113
// If the logger already exists, return it immediately.
114
// Quill strictly checks configuration matches on recreation and throws if
115
// PatternFormatterOptions differ, which crashes instances (like
116
// Dimer/Optimizers) that are created multiple times in loops (e.g., NEB).
117
if
(
auto
*existing = quill::Frontend::get_logger(std::string(name))) {
118
return
existing;
119
}
120
static
std::mutex file_logger_mutex;
121
std::lock_guard<std::mutex> lock(file_logger_mutex);
122
if
(
auto
*existing = quill::Frontend::get_logger(std::string(name))) {
123
return
existing;
124
}
125
126
try
{
127
// Durable absolute path: optimizers open "_lbfgs.log" etc. under CWD.
128
// Job integration fixtures chdir into /tmp/eon_test_job_* then delete that
129
// tree when the case ends, while Quill's process-lifetime FileSink still
130
// flushes — "fopen failed after 3 attempts". Keep logs under a stable
131
// temp subdir instead of the disposable workdir.
132
namespace
fs = std::filesystem;
133
fs::path path{std::string(filename)};
134
if
(!path.is_absolute()) {
135
static
const
fs::path log_dir = [] {
136
fs::path d = fs::temp_directory_path() /
"eon_logs"
;
137
std::error_code ec;
138
fs::create_directories(d, ec);
139
return
d;
140
}();
141
path = log_dir / path.filename();
142
}
143
quill::FileSinkConfig cfg;
144
cfg.set_open_mode(
'w'
);
145
auto
file_sink = quill::Frontend::create_or_get_sink<quill::FileSink>(
146
path.string(), cfg);
147
return
quill::Frontend::create_or_get_logger(
148
std::string(name), std::move(file_sink),
149
quill::PatternFormatterOptions{std::string(pattern)},
150
quill::ClockSourceType::System);
151
}
catch
(...) {
152
return
get
();
// Fallback to default combi logger if creation fails
153
}
154
}
155
171
struct
Scoped
{
172
[[no_unique_address]] quill::Logger *
logger
{
nullptr
};
173
174
Scoped
() noexcept
175
:
logger
(
get
()) {}
176
177
// Implicit conversion to Logger* for seamless use with QUILL_LOG_* macros
178
operator
quill::Logger *()
const
noexcept
{
return
logger
; }
179
180
// Support QUILL_LOG_ macro pointer dereference
181
quill::Logger *
operator->
() const noexcept {
return
logger
; }
182
183
// Allow dynamic re-assignment (e.g. switching to _traceback logger)
184
Scoped
&
operator=
(quill::Logger *l)
noexcept
{
185
logger
= l;
186
return
*
this
;
187
}
188
189
// Explicit access if needed
190
[[nodiscard]] quill::Logger *
ptr
() const noexcept {
return
logger
; }
191
};
192
208
struct
FileScoped
{
209
[[no_unique_address]] quill::Logger *
logger
{
nullptr
};
210
211
FileScoped
(std::string_view name, std::string_view filename,
212
std::string_view pattern =
"%(message)"
) noexcept
213
:
logger
(
get_file
(name, filename, pattern)) {}
214
215
operator
quill::Logger *()
const
noexcept
{
return
logger
; }
216
// Support QUILL_LOG_ macro pointer dereference
217
quill::Logger *
operator->
() const noexcept {
return
logger
; }
218
FileScoped
&
operator=
(quill::Logger *l)
noexcept
{
219
logger
= l;
220
return
*
this
;
221
}
222
[[nodiscard]] quill::Logger *
ptr
() const noexcept {
return
logger
; }
223
};
224
225
}
// namespace eonc::log
226
227
// Force MSVC to evaluate __VA_ARGS__ properly
228
#define EONC_EXPAND(x) x
229
238
#define EONC_LOG_TRACE(...) \
239
do { \
240
if (auto *l = eonc::log::get()) { \
241
EONC_EXPAND(QUILL_LOG_TRACE_L1(l, __VA_ARGS__)); \
242
} \
243
} while (0)
244
#define EONC_LOG_DEBUG(...) \
245
do { \
246
if (auto *l = eonc::log::get()) { \
247
EONC_EXPAND(QUILL_LOG_DEBUG(l, __VA_ARGS__)); \
248
} \
249
} while (0)
250
#define EONC_LOG_INFO(...) \
251
do { \
252
if (auto *l = eonc::log::get()) { \
253
EONC_EXPAND(QUILL_LOG_INFO(l, __VA_ARGS__)); \
254
} \
255
} while (0)
256
#define EONC_LOG_WARNING(...) \
257
do { \
258
if (auto *l = eonc::log::get()) { \
259
EONC_EXPAND(QUILL_LOG_WARNING(l, __VA_ARGS__)); \
260
} \
261
} while (0)
262
#define EONC_LOG_ERROR(...) \
263
do { \
264
if (auto *l = eonc::log::get()) { \
265
EONC_EXPAND(QUILL_LOG_ERROR(l, __VA_ARGS__)); \
266
} \
267
} while (0)
268
#define EONC_LOG_CRITICAL(...) \
269
do { \
270
if (auto *l = eonc::log::get()) { \
271
EONC_EXPAND(QUILL_LOG_CRITICAL(l, __VA_ARGS__)); \
272
} \
273
} while (0)
eonc::log::detail
Definition
EonLogger.h:31
eonc::log::detail::kTracebackLoggerName
constexpr std::string_view kTracebackLoggerName
Definition
EonLogger.h:33
eonc::log::detail::kDefaultLoggerName
constexpr std::string_view kDefaultLoggerName
Definition
EonLogger.h:32
eonc::log
Definition
EonLogger.h:28
eonc::log::get
quill::Logger * get() noexcept
Get or create the default "combi" logger.
Definition
EonLogger.h:44
eonc::log::traceback
quill::Logger * traceback() noexcept
Get or create the "_traceback" logger for traceback logging.
Definition
EonLogger.h:88
eonc::log::get_file
quill::Logger * get_file(std::string_view name, std::string_view filename, std::string_view pattern="%(message)")
Get or create a named logger with a file sink.
Definition
EonLogger.h:111
eonc::log::FileScoped::logger
quill::Logger * logger
Definition
EonLogger.h:209
eonc::log::FileScoped::FileScoped
FileScoped(std::string_view name, std::string_view filename, std::string_view pattern="%(message)") noexcept
Definition
EonLogger.h:211
eonc::log::FileScoped::operator->
quill::Logger * operator->() const noexcept
Definition
EonLogger.h:217
eonc::log::FileScoped::ptr
quill::Logger * ptr() const noexcept
Definition
EonLogger.h:222
eonc::log::FileScoped::operator=
FileScoped & operator=(quill::Logger *l) noexcept
Definition
EonLogger.h:218
eonc::log::Scoped::Scoped
Scoped() noexcept
Definition
EonLogger.h:174
eonc::log::Scoped::ptr
quill::Logger * ptr() const noexcept
Definition
EonLogger.h:190
eonc::log::Scoped::operator->
quill::Logger * operator->() const noexcept
Definition
EonLogger.h:181
eonc::log::Scoped::logger
quill::Logger * logger
Definition
EonLogger.h:172
eonc::log::Scoped::operator=
Scoped & operator=(quill::Logger *l) noexcept
Definition
EonLogger.h:184
include
eon
EonLogger.h
Generated by
1.17.0
Generated by
Doxygen 1.17.0
Analytics by
Antics
provided by
TurtleTech ehf