Fix test for bug #32625
[gnash.git] / libbase / log.cpp
blobcd3a7955a36a6b7c2bfead112cb1b2696d78ff47
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 "utility.h"
37 #include "GnashAlgorithm.h"
39 using std::cout;
40 using std::endl;
42 namespace gnash {
44 // Convert each byte into its hex representation
45 std::string
46 hexify(const unsigned char *p, size_t length, bool ascii)
49 const std::vector<unsigned char> bytes(p, p + length);
51 std::ostringstream ss;
53 // For hex output, fill single-digit numbers with a leading 0.
54 if (!ascii) ss << std::hex << std::setfill('0');
56 for (std::vector<unsigned char>::const_iterator i = bytes.begin(),
57 e = bytes.end(); i != e; ++i)
59 if (ascii) {
60 if (std::isprint(*i) || *i == 0xd) {
61 ss << *i;
63 else ss << ".";
65 else {
66 // Not ascii
67 ss << std::setw(2) << static_cast<int>(*i) << " ";
71 return ss.str();
75 std::ostream&
76 timestamp(std::ostream& o)
79 const char fmt[] = "%H:%M:%S";
81 time_t t;
82 char buf[sizeof fmt];
84 std::time(&t);
85 std::strftime(buf, sizeof buf, fmt, std::localtime(&t));
87 static std::map<int, int> threadMap;
88 int tid = get_thread_id();
89 int& htid = threadMap[tid];
90 if (!htid) {
91 htid = threadMap.size();
92 // TODO: notify actual thread id for index
95 o << getpid() << ":" << htid << "] " << buf;
96 return o;
100 LogFile&
101 LogFile::getDefaultInstance()
103 static LogFile o;
104 return o;
107 namespace {
108 LogFile& dbglogfile = LogFile::getDefaultInstance();
111 // boost format functions to process the objects
112 // created by our hundreds of templates
114 void
115 processLog_trace(const boost::format& fmt)
117 dbglogfile.log(N_("TRACE"), fmt.str());
120 void
121 processLog_debug(const boost::format& fmt)
123 if (dbglogfile.getVerbosity() < LogFile::LOG_DEBUG) return;
124 dbglogfile.log(N_("DEBUG"), fmt.str());
127 void
128 processLog_abc(const boost::format& fmt)
130 if (dbglogfile.getVerbosity() < LogFile::LOG_EXTRA) return;
131 dbglogfile.log(N_("ABC"), fmt.str());
134 void
135 processLog_parse(const boost::format& fmt)
137 dbglogfile.log(fmt.str());
140 void
141 processLog_network(const boost::format& fmt)
143 dbglogfile.log(N_("NETWORK"), fmt.str());
146 void
147 processLog_error(const boost::format& fmt)
149 dbglogfile.log(N_("ERROR"), fmt.str());
152 void
153 processLog_unimpl(const boost::format& fmt)
155 dbglogfile.log(N_("UNIMPLEMENTED"), fmt.str());
158 void
159 processLog_security(const boost::format& fmt)
161 dbglogfile.log(N_("SECURITY"), fmt.str());
164 void
165 processLog_swferror(const boost::format& fmt)
167 dbglogfile.log(N_("MALFORMED SWF"), fmt.str());
170 void
171 processLog_aserror(const boost::format& fmt)
173 dbglogfile.log(N_("ACTIONSCRIPT ERROR"), fmt.str());
176 void
177 processLog_action(const boost::format& fmt)
179 bool stamp = dbglogfile.getStamp();
180 dbglogfile.setStamp(false);
181 dbglogfile.log(fmt.str());
182 dbglogfile.setStamp(stamp);
185 void
186 LogFile::log(const std::string& msg)
189 boost::mutex::scoped_lock lock(_ioMutex);
191 if ( !_verbose ) return; // nothing to do if not verbose
193 if (openLogIfNeeded()) {
194 if (_stamp) {
195 _outstream << timestamp << ": " << msg << "\n";
196 } else {
197 _outstream << msg << "\n";
200 else {
201 // log to stdout
202 if (_stamp) {
203 cout << timestamp << " " << msg << endl;
204 } else {
205 cout << msg << endl;
209 if (_listener) {
210 (*_listener)(msg);
214 inline void
215 LogFile::log(const std::string& label, const std::string& msg)
217 log(label + ": " + msg);
220 void
221 LogFile::setLogFilename(const std::string& fname)
223 closeLog();
224 _logFilename = fname;
227 void
228 LogFile::setWriteDisk(bool use)
230 if (!use) closeLog();
231 _write = use;
234 // Default constructor
235 LogFile::LogFile()
237 _verbose(0),
238 _actiondump(false),
239 _parserdump(false),
240 _state(CLOSED),
241 _stamp(true),
242 _write(false),
243 _listener(NULL)
247 LogFile::~LogFile()
249 if (_state == OPEN) closeLog();
252 bool
253 LogFile::openLogIfNeeded()
255 if (_state != CLOSED) return true;
256 if (!_write) return false;
258 if (_logFilename.empty()) _logFilename = DEFAULT_LOGFILE;
260 // TODO: expand ~ to getenv("HOME") !!
262 return openLog(_logFilename);
265 bool
266 LogFile::openLog(const std::string& filespec)
269 // NOTE:
270 // don't need to lock the mutex here, as this method
271 // is intended to be called only by openLogIfNeeded,
272 // which in turn is called by operator<< which is called
273 // by the public log_xxx functions that log themselves
275 if (_state != CLOSED) {
276 cout << "Closing previously opened stream" << endl;
277 _outstream.close();
278 _state = CLOSED;
281 // Append, don't truncate, the log file
282 _outstream.open(filespec.c_str(), std::ios::app|std::ios::out); // ios::out
283 if( _outstream.fail() ) {
284 // Can't use log_error here...
285 cout << "ERROR: can't open debug log file " << filespec <<
286 " for appending." << endl;
287 return false;
290 _filespec = filespec;
291 _state = OPEN;
293 return true;
296 bool
297 LogFile::closeLog()
299 boost::mutex::scoped_lock lock(_ioMutex);
300 if (_state == OPEN) {
301 _outstream.flush();
302 _outstream.close();
304 _state = CLOSED;
306 return true;
309 bool
310 LogFile::removeLog()
312 if (_state == OPEN) {
313 _outstream.close();
316 // Ignore the error, we don't care
317 unlink(_filespec.c_str());
318 _filespec.clear();
320 return true;
323 } // end of gnash namespace
326 // Local Variables:
327 // mode: C++
328 // indent-tabs-mode: t
329 // End: