Upstream tarball 9445
[amule.git] / src / Logger.cpp
blob730a0dcafb9fd2c64ccb6ac0dd22dcccae1583a3
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2005-2008 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.
19 //
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 <sstream>
29 #include <wx/tokenzr.h>
30 #include <wx/wfstream.h>
31 #include <wx/sstream.h>
32 #include <wx/filename.h>
35 DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_LOGLINE)
38 CDebugCategory::CDebugCategory( DebugType type, const wxString& name )
39 : m_name( name ),
40 m_type( type )
42 m_enabled = false;
46 bool CDebugCategory::IsEnabled() const
48 return m_enabled;
52 void CDebugCategory::SetEnabled( bool enabled )
54 m_enabled = enabled;
58 const wxString& CDebugCategory::GetName() const
60 return m_name;
64 DebugType CDebugCategory::GetType() const
66 return m_type;
69 CDebugCategory g_debugcats[] = {
70 CDebugCategory( logGeneral, wxT("General") ),
71 CDebugCategory( logHasher, wxT("Hasher") ),
72 CDebugCategory( logClient, wxT("ED2k Client") ),
73 CDebugCategory( logLocalClient, wxT("Local Client Protocol") ),
74 CDebugCategory( logRemoteClient, wxT("Remote Client Protocol") ),
75 CDebugCategory( logPacketErrors, wxT("Packet Parsing Errors") ),
76 CDebugCategory( logCFile, wxT("CFile") ),
77 CDebugCategory( logFileIO, wxT("FileIO") ),
78 CDebugCategory( logZLib, wxT("ZLib") ),
79 CDebugCategory( logAICHThread, wxT("AICH-Hasher") ),
80 CDebugCategory( logAICHTransfer, wxT("AICH-Transfer") ),
81 CDebugCategory( logAICHRecovery, wxT("AICH-Recovery") ),
82 CDebugCategory( logListenSocket, wxT("ListenSocket") ),
83 CDebugCategory( logCredits, wxT("Credits") ),
84 CDebugCategory( logClientUDP, wxT("ClientUDPSocket") ),
85 CDebugCategory( logDownloadQueue, wxT("DownloadQueue") ),
86 CDebugCategory( logIPFilter, wxT("IPFilter") ),
87 CDebugCategory( logKnownFiles, wxT("KnownFileList") ),
88 CDebugCategory( logPartFile, wxT("PartFiles") ),
89 CDebugCategory( logSHAHashSet, wxT("SHAHashSet") ),
90 CDebugCategory( logServer, wxT("Servers") ),
91 CDebugCategory( logProxy, wxT("Proxy") ),
92 CDebugCategory( logSearch, wxT("Searching") ),
93 CDebugCategory( logServerUDP, wxT("ServerUDP") ),
94 CDebugCategory( logClientKadUDP, wxT("Client Kademlia UDP") ),
95 CDebugCategory( logKadSearch, wxT("Kademlia Search") ),
96 CDebugCategory( logKadRouting, wxT("Kademlia Routing") ),
97 CDebugCategory( logKadIndex, wxT("Kademlia Indexing") ),
98 CDebugCategory( logKadMain, wxT("Kademlia Main Thread") ),
99 CDebugCategory( logKadPrefs, wxT("Kademlia Preferences") ),
100 CDebugCategory( logPfConvert, wxT("PartFileConvert") ),
101 CDebugCategory( logMuleUDP, wxT("MuleUDPSocket" ) ),
102 CDebugCategory( logThreads, wxT("ThreadScheduler" ) ),
103 CDebugCategory( logUPnP, wxT("Universal Plug and Play" ) ),
104 CDebugCategory( logKadUdpFwTester, wxT("Kademlia UDP Firewall Tester") ),
105 CDebugCategory( logKadPacketTracking, wxT("Kademlia Packet Tracking") ),
106 CDebugCategory( logKadEntryTracking, wxT("Kademlia Entry Tracking") )
110 const int categoryCount = sizeof( g_debugcats ) / sizeof( g_debugcats[0] );
114 bool CLogger::IsEnabled( DebugType type )
116 #ifdef __DEBUG__
117 int index = (int)type;
119 if ( index >= 0 && index < categoryCount ) {
120 const CDebugCategory& cat = g_debugcats[ index ];
121 wxASSERT( type == cat.GetType() );
123 return ( cat.IsEnabled() && thePrefs::GetVerbose() );
126 wxFAIL;
127 #endif
128 return false;
132 void CLogger::SetEnabled( DebugType type, bool enabled )
134 int index = (int)type;
136 if ( index >= 0 && index < categoryCount ) {
137 CDebugCategory& cat = g_debugcats[ index ];
138 wxASSERT( type == cat.GetType() );
140 cat.SetEnabled( enabled );
141 } else {
142 wxFAIL;
147 bool CLogger::IsEnabledStdoutLog()
149 return m_StdoutLog;
153 void CLogger::SetEnabledStdoutLog(bool enabled)
155 m_StdoutLog = enabled;
159 void CLogger::AddLogLine(
160 const wxString &file,
161 int line,
162 bool critical,
163 DebugType type,
164 const wxString &str,
165 bool toStdout)
167 wxString msg(str);
168 // handle Debug messages
169 if (type != logStandard) {
170 if (!critical && !IsEnabled(type)) {
171 return;
173 int index = (int)type;
175 if ( index >= 0 && index < categoryCount ) {
176 const CDebugCategory& cat = g_debugcats[ index ];
177 wxASSERT(type == cat.GetType());
179 msg = cat.GetName() + wxT(": ") + msg;
180 } else {
181 wxFAIL;
185 #ifdef __DEBUG__
186 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
187 #endif
189 CLoggingEvent Event(critical, toStdout, msg);
191 // Try to handle events immediatly when possible (to save to file).
192 if (wxThread::IsMain()) {
193 // main thread and log file available: process directly
194 ProcessEvent(Event);
195 } else {
196 // otherwise put to background
197 AddPendingEvent(Event);
202 void CLogger::AddLogLine(
203 const wxString &file,
204 int line,
205 bool critical,
206 DebugType type,
207 const std::ostringstream &msg)
209 int index = (int)type;
211 if ( index >= 0 && index < categoryCount ) {
212 const CDebugCategory& cat = g_debugcats[ index ];
213 wxASSERT(type == cat.GetType());
215 AddLogLine(file, line, critical, logStandard, cat.GetName() + wxT(": ") + char2unicode(msg.str().c_str()));
220 const CDebugCategory& CLogger::GetDebugCategory( int index )
222 wxASSERT( index >= 0 && index < categoryCount );
224 return g_debugcats[ index ];
228 unsigned int CLogger::GetDebugCategoryCount()
230 return categoryCount;
234 bool CLogger::OpenLogfile(const wxString & name)
236 applog = new wxFFileOutputStream(name);
237 bool ret = applog->Ok();
238 if (ret) {
239 FlushApplog();
240 m_LogfileName = name;
241 } else {
242 CloseLogfile();
244 return ret;
248 void CLogger::CloseLogfile()
250 delete applog;
251 applog = NULL;
252 m_LogfileName = wxT("");
256 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
258 // Remove newspace at end
259 wxString bufferline = evt.Message().Strip(wxString::trailing);
261 // Create the timestamp
262 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
263 #ifdef CLIENT_GUI
264 + wxT(" (remote-GUI): ");
265 #else
266 + wxT(": ");
267 #endif
269 // critical lines get a ! prepended, others a blank
270 wxString prefix = evt.IsCritical() ? wxT("!") : wxT(" ");
272 if ( bufferline.IsEmpty() ) {
273 // If it's empty we just write a blank line with no timestamp.
274 DoLine(wxT(" \n"), evt.ToStdout());
275 } else {
276 // Split multi-line messages into individual lines
277 wxStringTokenizer tokens( bufferline, wxT("\n") );
278 while ( tokens.HasMoreTokens() ) {
279 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
280 DoLine(fullline, evt.ToStdout());
286 void CLogger::DoLine(const wxString & line, bool toStdout)
288 ++m_count;
290 // write to logfile
291 m_ApplogBuf += line;
292 FlushApplog();
294 // write to Stdout
295 if (m_StdoutLog || toStdout) {
296 printf("%s", (const char*)unicode2char(line));
298 #ifndef AMULE_DAEMON
299 // write to Listcontrol
300 theApp->AddGuiLogLine(line);
301 #endif
305 void CLogger::FlushApplog()
307 if (applog) { // Wait with output until logfile is actually opened
308 wxStringInputStream stream(m_ApplogBuf);
309 (*applog) << stream;
310 applog->Sync();
311 m_ApplogBuf = wxEmptyString;
315 CLogger theLogger;
317 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
318 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
319 END_EVENT_TABLE()
322 CLoggerTarget::CLoggerTarget()
327 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
329 // prevent infinite recursion
330 static bool recursion = false;
331 if (recursion) {
332 return;
334 recursion = true;
336 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
338 wxString str(msg);
340 // This is much simpler than manually handling all wx log-types.
341 bool critical = str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "));
343 AddLogLineM(critical, str);
345 recursion = false;
349 CLoggerAccess::CLoggerAccess()
351 m_bufferlen = 4096;
352 m_buffer = new wxCharBuffer(m_bufferlen);
353 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
354 m_pos = 0;
355 m_ready = false;
359 CLoggerAccess::~CLoggerAccess()
361 delete m_buffer;
362 delete m_logfile;
367 // read a line of text from the logfile if available
368 // (can't believe there's no library function for this >:( )
370 bool CLoggerAccess::HasString()
372 while (!m_ready) {
373 int c = m_logfile->GetC();
374 if (c == wxEOF) {
375 break;
377 // check for buffer overrun
378 if (m_pos == m_bufferlen) {
379 m_bufferlen += 1024;
380 m_buffer->extend(m_bufferlen);
382 m_buffer->data()[m_pos++] = c;
383 if (c == '\n') {
384 m_ready = true;
387 return m_ready;
391 bool CLoggerAccess::GetString(wxString & s)
393 if (!HasString()) {
394 return false;
396 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
397 m_pos = 0;
398 m_ready = false;
399 return true;
402 // File_checked_for_headers