Update Wiki URL
[amule.git] / src / Logger.cpp
blob07fd31cba95d622b8a01d3317e896572d011107f
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 //
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
8 // respective authors.
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "Logger.h"
26 #include "amule.h"
27 #include "Preferences.h"
28 #include <common/Macros.h>
29 #include <common/MacrosProgramSpecific.h>
30 #include <sstream>
31 #include <wx/tokenzr.h>
32 #include <wx/wfstream.h>
33 #include <wx/sstream.h>
34 #include <wx/filename.h>
37 DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_LOGLINE)
40 CDebugCategory g_debugcats[] = {
41 CDebugCategory( logGeneral, wxT("General") ),
42 CDebugCategory( logHasher, wxT("Hasher") ),
43 CDebugCategory( logClient, wxT("ED2k Client") ),
44 CDebugCategory( logLocalClient, wxT("Local Client Protocol") ),
45 CDebugCategory( logRemoteClient, wxT("Remote Client Protocol") ),
46 CDebugCategory( logPacketErrors, wxT("Packet Parsing Errors") ),
47 CDebugCategory( logCFile, wxT("CFile") ),
48 CDebugCategory( logFileIO, wxT("FileIO") ),
49 CDebugCategory( logZLib, wxT("ZLib") ),
50 CDebugCategory( logAICHThread, wxT("AICH-Hasher") ),
51 CDebugCategory( logAICHTransfer, wxT("AICH-Transfer") ),
52 CDebugCategory( logAICHRecovery, wxT("AICH-Recovery") ),
53 CDebugCategory( logListenSocket, wxT("ListenSocket") ),
54 CDebugCategory( logCredits, wxT("Credits") ),
55 CDebugCategory( logClientUDP, wxT("ClientUDPSocket") ),
56 CDebugCategory( logDownloadQueue, wxT("DownloadQueue") ),
57 CDebugCategory( logIPFilter, wxT("IPFilter") ),
58 CDebugCategory( logKnownFiles, wxT("KnownFileList") ),
59 CDebugCategory( logPartFile, wxT("PartFiles") ),
60 CDebugCategory( logSHAHashSet, wxT("SHAHashSet") ),
61 CDebugCategory( logServer, wxT("Servers") ),
62 CDebugCategory( logProxy, wxT("Proxy") ),
63 CDebugCategory( logSearch, wxT("Searching") ),
64 CDebugCategory( logServerUDP, wxT("ServerUDP") ),
65 CDebugCategory( logClientKadUDP, wxT("Client Kademlia UDP") ),
66 CDebugCategory( logKadSearch, wxT("Kademlia Search") ),
67 CDebugCategory( logKadRouting, wxT("Kademlia Routing") ),
68 CDebugCategory( logKadIndex, wxT("Kademlia Indexing") ),
69 CDebugCategory( logKadMain, wxT("Kademlia Main Thread") ),
70 CDebugCategory( logKadPrefs, wxT("Kademlia Preferences") ),
71 CDebugCategory( logPfConvert, wxT("PartFileConvert") ),
72 CDebugCategory( logMuleUDP, wxT("MuleUDPSocket" ) ),
73 CDebugCategory( logThreads, wxT("ThreadScheduler" ) ),
74 CDebugCategory( logUPnP, wxT("Universal Plug and Play" ) ),
75 CDebugCategory( logKadUdpFwTester, wxT("Kademlia UDP Firewall Tester") ),
76 CDebugCategory( logKadPacketTracking, wxT("Kademlia Packet Tracking") ),
77 CDebugCategory( logKadEntryTracking, wxT("Kademlia Entry Tracking") ),
78 CDebugCategory( logEC, wxT("External Connect") ),
79 CDebugCategory( logHTTP, wxT("HTTP") ),
80 CDebugCategory( logAsio, wxT("Asio Sockets") )
84 const int categoryCount = itemsof(g_debugcats);
88 #ifdef __DEBUG__
89 bool CLogger::IsEnabled( DebugType type ) const
91 int index = (int)type;
93 if ( index >= 0 && index < categoryCount ) {
94 const CDebugCategory& cat = g_debugcats[ index ];
95 wxASSERT( type == cat.GetType() );
97 return ( cat.IsEnabled() && thePrefs::GetVerbose() );
100 wxFAIL;
101 return false;
103 #endif
106 void CLogger::SetEnabled( DebugType type, bool enabled )
108 int index = (int)type;
110 if ( index >= 0 && index < categoryCount ) {
111 CDebugCategory& cat = g_debugcats[ index ];
112 wxASSERT( type == cat.GetType() );
114 cat.SetEnabled( enabled );
115 } else {
116 wxFAIL;
121 void CLogger::AddLogLine(
122 const wxString& DEBUG_ONLY(file),
123 int DEBUG_ONLY(line),
124 bool critical,
125 DebugType type,
126 const wxString &str,
127 bool toStdout,
128 bool toGUI)
130 wxString msg(str);
131 // handle Debug messages
132 if (type != logStandard) {
133 if (!critical && !IsEnabled(type)) {
134 return;
136 if (!critical && thePrefs::GetVerboseLogfile()) {
137 // print non critical debug messages only to the logfile
138 toGUI = false;
140 int index = (int)type;
142 if ( index >= 0 && index < categoryCount ) {
143 const CDebugCategory& cat = g_debugcats[ index ];
144 wxASSERT(type == cat.GetType());
146 msg = cat.GetName() + wxT(": ") + msg;
147 } else {
148 wxFAIL;
152 #ifdef __DEBUG__
153 if (line) {
154 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
156 #endif
158 if (toGUI && !wxThread::IsMain()) {
159 // put to background
160 CLoggingEvent Event(critical, toStdout, toGUI, msg);
161 AddPendingEvent(Event);
162 } else {
163 // Try to handle events immediatly when possible (to save to file).
164 DoLines(msg, critical, toStdout, toGUI);
169 void CLogger::AddLogLine(
170 const wxString &file,
171 int line,
172 bool critical,
173 DebugType type,
174 const std::ostringstream &msg)
176 AddLogLine(file, line, critical, type, wxString(char2unicode(msg.str().c_str())));
180 const CDebugCategory& CLogger::GetDebugCategory( int index )
182 wxASSERT( index >= 0 && index < categoryCount );
184 return g_debugcats[ index ];
188 unsigned int CLogger::GetDebugCategoryCount()
190 return categoryCount;
194 bool CLogger::OpenLogfile(const wxString & name)
196 applog = new wxFFileOutputStream(name);
197 bool ret = applog->Ok();
198 if (ret) {
199 FlushApplog();
200 m_LogfileName = name;
201 } else {
202 CloseLogfile();
204 return ret;
208 void CLogger::CloseLogfile()
210 delete applog;
211 applog = NULL;
212 m_LogfileName.Clear();
216 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
218 DoLines(evt.Message(), evt.IsCritical(), evt.ToStdout(), evt.ToGUI());
222 void CLogger::DoLines(const wxString & lines, bool critical, bool toStdout, bool toGUI)
224 // Remove newspace at end
225 wxString bufferline = lines.Strip(wxString::trailing);
227 // Create the timestamp
228 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
229 #ifdef CLIENT_GUI
230 + wxT(" (remote-GUI): ");
231 #else
232 + wxT(": ");
233 #endif
235 // critical lines get a ! prepended, ordinary lines a blank
236 // logfile-only lines get a . to prevent transmission on EC
237 wxString prefix = !toGUI ? wxT(".") : (critical ? wxT("!") : wxT(" "));
239 if ( bufferline.IsEmpty() ) {
240 // If it's empty we just write a blank line with no timestamp.
241 DoLine(wxT(" \n"), toStdout, toGUI);
242 } else {
243 // Split multi-line messages into individual lines
244 wxStringTokenizer tokens( bufferline, wxT("\n") );
245 while ( tokens.HasMoreTokens() ) {
246 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
247 DoLine(fullline, toStdout, toGUI);
253 void CLogger::DoLine(const wxString & line, bool toStdout, bool GUI_ONLY(toGUI))
256 wxMutexLocker lock(m_lineLock);
257 ++m_count;
259 // write to logfile
260 m_ApplogBuf += line;
261 FlushApplog();
263 // write to Stdout
264 if (m_StdoutLog || toStdout) {
265 printf("%s", (const char*)unicode2char(line));
268 #ifndef AMULE_DAEMON
269 // write to Listcontrol
270 if (toGUI) {
271 theApp->AddGuiLogLine(line);
273 #endif
277 void CLogger::EmergencyLog(const wxString &message, bool closeLog)
279 fprintf(stderr, "%s", (const char*)unicode2char(message));
280 m_ApplogBuf += message;
281 FlushApplog();
282 if (closeLog && applog) {
283 applog->Close();
284 applog = NULL;
289 void CLogger::FlushApplog()
291 if (applog) { // Wait with output until logfile is actually opened
292 wxStringInputStream stream(m_ApplogBuf);
293 (*applog) << stream;
294 applog->Sync();
295 m_ApplogBuf.Clear();
299 CLogger theLogger;
301 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
302 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
303 END_EVENT_TABLE()
306 CLoggerTarget::CLoggerTarget()
310 #if wxCHECK_VERSION(2, 9, 0)
311 void CLoggerTarget::DoLogText(const wxString &msg)
313 // prevent infinite recursion
314 static bool recursion = false;
315 if (recursion) {
316 return;
318 recursion = true;
320 // This is much simpler than manually handling all wx log-types.
321 if (msg.StartsWith(_("ERROR: ")) || msg.StartsWith(_("WARNING: "))) {
322 AddLogLineC(msg);
323 } else {
324 AddLogLineN(msg);
327 recursion = false;
329 #else
330 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
332 // prevent infinite recursion
333 static bool recursion = false;
334 if (recursion) {
335 return;
337 recursion = true;
339 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
341 wxString str(msg);
343 // This is much simpler than manually handling all wx log-types.
344 // cppcheck-suppress duplicateBranch
345 if (str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "))) {
346 AddLogLineC(str);
347 } else {
348 AddLogLineN(str);
351 recursion = false;
353 #endif
355 CLoggerAccess::CLoggerAccess()
357 m_bufferlen = 4096;
358 m_buffer = new wxCharBuffer(m_bufferlen);
359 m_logfile = NULL;
360 Reset();
364 void CLoggerAccess::Reset()
366 delete m_logfile;
367 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
368 m_pos = 0;
369 m_ready = false;
373 CLoggerAccess::~CLoggerAccess()
375 delete m_buffer;
376 delete m_logfile;
381 // read a line of text from the logfile if available
382 // (can't believe there's no library function for this >:( )
384 bool CLoggerAccess::HasString()
386 while (!m_ready) {
387 int c = m_logfile->GetC();
388 if (c == wxEOF) {
389 break;
391 // check for buffer overrun
392 if (m_pos == m_bufferlen) {
393 m_bufferlen += 1024;
394 m_buffer->extend(m_bufferlen);
396 m_buffer->data()[m_pos++] = c;
397 if (c == '\n') {
398 if (m_buffer->data()[0] == '.') {
399 // Log-only line, skip
400 m_pos = 0;
401 } else {
402 m_ready = true;
406 return m_ready;
410 bool CLoggerAccess::GetString(wxString & s)
412 if (!HasString()) {
413 return false;
415 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
416 m_pos = 0;
417 m_ready = false;
418 return true;
421 // Functions for EC logging
422 bool ECLogIsEnabled()
424 return theLogger.IsEnabled(logEC);
427 void DoECLogLine(const wxString &line)
429 // without file/line
430 theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false);
433 // File_checked_for_headers