2 // This file is part of the aMule Project.
4 // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org )
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
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.
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
27 #include "Preferences.h"
28 #include <common/Macros.h>
29 #include <common/MacrosProgramSpecific.h>
31 #include <wx/tokenzr.h>
32 #include <wx/wfstream.h>
33 #include <wx/sstream.h>
34 #include <wx/filename.h>
37 DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_LOGLINE
)
40 CDebugCategory g_debugcats
[] = {
41 CDebugCategory( logGeneral
, wxT("General") ),
42 CDebugCategory( logHasher
, wxT("Hasher") ),
43 CDebugCategory( logClient
, wxT("ED2k Client") ),
44 CDebugCategory( logLocalClient
, wxT("Local Client Protocol") ),
45 CDebugCategory( logRemoteClient
, wxT("Remote Client Protocol") ),
46 CDebugCategory( logPacketErrors
, wxT("Packet Parsing Errors") ),
47 CDebugCategory( logCFile
, wxT("CFile") ),
48 CDebugCategory( logFileIO
, wxT("FileIO") ),
49 CDebugCategory( logZLib
, wxT("ZLib") ),
50 CDebugCategory( logAICHThread
, wxT("AICH-Hasher") ),
51 CDebugCategory( logAICHTransfer
, wxT("AICH-Transfer") ),
52 CDebugCategory( logAICHRecovery
, wxT("AICH-Recovery") ),
53 CDebugCategory( logListenSocket
, wxT("ListenSocket") ),
54 CDebugCategory( logCredits
, wxT("Credits") ),
55 CDebugCategory( logClientUDP
, wxT("ClientUDPSocket") ),
56 CDebugCategory( logDownloadQueue
, wxT("DownloadQueue") ),
57 CDebugCategory( logIPFilter
, wxT("IPFilter") ),
58 CDebugCategory( logKnownFiles
, wxT("KnownFileList") ),
59 CDebugCategory( logPartFile
, wxT("PartFiles") ),
60 CDebugCategory( logSHAHashSet
, wxT("SHAHashSet") ),
61 CDebugCategory( logServer
, wxT("Servers") ),
62 CDebugCategory( logProxy
, wxT("Proxy") ),
63 CDebugCategory( logSearch
, wxT("Searching") ),
64 CDebugCategory( logServerUDP
, wxT("ServerUDP") ),
65 CDebugCategory( logClientKadUDP
, wxT("Client Kademlia UDP") ),
66 CDebugCategory( logKadSearch
, wxT("Kademlia Search") ),
67 CDebugCategory( logKadRouting
, wxT("Kademlia Routing") ),
68 CDebugCategory( logKadIndex
, wxT("Kademlia Indexing") ),
69 CDebugCategory( logKadMain
, wxT("Kademlia Main Thread") ),
70 CDebugCategory( logKadPrefs
, wxT("Kademlia Preferences") ),
71 CDebugCategory( logPfConvert
, wxT("PartFileConvert") ),
72 CDebugCategory( logMuleUDP
, wxT("MuleUDPSocket" ) ),
73 CDebugCategory( logThreads
, wxT("ThreadScheduler" ) ),
74 CDebugCategory( logUPnP
, wxT("Universal Plug and Play" ) ),
75 CDebugCategory( logKadUdpFwTester
, wxT("Kademlia UDP Firewall Tester") ),
76 CDebugCategory( logKadPacketTracking
, wxT("Kademlia Packet Tracking") ),
77 CDebugCategory( logKadEntryTracking
, wxT("Kademlia Entry Tracking") ),
78 CDebugCategory( logEC
, wxT("External Connect") ),
79 CDebugCategory( logHTTP
, wxT("HTTP") ),
80 CDebugCategory( logAsio
, wxT("Asio Sockets") )
84 const int categoryCount
= itemsof(g_debugcats
);
89 bool CLogger::IsEnabled( DebugType type
) const
91 int index
= (int)type
;
93 if ( index
>= 0 && index
< categoryCount
) {
94 const CDebugCategory
& cat
= g_debugcats
[ index
];
95 wxASSERT( type
== cat
.GetType() );
97 return ( cat
.IsEnabled() && thePrefs::GetVerbose() );
106 void CLogger::SetEnabled( DebugType type
, bool enabled
)
108 int index
= (int)type
;
110 if ( index
>= 0 && index
< categoryCount
) {
111 CDebugCategory
& cat
= g_debugcats
[ index
];
112 wxASSERT( type
== cat
.GetType() );
114 cat
.SetEnabled( enabled
);
121 void CLogger::AddLogLine(
122 const wxString
& DEBUG_ONLY(file
),
123 int DEBUG_ONLY(line
),
131 // handle Debug messages
132 if (type
!= logStandard
) {
133 if (!critical
&& !IsEnabled(type
)) {
136 if (!critical
&& thePrefs::GetVerboseLogfile()) {
137 // print non critical debug messages only to the logfile
140 int index
= (int)type
;
142 if ( index
>= 0 && index
< categoryCount
) {
143 const CDebugCategory
& cat
= g_debugcats
[ index
];
144 wxASSERT(type
== cat
.GetType());
146 msg
= cat
.GetName() + wxT(": ") + msg
;
154 msg
= file
.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line
<< wxT("): ") + msg
;
158 if (toGUI
&& !wxThread::IsMain()) {
160 CLoggingEvent
Event(critical
, toStdout
, toGUI
, msg
);
161 AddPendingEvent(Event
);
163 // Try to handle events immediatly when possible (to save to file).
164 DoLines(msg
, critical
, toStdout
, toGUI
);
169 void CLogger::AddLogLine(
170 const wxString
&file
,
174 const std::ostringstream
&msg
)
176 int index
= (int)type
;
178 if ( index
>= 0 && index
< categoryCount
) {
179 const CDebugCategory
& cat
= g_debugcats
[ index
];
180 wxASSERT(type
== cat
.GetType());
182 AddLogLine(file
, line
, critical
, logStandard
,
183 cat
.GetName() + wxT(": ") + wxString(char2unicode(msg
.str().c_str())));
188 const CDebugCategory
& CLogger::GetDebugCategory( int index
)
190 wxASSERT( index
>= 0 && index
< categoryCount
);
192 return g_debugcats
[ index
];
196 unsigned int CLogger::GetDebugCategoryCount()
198 return categoryCount
;
202 bool CLogger::OpenLogfile(const wxString
& name
)
204 applog
= new wxFFileOutputStream(name
);
205 bool ret
= applog
->Ok();
208 m_LogfileName
= name
;
216 void CLogger::CloseLogfile()
220 m_LogfileName
.Clear();
224 void CLogger::OnLoggingEvent(class CLoggingEvent
& evt
)
226 DoLines(evt
.Message(), evt
.IsCritical(), evt
.ToStdout(), evt
.ToGUI());
230 void CLogger::DoLines(const wxString
& lines
, bool critical
, bool toStdout
, bool toGUI
)
232 // Remove newspace at end
233 wxString bufferline
= lines
.Strip(wxString::trailing
);
235 // Create the timestamp
236 wxString stamp
= wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
238 + wxT(" (remote-GUI): ");
243 // critical lines get a ! prepended, ordinary lines a blank
244 // logfile-only lines get a . to prevent transmission on EC
245 wxString prefix
= !toGUI
? wxT(".") : (critical
? wxT("!") : wxT(" "));
247 if ( bufferline
.IsEmpty() ) {
248 // If it's empty we just write a blank line with no timestamp.
249 DoLine(wxT(" \n"), toStdout
, toGUI
);
251 // Split multi-line messages into individual lines
252 wxStringTokenizer
tokens( bufferline
, wxT("\n") );
253 while ( tokens
.HasMoreTokens() ) {
254 wxString fullline
= prefix
+ stamp
+ tokens
.GetNextToken() + wxT("\n");
255 DoLine(fullline
, toStdout
, toGUI
);
261 void CLogger::DoLine(const wxString
& line
, bool toStdout
, bool GUI_ONLY(toGUI
))
264 wxMutexLocker
lock(m_lineLock
);
272 if (m_StdoutLog
|| toStdout
) {
273 printf("%s", (const char*)unicode2char(line
));
277 // write to Listcontrol
279 theApp
->AddGuiLogLine(line
);
285 void CLogger::EmergencyLog(const wxString
&message
, bool closeLog
)
287 fprintf(stderr
, "%s", (const char*)unicode2char(message
));
288 m_ApplogBuf
+= message
;
290 if (closeLog
&& applog
) {
297 void CLogger::FlushApplog()
299 if (applog
) { // Wait with output until logfile is actually opened
300 wxStringInputStream
stream(m_ApplogBuf
);
309 BEGIN_EVENT_TABLE(CLogger
, wxEvtHandler
)
310 EVT_MULE_LOGGING(CLogger::OnLoggingEvent
)
314 CLoggerTarget::CLoggerTarget()
318 #if wxCHECK_VERSION(2, 9, 0)
319 void CLoggerTarget::DoLogText(const wxString
&msg
)
321 // prevent infinite recursion
322 static bool recursion
= false;
328 // This is much simpler than manually handling all wx log-types.
329 if (msg
.StartsWith(_("ERROR: ")) || msg
.StartsWith(_("WARNING: "))) {
338 void CLoggerTarget::DoLogString(const wxChar
* msg
, time_t)
340 // prevent infinite recursion
341 static bool recursion
= false;
347 wxCHECK_RET(msg
, wxT("Log message is NULL in DoLogString!"));
351 // This is much simpler than manually handling all wx log-types.
352 if (str
.StartsWith(_("ERROR: ")) || str
.StartsWith(_("WARNING: "))) {
362 CLoggerAccess::CLoggerAccess()
365 m_buffer
= new wxCharBuffer(m_bufferlen
);
371 void CLoggerAccess::Reset()
374 m_logfile
= new wxFFileInputStream(theLogger
.GetLogfileName());
380 CLoggerAccess::~CLoggerAccess()
388 // read a line of text from the logfile if available
389 // (can't believe there's no library function for this >:( )
391 bool CLoggerAccess::HasString()
394 int c
= m_logfile
->GetC();
398 // check for buffer overrun
399 if (m_pos
== m_bufferlen
) {
401 m_buffer
->extend(m_bufferlen
);
403 m_buffer
->data()[m_pos
++] = c
;
405 if (m_buffer
->data()[0] == '.') {
406 // Log-only line, skip
417 bool CLoggerAccess::GetString(wxString
& s
)
422 s
= wxString(m_buffer
->data(), wxConvUTF8
, m_pos
);
428 // Functions for EC logging
429 bool ECLogIsEnabled()
431 return theLogger
.IsEnabled(logEC
);
434 void DoECLogLine(const wxString
&line
)
437 theLogger
.AddLogLine(wxEmptyString
, 0, false, logStandard
, line
, false, false);
440 // File_checked_for_headers