Loading...
Searching...
No Matches
log.h
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 Artificial Intelligence Techniques, S.L. and Roberto López González
3
4#pragma once
5
6#include <functional>
7#include <ostream>
8#include <sstream>
9#include <string_view>
10
12{
13
14// Everything the library says goes through here: training progress,
15// warnings, backend diagnostics. By default it looks exactly as it always
16// has -- information on standard output, warnings and errors on standard
17// error -- and the two things a library must offer besides that are a way
18// to silence it and a way to redirect it.
19//
20// logging::set_level(logging::Level::Silent); // a library that says nothing
21// logging::set_sink([](logging::Level, std::string_view text) { my_logger(text); });
22// OPENNN_LOG_LEVEL=warning // the environment sets the default
23//
24// Text is passed to the sink verbatim, newlines included, so redirecting it
25// changes where it goes and not what it says.
26enum class Level { Silent = 0, Error = 1, Warning = 2, Info = 3, Debug = 4 };
27
28Level level() noexcept;
29void set_level(Level) noexcept;
30bool enabled(Level) noexcept;
31
32using Sink = std::function<void(Level, std::string_view)>;
33// Callbacks may run concurrently and must synchronize their own state. Replacing
34// a sink affects subsequent writes; an in-flight callback keeps its sink alive.
35// Recursive logging from a callback is discarded, and callback exceptions are
36// contained so diagnostics cannot terminate the application.
37// User captures are released at process shutdown; later exit diagnostics use
38// the default sink, retaining the configured level. The default sink flushes
39// each message, including interactive prompts and progress updates.
40void set_sink(Sink); // an empty sink restores the default streams
41void write(Level, std::string_view);
42
43// A line under construction: `logging::info() << "Epoch " << epoch << "\n";`.
44// Whatever is streamed into it is handed to the sink when the temporary
45// dies, at the end of the full expression, or dropped entirely when the level
46// is off -- the formatting work is skipped too, since the stream is a no-op.
47class Line
48{
49public:
50 explicit Line(Level level) noexcept : level_(level), on_(enabled(level)) {}
51 Line(const Line&) = delete;
52 Line& operator=(const Line&) = delete;
53 ~Line() noexcept { if (on_) write(level_, buffer_.view()); }
54
55 template<typename T>
56 Line& operator<<(const T& value)
57 {
58 if (on_) buffer_ << value;
59 return *this;
60 }
61
62 // Manipulators: std::endl, std::fixed, std::setprecision(...) and the like.
63 Line& operator<<(std::ostream& (*manipulator)(std::ostream&))
64 {
65 if (on_) buffer_ << manipulator;
66 return *this;
67 }
68
69private:
70 Level level_;
71 bool on_;
72 std::ostringstream buffer_;
73};
74
75inline Line error() { return Line(Level::Error); }
76inline Line warning() { return Line(Level::Warning); }
77inline Line info() { return Line(Level::Info); }
78inline Line debug() { return Line(Level::Debug); }
79
80}
Definition log.h:48
Line & operator<<(const T &value)
Definition log.h:56
Line & operator<<(std::ostream &(*manipulator)(std::ostream &))
Definition log.h:63
Line(const Line &)=delete
~Line() noexcept
Definition log.h:53
Line(Level level) noexcept
Definition log.h:50
Line & operator=(const Line &)=delete
Definition log.h:12
void set_level(Level) noexcept
Line info()
Definition log.h:77
Level level() noexcept
void write(Level, std::string_view)
std::function< void(Level, std::string_view)> Sink
Definition log.h:32
void set_sink(Sink)
bool enabled(Level) noexcept
Level
Definition log.h:26
@ Warning
Definition log.h:26
@ Silent
Definition log.h:26
@ Info
Definition log.h:26
@ Error
Definition log.h:26
@ Debug
Definition log.h:26
Line warning()
Definition log.h:76
Line debug()
Definition log.h:78
Line error()
Definition log.h:75