- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

glogoutput.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 // glogoutput.cpp
19 //
20
21 #include "gdef.h"
22 #include "glogoutput.h"
23 #include "glimits.h"
24 #include <sstream>
25 #include <string>
26 #include <ctime>
27 #include <cstdlib>
28 #include <fstream>
29
30 // (note that the implementation here has to be reentrant and using only the standard runtime library)
31
32 G::LogOutput::LogOutput( const std::string & prefix , bool enabled , bool summary_log ,
33 bool verbose_log , bool debug , bool level , bool timestamp , bool strip ,
34 bool use_syslog , const std::string & stderr_replacement , SyslogFacility syslog_facility ) :
35 m_prefix(prefix) ,
36 m_enabled(enabled) ,
37 m_summary_log(summary_log) ,
38 m_verbose_log(verbose_log) ,
39 m_debug(debug) ,
40 m_level(level) ,
41 m_strip(strip) ,
42 m_syslog(use_syslog) ,
43 m_std_err(err(stderr_replacement)) ,
44 m_facility(syslog_facility) ,
45 m_time(0) ,
46 m_timestamp(timestamp) ,
47 m_handle(0) ,
48 m_handle_set(false)
49 {
50 if( pthis() == NULL )
51 pthis() = this ;
52 init() ;
53 }
54
55 G::LogOutput::LogOutput( bool enabled_and_summary , bool verbose_and_debug ,
56 const std::string & stderr_replacement ) :
57 m_enabled(enabled_and_summary) ,
58 m_summary_log(enabled_and_summary) ,
59 m_verbose_log(verbose_and_debug) ,
60 m_debug(verbose_and_debug) ,
61 m_level(false) ,
62 m_strip(false) ,
63 m_syslog(false) ,
64 m_std_err(err(stderr_replacement)) ,
65 m_facility(User) ,
66 m_time(0) ,
67 m_timestamp(false) ,
68 m_handle(0) ,
69 m_handle_set(false)
70 {
71 if( pthis() == NULL )
72 pthis() = this ;
73 init() ;
74 }
75
76 std::ostream & G::LogOutput::err( const std::string & path_in )
77 {
78 if( !path_in.empty() )
79 {
80 std::string path = path_in ;
81 std::string::size_type pos = path.find("%d") ;
82 if( pos != std::string::npos )
83 path.replace( pos , 2U , dateString() ) ;
84
85 static std::ofstream file( path.c_str() , std::ios_base::out | std::ios_base::app ) ;
86 // ignore errors
87 return file ;
88 }
89 else
90 {
91 return std::cerr ;
92 }
93 }
94
95 G::LogOutput::~LogOutput()
96 {
97 if( pthis() == this )
98 pthis() = NULL ;
99 cleanup() ;
100 }
101
102 G::LogOutput * & G::LogOutput::pthis()
103 {
104 static G::LogOutput * p = NULL ;
105 return p ;
106 }
107
108 G::LogOutput * G::LogOutput::instance()
109 {
110 return pthis() ;
111 }
112
113 bool G::LogOutput::enable( bool enabled )
114 {
115 bool was_enabled = m_enabled ;
116 m_enabled = enabled ;
117 return was_enabled ;
118 }
119
120 void G::LogOutput::output( Log::Severity severity , const char * file , int line , const std::string & text )
121 {
122 if( instance() != NULL )
123 instance()->doOutput( severity , file , line , text ) ;
124 }
125
126 void G::LogOutput::doOutput( Log::Severity severity , const char * /* file */ , int /* line */ , const std::string & text )
127 {
128 // decide what to do
129 bool do_output = m_enabled ;
130 if( severity == Log::s_Debug )
131 do_output = m_enabled && m_debug ;
132 else if( severity == Log::s_LogSummary )
133 do_output = m_enabled && m_summary_log ;
134 else if( severity == Log::s_LogVerbose )
135 do_output = m_enabled && m_verbose_log ;
136
137 if( do_output )
138 {
139 // allocate a buffer
140 const size_type limit = static_cast<size_type>(limits::log) ;
141 std::string buffer ;
142 buffer.reserve( (text.length()>limit?limit:text.length()) + 40U ) ;
143
144 // add the preamble to tbe buffer
145 std::string::size_type text_pos = 0U ;
146 if( m_prefix.length() )
147 {
148 buffer.append( m_prefix ) ;
149 buffer.append( ": " ) ;
150 }
151 if( m_timestamp )
152 buffer.append( timestampString() ) ;
153 if( m_level )
154 buffer.append( levelString(severity) ) ;
155 if( m_strip )
156 {
157 text_pos = text.find(' ') ;
158 if( text_pos == std::string::npos || (text_pos+1U) == text.length() )
159 text_pos = 0U ;
160 else
161 text_pos++ ;
162 }
163
164 // add the text to the buffer, with a sanity limit
165 size_type text_len = text.length() - text_pos ;
166 bool limited = text_len > limit ;
167 text_len = text_len > limit ? limit : text_len ;
168 buffer.append( text , text_pos , text_len ) ;
169 if( limited )
170 buffer.append( " ..." ) ;
171
172 // last ditch removal of ansi escape sequences
173 while( buffer.find('\033') != std::string::npos )
174 buffer[buffer.find('\033')] = '.' ;
175
176 // do the actual output in an o/s-specific manner
177 rawOutput( m_std_err , severity , buffer ) ;
178 }
179 }
180
181 void G::LogOutput::onAssert()
182 {
183 // no-op
184 }
185
186 std::string G::LogOutput::timestampString()
187 {
188 // use a data member buffer to optimise away calls to localtime() and strftime()
189 std::time_t now = std::time(NULL) ;
190 if( m_time == 0 || m_time != now )
191 {
192 m_time = now ;
193 static struct std::tm zero_broken_down_time ;
194 struct std::tm broken_down_time = zero_broken_down_time ;
195 getLocalTime( m_time , &broken_down_time ) ;
196 m_time_buffer[0] = '\0' ;
197 std::strftime( m_time_buffer, sizeof(m_time_buffer)-1U, "%Y" "%m" "%d." "%H" "%M" "%S: ", &broken_down_time ) ;
198 m_time_buffer[sizeof(m_time_buffer)-1U] = '\0' ;
199 }
200 return std::string(m_time_buffer) ;
201 }
202
203 std::string G::LogOutput::dateString()
204 {
205 static struct std::tm zero_broken_down_time ;
206 struct std::tm broken_down_time = zero_broken_down_time ;
207 getLocalTime( std::time(NULL) , &broken_down_time ) ;
208 char buffer[10] = { 0 } ;
209 std::strftime( buffer , sizeof(buffer)-1U , "%Y" "%m" "%d" , &broken_down_time ) ;
210 buffer[sizeof(buffer)-1U] = '\0' ;
211 return std::string( buffer ) ;
212 }
213
214 std::string G::LogOutput::fileAndLine( const char * file , int line )
215 {
216 if( file != NULL )
217 {
218 std::string basename( file ) ;
219 std::string::size_type slash_pos = basename.find_last_of( "/\\" ) ;
220 if( slash_pos != std::string::npos && (slash_pos+1U) < basename.length() )
221 basename.erase( 0U , slash_pos+1U ) ;
222 return basename + "(" + itoa(line) + "): " ;
223 }
224 else
225 {
226 return std::string() ;
227 }
228 }
229
230 void G::LogOutput::assertion( const char * file , int line , bool test , const std::string & test_string )
231 {
232 if( !test )
233 {
234 if( instance() )
235 instance()->doAssertion( file , line , test_string ) ;
236 else
237 std::cerr << "assertion error: " << file << "(" << line << "): " << test_string << std::endl ;
238 halt() ;
239 }
240 }
241
242 void G::LogOutput::doAssertion( const char * file , int line , const std::string & test_string )
243 {
244 // forward to derived classes -- overrides may safely re-enter this
245 // method since all code in this class is re-entrant
246 onAssert() ;
247
248 rawOutput( m_std_err , Log::s_Assertion ,
249 std::string() + "Assertion error: " + fileAndLine(file,line) + test_string ) ;
250 }
251
252 void G::LogOutput::halt()
253 {
254 std::abort() ;
255 }
256
257 std::string G::LogOutput::levelString( Log::Severity s )
258 {
259 if( s == Log::s_Debug ) return "debug: " ;
260 else if( s == Log::s_LogSummary ) return "info: " ;
261 else if( s == Log::s_LogVerbose ) return "info: " ;
262 else if( s == Log::s_Warning ) return "warning: " ;
263 else if( s == Log::s_Error ) return "error: " ;
264 else if( s == Log::s_Assertion ) return "fatal: " ;
265 return std::string() ;
266 }
267
268 std::string G::LogOutput::itoa( int n_ )
269 {
270 // diy implementation for speed and portability
271 if( n_ < 0 ) return std::string(1U,'0') ;
272 char buffer[20] = { '0' , '\0' } ;
273 unsigned int buffer_size = sizeof(buffer) ;
274 unsigned int n = static_cast<unsigned int>(n_) ;
275 n %= 1000000U ;
276 bool zero = n == 0U ;
277 char * p = buffer + buffer_size - 1U ;
278 for( *p-- = '\0' ; n > 0U ; --p , n /= 10U )
279 *p = static_cast<char>( '0' + (n % 10U) ) ;
280 return zero ? buffer : (p+1U) ;
281 }
282
G::LogOutput::enable
bool enable(bool enabled=true)
Enables or disables output. Returns the previous setting.
Definition: glogoutput.cpp:113
G::limits::log
Definition: glimits.h:43
G::Log::s_Debug
Definition: glog.h:53
G::LogOutput::SyslogFacility
SyslogFacility
Definition: glogoutput.h:44
G::Log::s_LogVerbose
Definition: glog.h:53
G::LogOutput::instance
static LogOutput * instance()
Returns a pointer to the controlling LogOutput object.
Definition: glogoutput.cpp:108
G::LogOutput::LogOutput
LogOutput(const std::string &prefix, bool output, bool with_logging, bool with_verbose_logging, bool with_debug, bool with_level, bool with_timestamp, bool strip_context, bool use_syslog, const std::string &stderr_replacement=std::string(), SyslogFacility syslog_facility=User)
Constructor.
Definition: glogoutput.cpp:32
md5::size_type
std::string::size_type size_type
A std::size_t type.
Definition: md5.h:43
G::Log::s_LogSummary
Definition: glog.h:53
G::LogOutput::assertion
static void assertion(const char *file, int line, bool test, const std::string &)
Makes an assertion check (regardless of any LogOutput object).
Definition: glogoutput.cpp:230
G::LogOutput::onAssert
virtual void onAssert()
Called during an assertion failure.
Definition: glogoutput.cpp:181
G::Log::s_Error
Definition: glog.h:53
glogoutput.h
G::Log::s_Assertion
Definition: glog.h:53
G::LogOutput::~LogOutput
virtual ~LogOutput()
Destructor.
Definition: glogoutput.cpp:95
glimits.h
G::Log::s_Warning
Definition: glog.h:53
G::LogOutput::output
static void output(G::Log::Severity, const char *file, int line, const std::string &)
Generates output if there is an existing LogOutput object which is enabled.
Definition: glogoutput.cpp:120
G::Log::Severity
Severity
Definition: glog.h:53
G::LogOutput
Controls and implements low-level logging output, as used by the Log interface.
Definition: glogoutput.h:41