Upstream tarball 9716
[amule.git] / src / Logger.cpp
blobf376ecadd0414a27353c97c2c4d6c90cc321b5d2
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") ),
107 CDebugCategory( logEC, wxT("External Connect") )
111 const int categoryCount = sizeof( g_debugcats ) / sizeof( g_debugcats[0] );
115 bool CLogger::IsEnabled( DebugType type )
117 #ifdef __DEBUG__
118 int index = (int)type;
120 if ( index >= 0 && index < categoryCount ) {
121 const CDebugCategory& cat = g_debugcats[ index ];
122 wxASSERT( type == cat.GetType() );
124 return ( cat.IsEnabled() && thePrefs::GetVerbose() );
127 wxFAIL;
128 #endif
129 return false;
133 void CLogger::SetEnabled( DebugType type, bool enabled )
135 int index = (int)type;
137 if ( index >= 0 && index < categoryCount ) {
138 CDebugCategory& cat = g_debugcats[ index ];
139 wxASSERT( type == cat.GetType() );
141 cat.SetEnabled( enabled );
142 } else {
143 wxFAIL;
148 bool CLogger::IsEnabledStdoutLog()
150 return m_StdoutLog;
154 void CLogger::SetEnabledStdoutLog(bool enabled)
156 m_StdoutLog = enabled;
160 void CLogger::AddLogLine(
161 const wxString &file,
162 int line,
163 bool critical,
164 DebugType type,
165 const wxString &str,
166 bool toStdout,
167 bool toGUI)
169 wxString msg(str);
170 // handle Debug messages
171 if (type != logStandard) {
172 if (!critical && !IsEnabled(type)) {
173 return;
175 int index = (int)type;
177 if ( index >= 0 && index < categoryCount ) {
178 const CDebugCategory& cat = g_debugcats[ index ];
179 wxASSERT(type == cat.GetType());
181 msg = cat.GetName() + wxT(": ") + msg;
182 } else {
183 wxFAIL;
187 #ifdef __DEBUG__
188 if (line) {
189 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
191 #endif
193 CLoggingEvent Event(critical, toStdout, toGUI, msg);
195 // Try to handle events immediatly when possible (to save to file).
196 if (wxThread::IsMain()) {
197 // main thread and log file available: process directly
198 ProcessEvent(Event);
199 } else {
200 // otherwise put to background
201 AddPendingEvent(Event);
206 void CLogger::AddLogLine(
207 const wxString &file,
208 int line,
209 bool critical,
210 DebugType type,
211 const std::ostringstream &msg)
213 int index = (int)type;
215 if ( index >= 0 && index < categoryCount ) {
216 const CDebugCategory& cat = g_debugcats[ index ];
217 wxASSERT(type == cat.GetType());
219 AddLogLine(file, line, critical, logStandard, cat.GetName() + wxT(": ") + char2unicode(msg.str().c_str()));
224 const CDebugCategory& CLogger::GetDebugCategory( int index )
226 wxASSERT( index >= 0 && index < categoryCount );
228 return g_debugcats[ index ];
232 unsigned int CLogger::GetDebugCategoryCount()
234 return categoryCount;
238 bool CLogger::OpenLogfile(const wxString & name)
240 applog = new wxFFileOutputStream(name);
241 bool ret = applog->Ok();
242 if (ret) {
243 FlushApplog();
244 m_LogfileName = name;
245 } else {
246 CloseLogfile();
248 return ret;
252 void CLogger::CloseLogfile()
254 delete applog;
255 applog = NULL;
256 m_LogfileName = wxT("");
260 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
262 // Remove newspace at end
263 wxString bufferline = evt.Message().Strip(wxString::trailing);
265 // Create the timestamp
266 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
267 #ifdef CLIENT_GUI
268 + wxT(" (remote-GUI): ");
269 #else
270 + wxT(": ");
271 #endif
273 // critical lines get a ! prepended, ordinary lines a blank
274 // logfile-only lines get a . to prevent transmission on EC
275 wxString prefix = !evt.ToGUI() ? wxT(".") : (evt.IsCritical() ? wxT("!") : wxT(" "));
277 if ( bufferline.IsEmpty() ) {
278 // If it's empty we just write a blank line with no timestamp.
279 DoLine(wxT(" \n"), evt.ToStdout(), evt.ToGUI());
280 } else {
281 // Split multi-line messages into individual lines
282 wxStringTokenizer tokens( bufferline, wxT("\n") );
283 while ( tokens.HasMoreTokens() ) {
284 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
285 DoLine(fullline, evt.ToStdout(), evt.ToGUI());
291 void CLogger::DoLine(const wxString & line, bool toStdout, bool
292 #ifndef AMULE_DAEMON
293 toGUI
294 #endif
297 ++m_count;
299 // write to logfile
300 m_ApplogBuf += line;
301 FlushApplog();
303 // write to Stdout
304 if (m_StdoutLog || toStdout) {
305 printf("%s", (const char*)unicode2char(line));
307 #ifndef AMULE_DAEMON
308 // write to Listcontrol
309 if (toGUI) {
310 theApp->AddGuiLogLine(line);
312 #endif
316 void CLogger::FlushApplog()
318 if (applog) { // Wait with output until logfile is actually opened
319 wxStringInputStream stream(m_ApplogBuf);
320 (*applog) << stream;
321 applog->Sync();
322 m_ApplogBuf = wxEmptyString;
326 CLogger theLogger;
328 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
329 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
330 END_EVENT_TABLE()
333 CLoggerTarget::CLoggerTarget()
338 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
340 // prevent infinite recursion
341 static bool recursion = false;
342 if (recursion) {
343 return;
345 recursion = true;
347 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
349 wxString str(msg);
351 // This is much simpler than manually handling all wx log-types.
352 bool critical = str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "));
354 AddLogLineM(critical, str);
356 recursion = false;
360 CLoggerAccess::CLoggerAccess()
362 m_bufferlen = 4096;
363 m_buffer = new wxCharBuffer(m_bufferlen);
364 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
365 m_pos = 0;
366 m_ready = false;
370 CLoggerAccess::~CLoggerAccess()
372 delete m_buffer;
373 delete m_logfile;
378 // read a line of text from the logfile if available
379 // (can't believe there's no library function for this >:( )
381 bool CLoggerAccess::HasString()
383 while (!m_ready) {
384 int c = m_logfile->GetC();
385 if (c == wxEOF) {
386 break;
388 // check for buffer overrun
389 if (m_pos == m_bufferlen) {
390 m_bufferlen += 1024;
391 m_buffer->extend(m_bufferlen);
393 m_buffer->data()[m_pos++] = c;
394 if (c == '\n') {
395 if (m_buffer->data()[0] == '.') {
396 // Log-only line, skip
397 m_pos = 0;
398 } else {
399 m_ready = true;
403 return m_ready;
407 bool CLoggerAccess::GetString(wxString & s)
409 if (!HasString()) {
410 return false;
412 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
413 m_pos = 0;
414 m_ready = false;
415 return true;
418 // Functions for EC logging
419 bool ECLogIsEnabled()
421 return theLogger.IsEnabled(logEC);
424 void DoECLogLine(const wxString &line)
426 // without file/line
427 theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false);
430 // File_checked_for_headers