don't add (LIBLTDL) to LDFLAGS, libltdl is part of libgnashbase.
[gnash.git] / libbase / log.cpp
blob0f89113a50efeb402678fde067802c95905569e5
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_amferror(const boost::format& fmt)
173 dbglogfile.log(N_("MALFORMED AMF"), fmt.str());
176 void
177 processLog_aserror(const boost::format& fmt)
179 dbglogfile.log(N_("ACTIONSCRIPT ERROR"), fmt.str());
182 void
183 processLog_action(const boost::format& fmt)
185 bool stamp = dbglogfile.getStamp();
186 dbglogfile.setStamp(false);
187 dbglogfile.log(fmt.str());
188 dbglogfile.setStamp(stamp);
191 void
192 LogFile::log(const std::string& msg)
195 boost::mutex::scoped_lock lock(_ioMutex);
197 if ( !_verbose ) return; // nothing to do if not verbose
199 if (openLogIfNeeded()) {
200 if (_stamp) {
201 _outstream << timestamp << ": " << msg << "\n";
202 } else {
203 _outstream << msg << "\n";
206 else {
207 // log to stdout
208 if (_stamp) {
209 cout << timestamp << " " << msg << endl;
210 } else {
211 cout << msg << endl;
215 if (_listener) {
216 (*_listener)(msg);
220 inline void
221 LogFile::log(const std::string& label, const std::string& msg)
223 log(label + ": " + msg);
226 void
227 LogFile::setLogFilename(const std::string& fname)
229 closeLog();
230 _logFilename = fname;
233 void
234 LogFile::setWriteDisk(bool use)
236 if (!use) closeLog();
237 _write = use;
240 // Default constructor
241 LogFile::LogFile()
243 _verbose(0),
244 _actiondump(false),
245 _parserdump(false),
246 _state(CLOSED),
247 _stamp(true),
248 _write(false),
249 _listener(NULL)
253 LogFile::~LogFile()
255 if (_state == OPEN) closeLog();
258 bool
259 LogFile::openLogIfNeeded()
261 if (_state != CLOSED) return true;
262 if (!_write) return false;
264 if (_logFilename.empty()) _logFilename = DEFAULT_LOGFILE;
266 // TODO: expand ~ to getenv("HOME") !!
268 return openLog(_logFilename);
271 bool
272 LogFile::openLog(const std::string& filespec)
275 // NOTE:
276 // don't need to lock the mutex here, as this method
277 // is intended to be called only by openLogIfNeeded,
278 // which in turn is called by operator<< which is called
279 // by the public log_xxx functions that log themselves
281 if (_state != CLOSED) {
282 cout << "Closing previously opened stream" << endl;
283 _outstream.close();
284 _state = CLOSED;
287 // Append, don't truncate, the log file
288 _outstream.open(filespec.c_str(), std::ios::app|std::ios::out); // ios::out
289 if( _outstream.fail() ) {
290 // Can't use log_error here...
291 cout << "ERROR: can't open debug log file " << filespec <<
292 " for appending." << endl;
293 return false;
296 _filespec = filespec;
297 _state = OPEN;
299 return true;
302 bool
303 LogFile::closeLog()
305 boost::mutex::scoped_lock lock(_ioMutex);
306 if (_state == OPEN) {
307 _outstream.flush();
308 _outstream.close();
310 _state = CLOSED;
312 return true;
315 bool
316 LogFile::removeLog()
318 if (_state == OPEN) {
319 _outstream.close();
322 // Ignore the error, we don't care
323 unlink(_filespec.c_str());
324 _filespec.clear();
326 return true;
329 } // end of gnash namespace
332 // Local Variables:
333 // mode: C++
334 // indent-tabs-mode: t
335 // End: