Upstream tarball 10020
[amule.git] / src / Logger.cpp
blob7ff8408224e26e7431494472ec141bbaf3c429b9
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 <common/Macros.h>
29 #include <sstream>
30 #include <wx/tokenzr.h>
31 #include <wx/wfstream.h>
32 #include <wx/sstream.h>
33 #include <wx/filename.h>
36 DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_LOGLINE)
39 CDebugCategory g_debugcats[] = {
40 CDebugCategory( logGeneral, wxT("General") ),
41 CDebugCategory( logHasher, wxT("Hasher") ),
42 CDebugCategory( logClient, wxT("ED2k Client") ),
43 CDebugCategory( logLocalClient, wxT("Local Client Protocol") ),
44 CDebugCategory( logRemoteClient, wxT("Remote Client Protocol") ),
45 CDebugCategory( logPacketErrors, wxT("Packet Parsing Errors") ),
46 CDebugCategory( logCFile, wxT("CFile") ),
47 CDebugCategory( logFileIO, wxT("FileIO") ),
48 CDebugCategory( logZLib, wxT("ZLib") ),
49 CDebugCategory( logAICHThread, wxT("AICH-Hasher") ),
50 CDebugCategory( logAICHTransfer, wxT("AICH-Transfer") ),
51 CDebugCategory( logAICHRecovery, wxT("AICH-Recovery") ),
52 CDebugCategory( logListenSocket, wxT("ListenSocket") ),
53 CDebugCategory( logCredits, wxT("Credits") ),
54 CDebugCategory( logClientUDP, wxT("ClientUDPSocket") ),
55 CDebugCategory( logDownloadQueue, wxT("DownloadQueue") ),
56 CDebugCategory( logIPFilter, wxT("IPFilter") ),
57 CDebugCategory( logKnownFiles, wxT("KnownFileList") ),
58 CDebugCategory( logPartFile, wxT("PartFiles") ),
59 CDebugCategory( logSHAHashSet, wxT("SHAHashSet") ),
60 CDebugCategory( logServer, wxT("Servers") ),
61 CDebugCategory( logProxy, wxT("Proxy") ),
62 CDebugCategory( logSearch, wxT("Searching") ),
63 CDebugCategory( logServerUDP, wxT("ServerUDP") ),
64 CDebugCategory( logClientKadUDP, wxT("Client Kademlia UDP") ),
65 CDebugCategory( logKadSearch, wxT("Kademlia Search") ),
66 CDebugCategory( logKadRouting, wxT("Kademlia Routing") ),
67 CDebugCategory( logKadIndex, wxT("Kademlia Indexing") ),
68 CDebugCategory( logKadMain, wxT("Kademlia Main Thread") ),
69 CDebugCategory( logKadPrefs, wxT("Kademlia Preferences") ),
70 CDebugCategory( logPfConvert, wxT("PartFileConvert") ),
71 CDebugCategory( logMuleUDP, wxT("MuleUDPSocket" ) ),
72 CDebugCategory( logThreads, wxT("ThreadScheduler" ) ),
73 CDebugCategory( logUPnP, wxT("Universal Plug and Play" ) ),
74 CDebugCategory( logKadUdpFwTester, wxT("Kademlia UDP Firewall Tester") ),
75 CDebugCategory( logKadPacketTracking, wxT("Kademlia Packet Tracking") ),
76 CDebugCategory( logKadEntryTracking, wxT("Kademlia Entry Tracking") ),
77 CDebugCategory( logEC, wxT("External Connect") ),
78 CDebugCategory( logHTTP, wxT("HTTP") )
82 const int categoryCount = sizeof( g_debugcats ) / sizeof( g_debugcats[0] );
86 #ifdef __DEBUG__
87 bool CLogger::IsEnabled( DebugType type ) const
89 int index = (int)type;
91 if ( index >= 0 && index < categoryCount ) {
92 const CDebugCategory& cat = g_debugcats[ index ];
93 wxASSERT( type == cat.GetType() );
95 return ( cat.IsEnabled() && thePrefs::GetVerbose() );
98 wxFAIL;
99 return false;
101 #endif
104 void CLogger::SetEnabled( DebugType type, bool enabled )
106 int index = (int)type;
108 if ( index >= 0 && index < categoryCount ) {
109 CDebugCategory& cat = g_debugcats[ index ];
110 wxASSERT( type == cat.GetType() );
112 cat.SetEnabled( enabled );
113 } else {
114 wxFAIL;
119 void CLogger::AddLogLine(
120 const wxString &file,
121 int line,
122 bool critical,
123 DebugType type,
124 const wxString &str,
125 bool toStdout,
126 bool toGUI)
128 wxString msg(str);
129 // handle Debug messages
130 if (type != logStandard) {
131 if (!critical && !IsEnabled(type)) {
132 return;
134 int index = (int)type;
136 if ( index >= 0 && index < categoryCount ) {
137 const CDebugCategory& cat = g_debugcats[ index ];
138 wxASSERT(type == cat.GetType());
140 msg = cat.GetName() + wxT(": ") + msg;
141 } else {
142 wxFAIL;
146 #ifdef __DEBUG__
147 if (line) {
148 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
150 #endif
152 CLoggingEvent Event(critical, toStdout, toGUI, msg);
154 // Try to handle events immediatly when possible (to save to file).
155 if (wxThread::IsMain()) {
156 // main thread and log file available: process directly
157 ProcessEvent(Event);
158 } else {
159 // otherwise put to background
160 AddPendingEvent(Event);
165 void CLogger::AddLogLine(
166 const wxString &file,
167 int line,
168 bool critical,
169 DebugType type,
170 const std::ostringstream &msg)
172 int index = (int)type;
174 if ( index >= 0 && index < categoryCount ) {
175 const CDebugCategory& cat = g_debugcats[ index ];
176 wxASSERT(type == cat.GetType());
178 AddLogLine(file, line, critical, logStandard, cat.GetName() + wxT(": ") + char2unicode(msg.str().c_str()));
183 const CDebugCategory& CLogger::GetDebugCategory( int index )
185 wxASSERT( index >= 0 && index < categoryCount );
187 return g_debugcats[ index ];
191 unsigned int CLogger::GetDebugCategoryCount()
193 return categoryCount;
197 bool CLogger::OpenLogfile(const wxString & name)
199 applog = new wxFFileOutputStream(name);
200 bool ret = applog->Ok();
201 if (ret) {
202 FlushApplog();
203 m_LogfileName = name;
204 } else {
205 CloseLogfile();
207 return ret;
211 void CLogger::CloseLogfile()
213 delete applog;
214 applog = NULL;
215 m_LogfileName = wxT("");
219 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
221 // Remove newspace at end
222 wxString bufferline = evt.Message().Strip(wxString::trailing);
224 // Create the timestamp
225 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
226 #ifdef CLIENT_GUI
227 + wxT(" (remote-GUI): ");
228 #else
229 + wxT(": ");
230 #endif
232 // critical lines get a ! prepended, ordinary lines a blank
233 // logfile-only lines get a . to prevent transmission on EC
234 wxString prefix = !evt.ToGUI() ? wxT(".") : (evt.IsCritical() ? wxT("!") : wxT(" "));
236 if ( bufferline.IsEmpty() ) {
237 // If it's empty we just write a blank line with no timestamp.
238 DoLine(wxT(" \n"), evt.ToStdout(), evt.ToGUI());
239 } else {
240 // Split multi-line messages into individual lines
241 wxStringTokenizer tokens( bufferline, wxT("\n") );
242 while ( tokens.HasMoreTokens() ) {
243 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
244 DoLine(fullline, evt.ToStdout(), evt.ToGUI());
250 void CLogger::DoLine(const wxString & line, bool toStdout, bool GUI_ONLY(toGUI))
252 ++m_count;
254 // write to logfile
255 m_ApplogBuf += line;
256 FlushApplog();
258 // write to Stdout
259 if (m_StdoutLog || toStdout) {
260 printf("%s", (const char*)unicode2char(line));
262 #ifndef AMULE_DAEMON
263 // write to Listcontrol
264 if (toGUI) {
265 theApp->AddGuiLogLine(line);
267 #endif
271 void CLogger::FlushApplog()
273 if (applog) { // Wait with output until logfile is actually opened
274 wxStringInputStream stream(m_ApplogBuf);
275 (*applog) << stream;
276 applog->Sync();
277 m_ApplogBuf = wxEmptyString;
281 CLogger theLogger;
283 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
284 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
285 END_EVENT_TABLE()
288 CLoggerTarget::CLoggerTarget()
292 #if wxCHECK_VERSION(2, 9, 0)
293 void CLoggerTarget::DoLogText(const wxString &msg)
295 // prevent infinite recursion
296 static bool recursion = false;
297 if (recursion) {
298 return;
300 recursion = true;
302 // This is much simpler than manually handling all wx log-types.
303 bool critical = msg.StartsWith(_("ERROR: ")) || msg.StartsWith(_("WARNING: "));
305 AddLogLineM(critical, msg);
307 recursion = false;
309 #else
310 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
312 // prevent infinite recursion
313 static bool recursion = false;
314 if (recursion) {
315 return;
317 recursion = true;
319 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
321 wxString str(msg);
323 // This is much simpler than manually handling all wx log-types.
324 bool critical = str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "));
326 AddLogLineM(critical, str);
328 recursion = false;
330 #endif
332 CLoggerAccess::CLoggerAccess()
334 m_bufferlen = 4096;
335 m_buffer = new wxCharBuffer(m_bufferlen);
336 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
337 m_pos = 0;
338 m_ready = false;
342 CLoggerAccess::~CLoggerAccess()
344 delete m_buffer;
345 delete m_logfile;
350 // read a line of text from the logfile if available
351 // (can't believe there's no library function for this >:( )
353 bool CLoggerAccess::HasString()
355 while (!m_ready) {
356 int c = m_logfile->GetC();
357 if (c == wxEOF) {
358 break;
360 // check for buffer overrun
361 if (m_pos == m_bufferlen) {
362 m_bufferlen += 1024;
363 m_buffer->extend(m_bufferlen);
365 m_buffer->data()[m_pos++] = c;
366 if (c == '\n') {
367 if (m_buffer->data()[0] == '.') {
368 // Log-only line, skip
369 m_pos = 0;
370 } else {
371 m_ready = true;
375 return m_ready;
379 bool CLoggerAccess::GetString(wxString & s)
381 if (!HasString()) {
382 return false;
384 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
385 m_pos = 0;
386 m_ready = false;
387 return true;
390 // Functions for EC logging
391 bool ECLogIsEnabled()
393 return theLogger.IsEnabled(logEC);
396 void DoECLogLine(const wxString &line)
398 // without file/line
399 theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false);
402 // File_checked_for_headers