Revert "disable logging if configured that way"
[gnash.git] / libbase / log.cpp
bloba12124d6ff3427874158cae82c7d0ea803313464
1 // log.cpp: Message logging functions, for gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "log.h"
23 #include <ctime>
24 #include <cctype>
25 #include <cstring>
26 #include <iostream>
27 #include <map>
28 #include <sstream>
29 #include <fstream>
30 #include <iomanip>
31 #include <string>
32 #include <boost/format.hpp>
34 #include <unistd.h> // for getpid
36 #include "GnashAlgorithm.h"
37 #include "ClockTime.h"
39 using std::cout;
40 using std::endl;
42 namespace {
43 // TODO: drop this and use boost::this_thread::id instead.
44 inline unsigned long int /* pthread_t */ get_thread_id();
47 namespace gnash {
49 // Convert each byte into its hex representation
50 std::string
51 hexify(const unsigned char *p, size_t length, bool ascii)
54 const std::vector<unsigned char> bytes(p, p + length);
56 std::ostringstream ss;
58 // For hex output, fill single-digit numbers with a leading 0.
59 if (!ascii) ss << std::hex << std::setfill('0');
61 for (std::vector<unsigned char>::const_iterator i = bytes.begin(),
62 e = bytes.end(); i != e; ++i)
64 if (ascii) {
65 if (std::isprint(*i) || *i == 0xd) {
66 ss << *i;
68 else ss << ".";
70 else {
71 // Not ascii
72 ss << std::setw(2) << static_cast<int>(*i) << " ";
76 return ss.str();
80 LogFile&
81 LogFile::getDefaultInstance()
83 static LogFile o;
84 return o;
88 namespace {
90 LogFile& dbglogfile = LogFile::getDefaultInstance();
92 struct Timestamp {
93 boost::uint64_t startTicks;
94 std::map<int, int> threadMap;
95 Timestamp() : startTicks(clocktime::getTicks()) {}
98 std::ostream& operator<< (std::ostream& o, Timestamp& t)
100 int tid = get_thread_id();
101 int& htid = t.threadMap[tid];
102 if (!htid) {
103 htid = t.threadMap.size();
104 // TODO: notify actual thread id for index
107 boost::uint64_t diff = clocktime::getTicks() - t.startTicks;
108 // should we split in seconds/ms ?
109 o << getpid() << ":" << htid << "] " << diff;
111 return o;
115 Timestamp timestamp;
119 // boost format functions to process the objects
120 // created by our hundreds of templates
122 void
123 processLog_trace(const boost::format& fmt)
125 dbglogfile.log(N_("TRACE"), fmt.str());
128 void
129 processLog_debug(const boost::format& fmt)
131 if (dbglogfile.getVerbosity() < LogFile::LOG_DEBUG) return;
132 dbglogfile.log(N_("DEBUG"), fmt.str());
135 void
136 processLog_abc(const boost::format& fmt)
138 if (dbglogfile.getVerbosity() < LogFile::LOG_EXTRA) return;
139 dbglogfile.log(N_("ABC"), fmt.str());
142 void
143 processLog_parse(const boost::format& fmt)
145 dbglogfile.log(fmt.str());
148 void
149 processLog_network(const boost::format& fmt)
151 dbglogfile.log(N_("NETWORK"), fmt.str());
154 void
155 processLog_error(const boost::format& fmt)
157 dbglogfile.log(N_("ERROR"), fmt.str());
160 void
161 processLog_unimpl(const boost::format& fmt)
163 dbglogfile.log(N_("UNIMPLEMENTED"), fmt.str());
166 void
167 processLog_security(const boost::format& fmt)
169 dbglogfile.log(N_("SECURITY"), fmt.str());
172 void
173 processLog_swferror(const boost::format& fmt)
175 dbglogfile.log(N_("MALFORMED SWF"), fmt.str());
178 void
179 processLog_aserror(const boost::format& fmt)
181 dbglogfile.log(N_("ACTIONSCRIPT ERROR"), fmt.str());
184 void
185 processLog_action(const boost::format& fmt)
187 bool stamp = dbglogfile.getStamp();
188 dbglogfile.setStamp(false);
189 dbglogfile.log(fmt.str());
190 dbglogfile.setStamp(stamp);
193 void
194 LogFile::log(const std::string& msg)
197 boost::mutex::scoped_lock lock(_ioMutex);
199 if ( !_verbose ) return; // nothing to do if not verbose
201 if (openLogIfNeeded()) {
202 if (_stamp) {
203 _outstream << timestamp << ": " << msg << "\n";
204 } else {
205 _outstream << msg << "\n";
208 else {
209 // log to stdout
210 if (_stamp) {
211 cout << timestamp << " " << msg << endl;
212 } else {
213 cout << msg << endl;
217 if (_listener) {
218 (*_listener)(msg);
222 inline void
223 LogFile::log(const std::string& label, const std::string& msg)
225 log(label + ": " + msg);
228 void
229 LogFile::setLogFilename(const std::string& fname)
231 closeLog();
232 _logFilename = fname;
235 void
236 LogFile::setWriteDisk(bool use)
238 if (!use) closeLog();
239 _write = use;
242 // Default constructor
243 LogFile::LogFile()
245 _verbose(0),
246 _actiondump(false),
247 _parserdump(false),
248 _state(CLOSED),
249 _stamp(true),
250 _write(false),
251 _listener(NULL)
255 LogFile::~LogFile()
257 if (_state == OPEN) closeLog();
260 bool
261 LogFile::openLogIfNeeded()
263 if (_state != CLOSED) return true;
264 if (!_write) return false;
266 if (_logFilename.empty()) _logFilename = DEFAULT_LOGFILE;
268 // TODO: expand ~ to getenv("HOME") !!
270 return openLog(_logFilename);
273 bool
274 LogFile::openLog(const std::string& filespec)
277 // NOTE:
278 // don't need to lock the mutex here, as this method
279 // is intended to be called only by openLogIfNeeded,
280 // which in turn is called by operator<< which is called
281 // by the public log_xxx functions that log themselves
283 if (_state != CLOSED) {
284 cout << "Closing previously opened stream" << endl;
285 _outstream.close();
286 _state = CLOSED;
289 // Append, don't truncate, the log file
290 _outstream.open(filespec.c_str(), std::ios::app|std::ios::out); // ios::out
291 if( _outstream.fail() ) {
292 // Can't use log_error here...
293 cout << "ERROR: can't open debug log file " << filespec <<
294 " for appending." << endl;
295 return false;
298 _filespec = filespec;
299 _state = OPEN;
301 return true;
304 bool
305 LogFile::closeLog()
307 boost::mutex::scoped_lock lock(_ioMutex);
308 if (_state == OPEN) {
309 _outstream.flush();
310 _outstream.close();
312 _state = CLOSED;
314 return true;
317 bool
318 LogFile::removeLog()
320 if (_state == OPEN) {
321 _outstream.close();
324 // Ignore the error, we don't care
325 unlink(_filespec.c_str());
326 _filespec.clear();
328 return true;
331 } // end of gnash namespace
333 /// Used in logging.
334 #ifdef HAVE_PTHREADS
335 #include <pthread.h>
336 #else
337 # ifdef _WIN32
338 extern "C" unsigned long int /* DWORD WINAPI */ GetCurrentThreadId();
339 # else
340 #include <sys/types.h>
341 #include <unistd.h>
342 # endif
343 #endif
345 namespace {
347 inline unsigned long int /* pthread_t */ get_thread_id(void)
349 #ifdef HAVE_PTHREADS
350 # ifdef __APPLE_CC__
351 return reinterpret_cast<unsigned long int>(pthread_self());
352 # else
353 // This isn't a proper style C++ cast, but FreeBSD has a problem with
354 // static_cast for this as pthread_self() returns a pointer. We can
355 // use that too, this ID is only used for the log file to keep output
356 // from seperare threads clear.
357 # ifdef _WIN32
358 return GetCurrentThreadId();
359 #else
360 return (unsigned long int)pthread_self();
361 #endif
362 # endif
363 #else
364 # ifdef _WIN32
365 return GetCurrentThreadId();
366 # else
367 return static_cast<unsigned long int>(getpid());
368 # endif
369 #endif
373 } // anonymous namespace
375 // Local Variables:
376 // mode: C++
377 // indent-tabs-mode: t
378 // End: