Upstream tarball 9401
[amule.git] / src / Logger.cpp
blobf828294a651c176188511b8f608b13e7946c70e0
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 <wx/tokenzr.h>
29 #include <wx/wfstream.h>
30 #include <wx/sstream.h>
31 #include <wx/filename.h>
34 DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_LOGLINE)
37 CDebugCategory::CDebugCategory( DebugType type, const wxString& name )
38 : m_name( name ),
39 m_type( type )
41 m_enabled = false;
45 bool CDebugCategory::IsEnabled() const
47 return m_enabled;
51 void CDebugCategory::SetEnabled( bool enabled )
53 m_enabled = enabled;
57 const wxString& CDebugCategory::GetName() const
59 return m_name;
63 DebugType CDebugCategory::GetType() const
65 return m_type;
68 CDebugCategory g_debugcats[] = {
69 CDebugCategory( logGeneral, wxT("General") ),
70 CDebugCategory( logHasher, wxT("Hasher") ),
71 CDebugCategory( logClient, wxT("ED2k Client") ),
72 CDebugCategory( logLocalClient, wxT("Local Client Protocol") ),
73 CDebugCategory( logRemoteClient, wxT("Remote Client Protocol") ),
74 CDebugCategory( logPacketErrors, wxT("Packet Parsing Errors") ),
75 CDebugCategory( logCFile, wxT("CFile") ),
76 CDebugCategory( logFileIO, wxT("FileIO") ),
77 CDebugCategory( logZLib, wxT("ZLib") ),
78 CDebugCategory( logAICHThread, wxT("AICH-Hasher") ),
79 CDebugCategory( logAICHTransfer, wxT("AICH-Transfer") ),
80 CDebugCategory( logAICHRecovery, wxT("AICH-Recovery") ),
81 CDebugCategory( logListenSocket, wxT("ListenSocket") ),
82 CDebugCategory( logCredits, wxT("Credits") ),
83 CDebugCategory( logClientUDP, wxT("ClientUDPSocket") ),
84 CDebugCategory( logDownloadQueue, wxT("DownloadQueue") ),
85 CDebugCategory( logIPFilter, wxT("IPFilter") ),
86 CDebugCategory( logKnownFiles, wxT("KnownFileList") ),
87 CDebugCategory( logPartFile, wxT("PartFiles") ),
88 CDebugCategory( logSHAHashSet, wxT("SHAHashSet") ),
89 CDebugCategory( logServer, wxT("Servers") ),
90 CDebugCategory( logProxy, wxT("Proxy") ),
91 CDebugCategory( logSearch, wxT("Searching") ),
92 CDebugCategory( logServerUDP, wxT("ServerUDP") ),
93 CDebugCategory( logClientKadUDP, wxT("Client Kademlia UDP") ),
94 CDebugCategory( logKadSearch, wxT("Kademlia Search") ),
95 CDebugCategory( logKadRouting, wxT("Kademlia Routing") ),
96 CDebugCategory( logKadIndex, wxT("Kademlia Indexing") ),
97 CDebugCategory( logKadMain, wxT("Kademlia Main Thread") ),
98 CDebugCategory( logKadPrefs, wxT("Kademlia Preferences") ),
99 CDebugCategory( logPfConvert, wxT("PartFileConvert") ),
100 CDebugCategory( logMuleUDP, wxT("MuleUDPSocket" ) ),
101 CDebugCategory( logThreads, wxT("ThreadScheduler" ) ),
102 CDebugCategory( logUPnP, wxT("Universal Plug and Play" ) ),
103 CDebugCategory( logKadUdpFwTester, wxT("Kademlia UDP Firewall Tester") ),
104 CDebugCategory( logKadPacketTracking, wxT("Kademlia Packet Tracking") ),
105 CDebugCategory( logKadEntryTracking, wxT("Kademlia Entry Tracking") )
109 const int categoryCount = sizeof( g_debugcats ) / sizeof( g_debugcats[0] );
113 bool CLogger::IsEnabled( DebugType type )
115 #ifdef __DEBUG__
116 int index = (int)type;
118 if ( index >= 0 && index < categoryCount ) {
119 const CDebugCategory& cat = g_debugcats[ index ];
120 wxASSERT( type == cat.GetType() );
122 return ( cat.IsEnabled() && thePrefs::GetVerbose() );
125 wxASSERT( false );
126 #endif
127 return false;
131 void CLogger::SetEnabled( DebugType type, bool enabled )
133 int index = (int)type;
135 if ( index >= 0 && index < categoryCount ) {
136 CDebugCategory& cat = g_debugcats[ index ];
137 wxASSERT( type == cat.GetType() );
139 cat.SetEnabled( enabled );
140 } else {
141 wxASSERT( false );
146 bool CLogger::IsEnabledStdoutLog()
148 return m_StdoutLog;
152 void CLogger::SetEnabledStdoutLog(bool enabled)
154 m_StdoutLog = enabled;
158 void CLogger::AddLogLine(
159 const wxString &file,
160 int line,
161 bool critical,
162 DebugType type,
163 const wxString &str,
164 bool toStdout)
166 wxString msg(str);
167 // handle Debug messages
168 if (type != logStandard) {
169 if (!critical && !IsEnabled(type)) {
170 return;
172 int index = (int)type;
174 if ( index >= 0 && index < categoryCount ) {
175 const CDebugCategory& cat = g_debugcats[ index ];
176 wxASSERT(type == cat.GetType());
178 msg = cat.GetName() + wxT(": ") + msg;
179 } else {
180 wxASSERT( false );
184 #ifdef __DEBUG__
185 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
186 #endif
188 CLoggingEvent Event(critical, toStdout, msg);
190 // Try to handle events immediatly when possible (to save to file).
191 if (wxThread::IsMain()) {
192 // main thread and log file available: process directly
193 ProcessEvent(Event);
194 } else {
195 // otherwise put to background
196 AddPendingEvent(Event);
201 void CLogger::AddLogLine(
202 const wxString &file,
203 int line,
204 bool critical,
205 DebugType type,
206 const std::ostringstream &msg)
208 int index = (int)type;
210 if ( index >= 0 && index < categoryCount ) {
211 const CDebugCategory& cat = g_debugcats[ index ];
212 wxASSERT(type == cat.GetType());
214 AddLogLine(file, line, critical, logStandard, cat.GetName() + wxT(": ") + char2unicode(msg.str().c_str()));
219 const CDebugCategory& CLogger::GetDebugCategory( int index )
221 wxASSERT( index >= 0 && index < categoryCount );
223 return g_debugcats[ index ];
227 unsigned int CLogger::GetDebugCategoryCount()
229 return categoryCount;
233 bool CLogger::OpenLogfile(const wxString & name)
235 applog = new wxFFileOutputStream(name);
236 bool ret = applog->Ok();
237 if (ret) {
238 FlushApplog();
239 m_LogfileName = name;
240 } else {
241 CloseLogfile();
243 return ret;
247 void CLogger::CloseLogfile()
249 delete applog;
250 applog = NULL;
251 m_LogfileName = wxT("");
255 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
257 // Remove newspace at end
258 wxString bufferline = evt.Message().Strip(wxString::trailing);
260 // Create the timestamp
261 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
262 #ifdef CLIENT_GUI
263 + wxT(" (remote-GUI): ");
264 #else
265 + wxT(": ");
266 #endif
268 // critical lines get a ! prepended, others a blank
269 wxString prefix = evt.IsCritical() ? wxT("!") : wxT(" ");
271 if ( bufferline.IsEmpty() ) {
272 // If it's empty we just write a blank line with no timestamp.
273 DoLine(wxT(" \n"), evt.ToStdout());
274 } else {
275 // Split multi-line messages into individual lines
276 wxStringTokenizer tokens( bufferline, wxT("\n") );
277 while ( tokens.HasMoreTokens() ) {
278 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
279 DoLine(fullline, evt.ToStdout());
285 void CLogger::DoLine(const wxString & line, bool toStdout)
287 ++m_count;
289 // write to logfile
290 m_ApplogBuf += line;
291 FlushApplog();
293 // write to Stdout
294 if (m_StdoutLog || toStdout) {
295 printf("%s", (const char*)unicode2char(line));
297 #ifndef AMULE_DAEMON
298 // write to Listcontrol
299 theApp->AddGuiLogLine(line);
300 #endif
304 void CLogger::FlushApplog()
306 if (applog) { // Wait with output until logfile is actually opened
307 wxStringInputStream stream(m_ApplogBuf);
308 (*applog) << stream;
309 applog->Sync();
310 m_ApplogBuf = wxEmptyString;
314 CLogger theLogger;
316 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
317 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
318 END_EVENT_TABLE()
321 CLoggerTarget::CLoggerTarget()
326 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
328 // prevent infinite recursion
329 static bool recursion = false;
330 if (recursion) {
331 return;
333 recursion = true;
335 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
337 wxString str(msg);
339 // This is much simpler than manually handling all wx log-types.
340 bool critical = str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "));
342 AddLogLineM(critical, str);
344 recursion = false;
348 CLoggerAccess::CLoggerAccess()
350 m_bufferlen = 4096;
351 m_buffer = new wxCharBuffer(m_bufferlen);
352 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
353 m_pos = 0;
354 m_ready = false;
358 CLoggerAccess::~CLoggerAccess()
360 delete m_buffer;
361 delete m_logfile;
366 // read a line of text from the logfile if available
367 // (can't believe there's no library function for this >:( )
369 bool CLoggerAccess::HasString()
371 while (!m_ready) {
372 int c = m_logfile->GetC();
373 if (c == wxEOF) {
374 break;
376 // check for buffer overrun
377 if (m_pos == m_bufferlen) {
378 m_bufferlen += 1024;
379 m_buffer->extend(m_bufferlen);
381 m_buffer->data()[m_pos++] = c;
382 if (c == '\n') {
383 m_ready = true;
386 return m_ready;
390 bool CLoggerAccess::GetString(wxString & s)
392 if (!HasString()) {
393 return false;
395 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
396 m_pos = 0;
397 m_ready = false;
398 return true;
401 // File_checked_for_headers