E-MailRelay
glogoutput.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file glogoutput.h
19///
20
21#ifndef G_LOG_OUTPUT_H
22#define G_LOG_OUTPUT_H
23
24#include "gdef.h"
25#include "glog.h"
26#include "glogstream.h"
27#include "gprocess.h"
28#include "gexception.h"
29#include "gstringview.h"
30#include <string>
31#include <vector>
32#include <fstream>
33#include <ctime>
34#include <array>
35#include <utility>
36
37namespace G
38{
39 class LogOutput ;
40}
41
42//| \class G::LogOutput
43/// Controls and implements low-level logging output, as used by G::Log.
44///
45/// Applications should instantiate a LogOutput object in main() to
46/// enable and configure log output.
47///
48/// The implementation uses a file descriptor for osoutput() rather than
49/// a stream because windows file-sharing options are not accessible
50/// when building with mingw streams, and to avoid double buffering.
51///
52/// \see G::Log
53///
55{
56public:
57 G_EXCEPTION( LogFileError , tx("cannot open log file") ) ;
58 G_EXCEPTION( EventLogError , tx("cannot access the system event log") ) ;
59
60 enum class SyslogFacility
61 {
62 User ,
63 Daemon ,
64 Mail ,
65 Cron ,
66 Local0 ,
67 Local1 ,
68 Local2 ,
69 Local3 ,
70 Local4 ,
71 Local5 ,
72 Local6 ,
73 Local7
74 } ;
75
76 struct Config /// A configuration structure for G::LogOutput.
77 {
78 bool m_output_enabled {false} ;
79 bool m_summary_info {false} ;
80 bool m_verbose_info {false} ;
81 bool m_more_verbose_info {false} ;
82 bool m_debug {false} ;
83 bool m_with_level {false} ;
84 bool m_with_timestamp {false} ;
85 bool m_with_context {false} ;
86 bool m_strip {false} ; // strip first word
87 bool m_quiet_stderr {false} ;
88 bool m_use_syslog {false} ;
89 bool m_allow_bad_syslog {false} ;
90 bool m_stdout {false} ;
91 SyslogFacility m_facility {SyslogFacility::User} ;
92 Process::Umask::Mode m_umask {Process::Umask::Mode::NoChange} ;
93 Config() ;
94 Config & set_output_enabled( bool value = true ) ;
95 Config & set_summary_info( bool value = true ) ;
96 Config & set_verbose_info( bool value = true ) ;
97 Config & set_more_verbose_info( bool value = true ) ;
98 Config & set_debug( bool value = true ) ;
99 Config & set_with_level( bool value = true ) ;
100 Config & set_with_timestamp( bool value = true ) ;
101 Config & set_with_context( bool value = true ) ;
102 Config & set_strip( bool value = true ) ;
103 Config & set_quiet_stderr( bool value = true ) ;
104 Config & set_use_syslog( bool value = true ) ;
105 Config & set_allow_bad_syslog( bool value = true ) ;
106 Config & set_facility( SyslogFacility ) ;
107 Config & set_umask( Process::Umask::Mode ) ;
108 Config & set_stdout( bool value = true ) ;
109 } ;
110
111 LogOutput( const std::string & exename , const Config & config ,
112 const std::string & filename = {} ) ;
113 ///< Constructor. If there is no LogOutput object, or if
114 ///< 'config.output_enabled' is false, then there is no
115 ///< output at all except for assertions to stderr in a
116 ///< debug build. Otherwise at least warning and error
117 ///< messages are generated.
118 ///<
119 ///< If 'config.summary_info' is true then log-summary
120 ///< messages are output. If 'config.verbose_info' is true
121 ///< then log-verbose messages are output. If 'config.with_debug'
122 ///< is true then debug messages will also be generated (but
123 ///< only if compiled in).
124 ///<
125 ///< If an output filename is given it has "%d" and "%h"
126 ///< substitutions applied and it is then opened or created
127 ///< before this constructor returns. If no filename is given
128 ///< then logging is sent to the standard error stream; the user
129 ///< is free to close stderr and reopen it onto /dev/null if
130 ///< only syslog logging is required.
131 ///<
132 ///< More than one LogOutput object may be created, but only
133 ///< the first one controls output.
134
135 explicit LogOutput( bool output_enabled_and_summary_info ,
136 bool verbose_info_and_debug = true ,
137 const std::string & filename = {} ) ;
138 ///< Constructor for test programs. Only generates output if the
139 ///< first parameter is true. Never uses syslog.
140
141 ~LogOutput() ;
142 ///< Destructor.
143
144 static LogOutput * instance() noexcept ;
145 ///< Returns a pointer to the controlling LogOutput object. Returns
146 ///< nullptr if none.
147
148 Config config() const ;
149 ///< Returns the current configuration.
150
151 void configure( const Config & ) ;
152 ///< Updates the current configuration.
153
154 bool at( Log::Severity ) const noexcept ;
155 ///< Returns true if logging should occur for the given severity level.
156
157 static void context( std::string (*fn)(void*) = nullptr , void * fn_arg = nullptr ) noexcept ;
158 ///< Sets a functor that is used to provide a context string for
159 ///< every log line, if configured. The functor should return
160 ///< the context string with trailing punctuation, typically
161 ///< colon and space.
162
163 static void * contextarg() noexcept ;
164 ///< Returns the functor argument as set by the last call to context().
165
166 static LogStream & start( Log::Severity , const char * file , int line ) noexcept ;
167 ///< Prepares the internal ostream for a new log line and returns a
168 ///< reference to it. The caller should stream out the rest of the log
169 ///< line into the ostream and then call output(). Calls to start() and
170 ///< output() must be strictly in pairs. Returns a pointer to a dummy
171 ///< ostream if there is no LogOutput instance.
172
173 static void output( LogStream & ) noexcept ;
174 ///< Emits the current log line (see start()). Does nothing if there
175 ///< is no LogOutput instance.
176
177 static void assertion( const char * file , int line , bool test , const char * test_string ) ;
178 ///< Performs an assertion check.
179
180 static void assertion( const char * file , int line , void * test , const char * test_string ) ;
181 ///< Performs an assertion check. This overload, using a test on a
182 ///< pointer, is motivated by MSVC warnings.
183
184 static void assertionFailure( const char * file , int line , const char * test_expression ) noexcept ;
185 ///< Reports an assertion failure.
186
187 GDEF_NORETURN_LHS static void assertionAbort() GDEF_NORETURN_RHS ;
188 ///< Aborts the program when an assertion has failed.
189
190 static void register_( const std::string & exe ) ;
191 ///< Registers the given executable as a source of logging.
192 ///< This is called from osinit(), but it might also need to be
193 ///< done as a program installation step with the necessary
194 ///< process permissions.
195
196public:
197 LogOutput( const LogOutput & ) = delete ;
198 LogOutput( LogOutput && ) = delete ;
199 LogOutput & operator=( const LogOutput & ) = delete ;
200 LogOutput & operator=( LogOutput && ) = delete ;
201
202private:
203 void osinit() ;
204 void open( const std::string & , bool ) ;
205 LogStream & start( Log::Severity ) ;
206 void output( LogStream & , int ) ;
207 void osoutput( int , Log::Severity , char * , std::size_t ) ;
208 void oscleanup() const noexcept ;
209 bool updateTime() ;
210 bool updatePath( const std::string & , std::string & ) const ;
211 std::string makePath( const std::string & ) const ;
212 void appendTimeTo( LogStream & ) ;
213 static G::string_view levelString( Log::Severity ) noexcept ;
214 static const char * basename( const char * ) noexcept ;
215
216private:
217 std::string m_exename ;
218 Config m_config ;
219 std::time_t m_time_s{0} ;
220 unsigned int m_time_us{0U} ;
221 std::array<char,17U> m_time_buffer {} ;
222 std::array<char,17U> m_time_change_buffer {} ;
223 HANDLE m_handle{0} ; // windows
224 std::string m_path ; // with %d etc
225 std::string m_real_path ;
226 int m_fd{-1} ;
227 unsigned int m_depth{0U} ;
228 Log::Severity m_severity{Log::Severity::Debug} ;
229 std::size_t m_start_pos{0U} ;
230 std::string (*m_context_fn)(void *){nullptr} ;
231 void * m_context_fn_arg{nullptr} ;
232} ;
233
234inline void G::LogOutput::assertion( const char * file , int line , bool test , const char * test_string )
235{
236 if( !test )
237 {
238 assertionFailure( file , line , test_string ) ;
240 }
241}
242
243inline void G::LogOutput::assertion( const char * file , int line , void * test , const char * test_string )
244{
245 if( !test )
246 {
247 assertionFailure( file , line , test_string ) ;
248 assertionAbort() ;
249 }
250}
251
252#endif
A static interface for daemonising the calling process.
Definition: gdaemon.h:43
Controls and implements low-level logging output, as used by G::Log.
Definition: glogoutput.h:55
static void assertion(const char *file, int line, bool test, const char *test_string)
Performs an assertion check.
Definition: glogoutput.h:234
static GDEF_NORETURN_LHS void assertionAbort() GDEF_NORETURN_RHS
Aborts the program when an assertion has failed.
Definition: glogoutput.cpp:365
static void register_(const std::string &exe)
Registers the given executable as a source of logging.
bool at(Log::Severity) const noexcept
Returns true if logging should occur for the given severity level.
Definition: glogoutput.cpp:179
static LogStream & start(Log::Severity, const char *file, int line) noexcept
Prepares the internal ostream for a new log line and returns a reference to it.
Definition: glogoutput.cpp:193
Config config() const
Returns the current configuration.
Definition: glogoutput.cpp:133
static void * contextarg() noexcept
Returns the functor argument as set by the last call to context().
Definition: glogoutput.cpp:173
static void output(LogStream &) noexcept
Emits the current log line (see start()).
Definition: glogoutput.cpp:208
LogOutput(const std::string &exename, const Config &config, const std::string &filename={})
Constructor.
Definition: glogoutput.cpp:98
~LogOutput()
Destructor.
Definition: glogoutput.cpp:143
void configure(const Config &)
Updates the current configuration.
Definition: glogoutput.cpp:138
static void assertionFailure(const char *file, int line, const char *test_expression) noexcept
Reports an assertion failure.
Definition: glogoutput.cpp:348
static LogOutput * instance() noexcept
Returns a pointer to the controlling LogOutput object.
Definition: glogoutput.cpp:158
static void context(std::string(*fn)(void *)=nullptr, void *fn_arg=nullptr) noexcept
Sets a functor that is used to provide a context string for every log line, if configured.
Definition: glogoutput.cpp:163
Low-level classes.
Definition: garg.h:30
constexpr const char * tx(const char *p)
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84
STL namespace.
A configuration structure for G::LogOutput.
Definition: glogoutput.h:77