Improve the code by static code analysis [3/3]: Style
[amule.git] / src / Logger.cpp
blob81c49c7bbad5dd89d171ac439f086838a9ac63ed
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2005-2011 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.
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 <common/MacrosProgramSpecific.h>
30 #include <sstream>
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);
88 #ifdef __DEBUG__
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() );
100 wxFAIL;
101 return false;
103 #endif
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 );
115 } else {
116 wxFAIL;
121 void CLogger::AddLogLine(
122 const wxString& DEBUG_ONLY(file),
123 int DEBUG_ONLY(line),
124 bool critical,
125 DebugType type,
126 const wxString &str,
127 bool toStdout,
128 bool toGUI)
130 wxString msg(str);
131 // handle Debug messages
132 if (type != logStandard) {
133 if (!critical && !IsEnabled(type)) {
134 return;
136 if (!critical && thePrefs::GetVerboseLogfile()) {
137 // print non critical debug messages only to the logfile
138 toGUI = false;
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;
147 } else {
148 wxFAIL;
152 #ifdef __DEBUG__
153 if (line) {
154 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
156 #endif
158 if (toGUI && !wxThread::IsMain()) {
159 // put to background
160 CLoggingEvent Event(critical, toStdout, toGUI, msg);
161 AddPendingEvent(Event);
162 } else {
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,
171 int line,
172 bool critical,
173 DebugType type,
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();
206 if (ret) {
207 FlushApplog();
208 m_LogfileName = name;
209 } else {
210 CloseLogfile();
212 return ret;
216 void CLogger::CloseLogfile()
218 delete applog;
219 applog = NULL;
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()
237 #ifdef CLIENT_GUI
238 + wxT(" (remote-GUI): ");
239 #else
240 + wxT(": ");
241 #endif
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);
250 } else {
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);
265 ++m_count;
267 // write to logfile
268 m_ApplogBuf += line;
269 FlushApplog();
271 // write to Stdout
272 if (m_StdoutLog || toStdout) {
273 printf("%s", (const char*)unicode2char(line));
276 #ifndef AMULE_DAEMON
277 // write to Listcontrol
278 if (toGUI) {
279 theApp->AddGuiLogLine(line);
281 #endif
285 void CLogger::EmergencyLog(const wxString &message, bool closeLog)
287 fprintf(stderr, "%s", (const char*)unicode2char(message));
288 m_ApplogBuf += message;
289 FlushApplog();
290 if (closeLog && applog) {
291 applog->Close();
292 applog = NULL;
297 void CLogger::FlushApplog()
299 if (applog) { // Wait with output until logfile is actually opened
300 wxStringInputStream stream(m_ApplogBuf);
301 (*applog) << stream;
302 applog->Sync();
303 m_ApplogBuf.Clear();
307 CLogger theLogger;
309 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
310 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
311 END_EVENT_TABLE()
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;
323 if (recursion) {
324 return;
326 recursion = true;
328 // This is much simpler than manually handling all wx log-types.
329 if (msg.StartsWith(_("ERROR: ")) || msg.StartsWith(_("WARNING: "))) {
330 AddLogLineC(msg);
331 } else {
332 AddLogLineN(msg);
335 recursion = false;
337 #else
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 // cppcheck-suppress duplicateBranch
353 if (str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "))) {
354 AddLogLineC(str);
355 } else {
356 AddLogLineN(str);
359 recursion = false;
361 #endif
363 CLoggerAccess::CLoggerAccess()
365 m_bufferlen = 4096;
366 m_buffer = new wxCharBuffer(m_bufferlen);
367 m_logfile = NULL;
368 Reset();
372 void CLoggerAccess::Reset()
374 delete m_logfile;
375 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
376 m_pos = 0;
377 m_ready = false;
381 CLoggerAccess::~CLoggerAccess()
383 delete m_buffer;
384 delete m_logfile;
389 // read a line of text from the logfile if available
390 // (can't believe there's no library function for this >:( )
392 bool CLoggerAccess::HasString()
394 while (!m_ready) {
395 int c = m_logfile->GetC();
396 if (c == wxEOF) {
397 break;
399 // check for buffer overrun
400 if (m_pos == m_bufferlen) {
401 m_bufferlen += 1024;
402 m_buffer->extend(m_bufferlen);
404 m_buffer->data()[m_pos++] = c;
405 if (c == '\n') {
406 if (m_buffer->data()[0] == '.') {
407 // Log-only line, skip
408 m_pos = 0;
409 } else {
410 m_ready = true;
414 return m_ready;
418 bool CLoggerAccess::GetString(wxString & s)
420 if (!HasString()) {
421 return false;
423 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
424 m_pos = 0;
425 m_ready = false;
426 return true;
429 // Functions for EC logging
430 bool ECLogIsEnabled()
432 return theLogger.IsEnabled(logEC);
435 void DoECLogLine(const wxString &line)
437 // without file/line
438 theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false);
441 // File_checked_for_headers