17#define NCORR_ISATTY(fd) _isatty(fd)
18#define NCORR_FILENO(f) _fileno(f)
21#define NCORR_ISATTY(fd) ::isatty(fd)
22#define NCORR_FILENO(f) ::fileno(f)
31std::string to_lower(std::string s) {
32 std::transform(s.begin(), s.end(), s.begin(),
33 [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
38const char* base_name(
const char* path) {
40 const char* base = path;
41 for (
const char* p = path; *p; ++p) {
42 if (*p ==
'/' || *p ==
'\\') base = p + 1;
48const char* color_for(
Level l) {
64const char* color_reset() {
69std::string timestamp() {
70 using namespace std::chrono;
71 const auto now = system_clock::now();
72 const auto t = system_clock::to_time_t(now);
73 const auto ms = duration_cast<milliseconds>(now.time_since_epoch()).count() % 1000;
76 localtime_s(&tm_buf, &t);
78 localtime_r(&t, &tm_buf);
81 std::strftime(buf,
sizeof(buf),
"%Y-%m-%d %H:%M:%S", &tm_buf);
83 std::snprintf(out,
sizeof(out),
"%s.%03d", buf,
static_cast<int>(ms));
88std::string rtrim(
const std::string& s) {
89 std::size_t end = s.size();
91 const char c = s[end - 1];
92 if (c ==
'\n' || c ==
'\r' || c ==
' ' || c ==
'\t')
97 return s.substr(0, end);
103 const std::string v = to_lower(s);
107 if (v ==
"warn" || v ==
"warning")
return Level::Warn;
109 if (v ==
"off" || v ==
"none" || v ==
"silent")
return Level::Off;
140void Logger::ensure_env() {
148 if (
const char* lvl = std::getenv(
"NCORR_LOG_LEVEL")) {
151 if (
const char* con = std::getenv(
"NCORR_LOG_CONSOLE")) {
152 const std::string v = to_lower(con);
153 console_enabled_ = !(v ==
"0" || v ==
"false" || v ==
"off" || v ==
"no");
155 if (
const char* path = std::getenv(
"NCORR_LOG_FILE")) {
156 if (path[0] !=
'\0') {
157 file_.open(path, std::ios::out | std::ios::app);
163 std::lock_guard<std::mutex> lk(mtx_);
168 std::lock_guard<std::mutex> lk(mtx_);
173 std::lock_guard<std::mutex> lk(mtx_);
174 return console_level_;
178 std::lock_guard<std::mutex> lk(mtx_);
183 std::lock_guard<std::mutex> lk(mtx_);
184 if (file_.is_open()) file_.close();
185 if (path.empty())
return true;
186 file_.open(path, std::ios::out | std::ios::app);
187 return file_.is_open();
191 std::lock_guard<std::mutex> lk(mtx_);
192 console_enabled_ = on;
196 std::lock_guard<std::mutex> lk(mtx_);
197 verbose_format_ = on;
201 std::lock_guard<std::mutex> lk(mtx_);
204 const bool to_console = console_enabled_ && l >= console_level_;
205 const bool to_file = file_.is_open() && l >= file_level_;
206 return to_console || to_file;
210 std::lock_guard<std::mutex> lk(mtx_);
214 const std::string text = rtrim(msg);
215 const char* fname = base_name(file);
217 if (console_enabled_ && l >= console_level_) {
218 std::ostream& os = (l >=
Level::Warn) ? std::cerr : std::cout;
219 if (color_) os << color_for(l);
221 if (color_) os << color_reset();
222 if (verbose_format_) {
223 os <<
" " << timestamp() <<
" " << fname <<
":" << line;
225 os <<
" " << text <<
"\n";
228 if (file_.is_open() && l >= file_level_) {
229 file_ << timestamp() <<
" [" <<
level_name(l) <<
"] " << fname <<
":" << line <<
" " << text
Process-wide singleton logger.
void configure_from_env()
Apply NCORR_LOG_LEVEL / NCORR_LOG_FILE / NCORR_LOG_CONSOLE.
void set_file_level(Level l)
void write(Level l, const char *file, int line, const std::string &msg)
Emit a fully-formed message (trailing newlines are trimmed) at l.
Level console_level() const
static Logger & instance()
bool enabled(Level l)
True if a message at l would reach any sink.
void set_console_enabled(bool on)
Enable or disable console output entirely.
void set_console_level(Level l)
bool set_file(const std::string &path)
Open (or replace) the file sink.
void set_verbose_format(bool on)
Include timestamp + source location in console output too (the file sink always includes them).
Lightweight, dependency-free logging facility for CppNCorr.
void set_level(Level l)
Set the console threshold (convenience wrapper).
void set_debug(bool on)
Lower the console threshold to Debug when on is true (used to honour the engine's existing debug flag...
Level level_from_string(const std::string &s, Level fallback=Level::Info)
Parse a level name (case-insensitive): trace, debug, info, warn|warning, error, off.
Level
Severity levels, ordered from most to least verbose.
const char * level_name(Level l)
Short, fixed-width display name for a level (e.g. "INFO ").
bool set_file(const std::string &path)
Convenience: open a log file sink (full Debug detail).