Upstream tarball 9938
[amule.git] / src / Logger.cpp
blob9fbe08e6d706dc8f0ee14bb55b04432ea7d350e5
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") )
81 const int categoryCount = sizeof( g_debugcats ) / sizeof( g_debugcats[0] );
85 #ifdef __DEBUG__
86 bool CLogger::IsEnabled( DebugType type ) const
88 int index = (int)type;
90 if ( index >= 0 && index < categoryCount ) {
91 const CDebugCategory& cat = g_debugcats[ index ];
92 wxASSERT( type == cat.GetType() );
94 return ( cat.IsEnabled() && thePrefs::GetVerbose() );
97 wxFAIL;
98 return false;
100 #endif
103 void CLogger::SetEnabled( DebugType type, bool enabled )
105 int index = (int)type;
107 if ( index >= 0 && index < categoryCount ) {
108 CDebugCategory& cat = g_debugcats[ index ];
109 wxASSERT( type == cat.GetType() );
111 cat.SetEnabled( enabled );
112 } else {
113 wxFAIL;
118 void CLogger::AddLogLine(
119 const wxString &file,
120 int line,
121 bool critical,
122 DebugType type,
123 const wxString &str,
124 bool toStdout,
125 bool toGUI)
127 wxString msg(str);
128 // handle Debug messages
129 if (type != logStandard) {
130 if (!critical && !IsEnabled(type)) {
131 return;
133 int index = (int)type;
135 if ( index >= 0 && index < categoryCount ) {
136 const CDebugCategory& cat = g_debugcats[ index ];
137 wxASSERT(type == cat.GetType());
139 msg = cat.GetName() + wxT(": ") + msg;
140 } else {
141 wxFAIL;
145 #ifdef __DEBUG__
146 if (line) {
147 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
149 #endif
151 CLoggingEvent Event(critical, toStdout, toGUI, msg);
153 // Try to handle events immediatly when possible (to save to file).
154 if (wxThread::IsMain()) {
155 // main thread and log file available: process directly
156 ProcessEvent(Event);
157 } else {
158 // otherwise put to background
159 AddPendingEvent(Event);
164 void CLogger::AddLogLine(
165 const wxString &file,
166 int line,
167 bool critical,
168 DebugType type,
169 const std::ostringstream &msg)
171 int index = (int)type;
173 if ( index >= 0 && index < categoryCount ) {
174 const CDebugCategory& cat = g_debugcats[ index ];
175 wxASSERT(type == cat.GetType());
177 AddLogLine(file, line, critical, logStandard, cat.GetName() + wxT(": ") + char2unicode(msg.str().c_str()));
182 const CDebugCategory& CLogger::GetDebugCategory( int index )
184 wxASSERT( index >= 0 && index < categoryCount );
186 return g_debugcats[ index ];
190 unsigned int CLogger::GetDebugCategoryCount()
192 return categoryCount;
196 bool CLogger::OpenLogfile(const wxString & name)
198 applog = new wxFFileOutputStream(name);
199 bool ret = applog->Ok();
200 if (ret) {
201 FlushApplog();
202 m_LogfileName = name;
203 } else {
204 CloseLogfile();
206 return ret;
210 void CLogger::CloseLogfile()
212 delete applog;
213 applog = NULL;
214 m_LogfileName = wxT("");
218 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
220 // Remove newspace at end
221 wxString bufferline = evt.Message().Strip(wxString::trailing);
223 // Create the timestamp
224 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
225 #ifdef CLIENT_GUI
226 + wxT(" (remote-GUI): ");
227 #else
228 + wxT(": ");
229 #endif
231 // critical lines get a ! prepended, ordinary lines a blank
232 // logfile-only lines get a . to prevent transmission on EC
233 wxString prefix = !evt.ToGUI() ? wxT(".") : (evt.IsCritical() ? wxT("!") : wxT(" "));
235 if ( bufferline.IsEmpty() ) {
236 // If it's empty we just write a blank line with no timestamp.
237 DoLine(wxT(" \n"), evt.ToStdout(), evt.ToGUI());
238 } else {
239 // Split multi-line messages into individual lines
240 wxStringTokenizer tokens( bufferline, wxT("\n") );
241 while ( tokens.HasMoreTokens() ) {
242 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
243 DoLine(fullline, evt.ToStdout(), evt.ToGUI());
249 void CLogger::DoLine(const wxString & line, bool toStdout, bool GUI_ONLY(toGUI))
251 ++m_count;
253 // write to logfile
254 m_ApplogBuf += line;
255 FlushApplog();
257 // write to Stdout
258 if (m_StdoutLog || toStdout) {
259 printf("%s", (const char*)unicode2char(line));
261 #ifndef AMULE_DAEMON
262 // write to Listcontrol
263 if (toGUI) {
264 theApp->AddGuiLogLine(line);
266 #endif
270 void CLogger::FlushApplog()
272 if (applog) { // Wait with output until logfile is actually opened
273 wxStringInputStream stream(m_ApplogBuf);
274 (*applog) << stream;
275 applog->Sync();
276 m_ApplogBuf = wxEmptyString;
280 CLogger theLogger;
282 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
283 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
284 END_EVENT_TABLE()
287 CLoggerTarget::CLoggerTarget()
291 #if wxCHECK_VERSION(2, 9, 0)
292 void CLoggerTarget::DoLogText(const wxString &msg)
294 // prevent infinite recursion
295 static bool recursion = false;
296 if (recursion) {
297 return;
299 recursion = true;
301 // This is much simpler than manually handling all wx log-types.
302 bool critical = msg.StartsWith(_("ERROR: ")) || msg.StartsWith(_("WARNING: "));
304 AddLogLineM(critical, msg);
306 recursion = false;
308 #else
309 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
311 // prevent infinite recursion
312 static bool recursion = false;
313 if (recursion) {
314 return;
316 recursion = true;
318 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
320 wxString str(msg);
322 // This is much simpler than manually handling all wx log-types.
323 bool critical = str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "));
325 AddLogLineM(critical, str);
327 recursion = false;
329 #endif
331 CLoggerAccess::CLoggerAccess()
333 m_bufferlen = 4096;
334 m_buffer = new wxCharBuffer(m_bufferlen);
335 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
336 m_pos = 0;
337 m_ready = false;
341 CLoggerAccess::~CLoggerAccess()
343 delete m_buffer;
344 delete m_logfile;
349 // read a line of text from the logfile if available
350 // (can't believe there's no library function for this >:( )
352 bool CLoggerAccess::HasString()
354 while (!m_ready) {
355 int c = m_logfile->GetC();
356 if (c == wxEOF) {
357 break;
359 // check for buffer overrun
360 if (m_pos == m_bufferlen) {
361 m_bufferlen += 1024;
362 m_buffer->extend(m_bufferlen);
364 m_buffer->data()[m_pos++] = c;
365 if (c == '\n') {
366 if (m_buffer->data()[0] == '.') {
367 // Log-only line, skip
368 m_pos = 0;
369 } else {
370 m_ready = true;
374 return m_ready;
378 bool CLoggerAccess::GetString(wxString & s)
380 if (!HasString()) {
381 return false;
383 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
384 m_pos = 0;
385 m_ready = false;
386 return true;
389 // Functions for EC logging
390 bool ECLogIsEnabled()
392 return theLogger.IsEnabled(logEC);
395 void DoECLogLine(const wxString &line)
397 // without file/line
398 theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false);
401 // File_checked_for_headers