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