]> WPIA git - cassiopeia.git/blob - src/log/logger.hpp
3045365417c2db7c527c61e56dbdc233c981ae7b
[cassiopeia.git] / src / log / logger.hpp
1 #pragma once
2
3 #include <algorithm>
4 #include <iomanip>
5 #include <iostream>
6 #include <string>
7 #include <sstream>
8 #include <vector>
9 #include <fstream>
10
11 namespace logger {
12
13     /**
14      * conv::to_string will be used to convert whatever argument is send
15      * to the logger to a string. If another type shall be supported,
16      * just add the appropriate overload and you can start using it right
17      * away. The default conversion will use a stringstream.
18      */
19     namespace conv {
20         template <typename T>
21         inline std::string to_string( const T& arg ) {
22             std::ostringstream stream;
23             stream << arg;
24             return stream.str();
25         }
26         inline std::string to_string( std::string&& arg ) {
27             return arg;
28         }
29         inline std::string to_string( const std::string& arg ) {
30             return arg;
31         }
32         inline std::string to_string( const char* arg ) {
33             return arg;
34         }
35
36     } // namespace conv
37
38     enum class level {
39         debug, note, warn, error, fatal
40     };
41
42     const auto default_level = level::note;
43
44     struct log_target {
45         log_target( std::ostream& stream, level min_level = default_level ):
46             stream {&stream}, min_level {min_level} {}
47         log_target( std::ofstream& stream, level min_level = default_level ):
48             stream {&stream}, min_level {min_level} {
49             if( !stream.is_open() ) {
50                 throw std::runtime_error {"logfile not open"};
51             }
52         }
53         std::ostream* stream;
54         level min_level;
55     };
56
57     class logger_set;
58     namespace impl {
59         void reassign_stack_pointer( logger_set*& ptr );
60     }
61
62     /**
63      * Provides controll over wether a logger should automatically register itself
64      */
65     enum class auto_register {
66         on, off
67     };
68
69     class logger_set {
70     public:
71         logger_set( std::initializer_list<log_target> lst, auto_register = auto_register::on );
72
73         logger_set( logger_set&& ) noexcept;
74         logger_set& operator=( logger_set && ) noexcept;
75         ~logger_set();
76
77         template<typename... Args>
78         void log( level l, Args&& ... args );
79         template<typename... Args>
80         void logf( level l, const std::string& format, Args&& ... args );
81
82         template<typename... Args>
83         void debug( Args&& ... args );
84         template<typename... Args>
85         void debugf( const std::string& format, Args&& ... args );
86
87         template<typename... Args>
88         void note( Args&& ... args );
89         template<typename... Args>
90         void notef( const std::string& format, Args&& ... args );
91
92         template<typename... Args>
93         void warn( Args&& ... args );
94         template<typename... Args>
95         void warnf( const std::string& format, Args&& ... args );
96
97         template<typename... Args>
98         void error( Args&& ... args );
99         template<typename... Args>
100         void errorf( const std::string& format, Args&& ... args );
101
102         template<typename... Args>
103         void fatal( Args&& ... args );
104         template<typename... Args>
105         void fatalf( const std::string& format, Args&& ... args );
106
107         friend void impl::reassign_stack_pointer( logger_set*& ptr );
108         friend logger_set current_logger_extended( std::initializer_list<log_target> further_targets );
109     private:
110         void log_impl( level l, const std::string& msg );
111
112         std::vector<log_target> m_loggers;
113         logger_set** m_stackpointer = nullptr;
114         level m_min_level;
115     };
116
117     logger_set current_logger_extended( std::initializer_list<log_target> further_targets );
118
119     namespace impl {
120         std::string concat_msg( level l, const std::vector<std::string>& args );
121         std::string format_msg( level l, const std::string&, std::vector<std::string> args );
122         logger_set& active_logger();
123     }
124
125     template <typename... Args>
126     void logger_set::log( level l, Args&& ... data ) {
127         if( l < m_min_level ) {
128             return;
129         }
130
131         log_impl( l, impl::concat_msg( l, {conv::to_string( std::forward<Args>( data ) )...} ) );
132     }
133
134     template <typename... Args>
135     void logger_set::logf( level l, const std::string& format, Args&& ... data ) {
136         if( l < m_min_level ) {
137             return;
138         }
139
140         log_impl( l, impl::format_msg( l, format, {conv::to_string( std::forward<Args>( data ) )...} ) );
141     }
142
143     template <typename... Args>
144     void log( level l, Args&& ... args ) {
145         impl::active_logger().log( l, std::forward<Args>( args )... );
146     }
147     template <typename... Args>
148     void logf( level l, const std::string& format, Args&& ... args ) {
149         impl::active_logger().logf( l, format, std::forward<Args>( args )... );
150     }
151
152     // concat-based methods
153     template <typename... Args>
154     void logger_set::debug( Args&& ... args ) {
155         log( level::debug, std::forward<Args>( args )... );
156     }
157     template <typename... Args>
158     void logger_set::note( Args&& ... args ) {
159         log( level::note, std::forward<Args>( args )... );
160     }
161     template <typename... Args>
162     void logger_set::warn( Args&& ... args ) {
163         log( level::warn, std::forward<Args>( args )... );
164     }
165     template <typename... Args>
166     void logger_set::error( Args&& ... args ) {
167         log( level::error, std::forward<Args>( args )... );
168     }
169     template <typename... Args>
170     void logger_set::fatal( Args&& ... args ) {
171         log( level::fatal, std::forward<Args>( args )... );
172     }
173
174     // format-based methods
175     template <typename... Args>
176     void logger_set::debugf( const std::string& fmt, Args&& ... args ) {
177         logf( level::debug, fmt, std::forward<Args>( args )... );
178     }
179     template <typename... Args>
180     void logger_set::notef( const std::string& fmt, Args&& ... args ) {
181         logf( level::note, fmt, std::forward<Args>( args )... );
182     }
183     template <typename... Args>
184     void logger_set::warnf( const std::string& fmt, Args&& ... args ) {
185         logf( level::warn, fmt, std::forward<Args>( args )... );
186     }
187     template <typename... Args>
188     void logger_set::errorf( const std::string& fmt, Args&& ... args ) {
189         logf( level::error, fmt, std::forward<Args>( args )... );
190     }
191     template <typename... Args>
192     void logger_set::fatalf( const std::string& fmt, Args&& ... args ) {
193         logf( level::fatal, fmt, std::forward<Args>( args )... );
194     }
195
196     // global concat-based
197     template <typename... Args>
198     void debug( Args&& ... args ) {
199         log( level::debug, std::forward<Args>( args )... );
200     }
201     template <typename... Args>
202     void note( Args&& ... args ) {
203         log( level::note, std::forward<Args>( args )... );
204     }
205     template <typename... Args>
206     void warn( Args&& ... args ) {
207         log( level::warn, std::forward<Args>( args )... );
208     }
209     template <typename... Args>
210     void error( Args&& ... args ) {
211         log( level::error, std::forward<Args>( args )... );
212     }
213     template <typename... Args>
214     void fatal( Args&& ... args ) {
215         log( level::fatal, std::forward<Args>( args )... );
216     }
217
218     // global format-based
219     template <typename... Args>
220     void debugf( const std::string& fmt, Args&& ... args ) {
221         logf( level::debug, fmt, std::forward<Args>( args )... );
222     }
223     template <typename... Args>
224     void notef( const std::string& fmt, Args&& ... args ) {
225         logf( level::note, fmt, std::forward<Args>( args )... );
226     }
227     template <typename... Args>
228     void warnf( const std::string& fmt, Args&& ... args ) {
229         logf( level::warn, fmt, std::forward<Args>( args )... );
230     }
231     template <typename... Args>
232     void errorf( const std::string& fmt, Args&& ... args ) {
233         logf( level::error, fmt, std::forward<Args>( args )... );
234     }
235     template <typename... Args>
236     void fatalf( const std::string& fmt, Args&& ... args ) {
237         logf( level::fatal, fmt, std::forward<Args>( args )... );
238     }
239
240 }