Fixed problem in the CFile write_safe concept
[amule.git] / src / Logger.cpp
blobcf99e66796494164a4c166043d7b0510dff67748
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.
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 <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") )
83 const int categoryCount = sizeof( g_debugcats ) / sizeof( g_debugcats[0] );
87 #ifdef __DEBUG__
88 bool CLogger::IsEnabled( DebugType type ) const
90 int index = (int)type;
92 if ( index >= 0 && index < categoryCount ) {
93 const CDebugCategory& cat = g_debugcats[ index ];
94 wxASSERT( type == cat.GetType() );
96 return ( cat.IsEnabled() && thePrefs::GetVerbose() );
99 wxFAIL;
100 return false;
102 #endif
105 void CLogger::SetEnabled( DebugType type, bool enabled )
107 int index = (int)type;
109 if ( index >= 0 && index < categoryCount ) {
110 CDebugCategory& cat = g_debugcats[ index ];
111 wxASSERT( type == cat.GetType() );
113 cat.SetEnabled( enabled );
114 } else {
115 wxFAIL;
120 void CLogger::AddLogLine(
121 const wxString& DEBUG_ONLY(file),
122 int DEBUG_ONLY(line),
123 bool critical,
124 DebugType type,
125 const wxString &str,
126 bool toStdout,
127 bool toGUI)
129 wxString msg(str);
130 // handle Debug messages
131 if (type != logStandard) {
132 if (!critical && !IsEnabled(type)) {
133 return;
135 int index = (int)type;
137 if ( index >= 0 && index < categoryCount ) {
138 const CDebugCategory& cat = g_debugcats[ index ];
139 wxASSERT(type == cat.GetType());
141 msg = cat.GetName() + wxT(": ") + msg;
142 } else {
143 wxFAIL;
147 #ifdef __DEBUG__
148 if (line) {
149 msg = file.AfterLast(wxFileName::GetPathSeparator()).AfterLast(wxT('/')) << wxT("(") << line << wxT("): ") + msg;
151 #endif
153 CLoggingEvent Event(critical, toStdout, toGUI, msg);
155 // Try to handle events immediatly when possible (to save to file).
156 if (wxThread::IsMain()) {
157 // main thread and log file available: process directly
158 ProcessEvent(Event);
159 } else {
160 // otherwise put to background
161 AddPendingEvent(Event);
166 void CLogger::AddLogLine(
167 const wxString &file,
168 int line,
169 bool critical,
170 DebugType type,
171 const std::ostringstream &msg)
173 int index = (int)type;
175 if ( index >= 0 && index < categoryCount ) {
176 const CDebugCategory& cat = g_debugcats[ index ];
177 wxASSERT(type == cat.GetType());
179 AddLogLine(file, line, critical, logStandard,
180 cat.GetName() + wxT(": ") + wxString(char2unicode(msg.str().c_str())));
185 const CDebugCategory& CLogger::GetDebugCategory( int index )
187 wxASSERT( index >= 0 && index < categoryCount );
189 return g_debugcats[ index ];
193 unsigned int CLogger::GetDebugCategoryCount()
195 return categoryCount;
199 bool CLogger::OpenLogfile(const wxString & name)
201 applog = new wxFFileOutputStream(name);
202 bool ret = applog->Ok();
203 if (ret) {
204 FlushApplog();
205 m_LogfileName = name;
206 } else {
207 CloseLogfile();
209 return ret;
213 void CLogger::CloseLogfile()
215 delete applog;
216 applog = NULL;
217 m_LogfileName.Clear();
221 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
223 // Remove newspace at end
224 wxString bufferline = evt.Message().Strip(wxString::trailing);
226 // Create the timestamp
227 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
228 #ifdef CLIENT_GUI
229 + wxT(" (remote-GUI): ");
230 #else
231 + wxT(": ");
232 #endif
234 // critical lines get a ! prepended, ordinary lines a blank
235 // logfile-only lines get a . to prevent transmission on EC
236 wxString prefix = !evt.ToGUI() ? wxT(".") : (evt.IsCritical() ? wxT("!") : wxT(" "));
238 if ( bufferline.IsEmpty() ) {
239 // If it's empty we just write a blank line with no timestamp.
240 DoLine(wxT(" \n"), evt.ToStdout(), evt.ToGUI());
241 } else {
242 // Split multi-line messages into individual lines
243 wxStringTokenizer tokens( bufferline, wxT("\n") );
244 while ( tokens.HasMoreTokens() ) {
245 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
246 DoLine(fullline, evt.ToStdout(), evt.ToGUI());
252 void CLogger::DoLine(const wxString & line, bool toStdout, bool GUI_ONLY(toGUI))
254 ++m_count;
256 // write to logfile
257 m_ApplogBuf += line;
258 FlushApplog();
260 // write to Stdout
261 if (m_StdoutLog || toStdout) {
262 printf("%s", (const char*)unicode2char(line));
264 #ifndef AMULE_DAEMON
265 // write to Listcontrol
266 if (toGUI) {
267 theApp->AddGuiLogLine(line);
269 #endif
273 void CLogger::FlushApplog()
275 if (applog) { // Wait with output until logfile is actually opened
276 wxStringInputStream stream(m_ApplogBuf);
277 (*applog) << stream;
278 applog->Sync();
279 m_ApplogBuf.Clear();
283 CLogger theLogger;
285 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
286 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
287 END_EVENT_TABLE()
290 CLoggerTarget::CLoggerTarget()
294 #if wxCHECK_VERSION(2, 9, 0)
295 void CLoggerTarget::DoLogText(const wxString &msg)
297 // prevent infinite recursion
298 static bool recursion = false;
299 if (recursion) {
300 return;
302 recursion = true;
304 // This is much simpler than manually handling all wx log-types.
305 if (msg.StartsWith(_("ERROR: ")) || msg.StartsWith(_("WARNING: "))) {
306 AddLogLineC(msg);
307 } else {
308 AddLogLineN(msg);
311 recursion = false;
313 #else
314 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
316 // prevent infinite recursion
317 static bool recursion = false;
318 if (recursion) {
319 return;
321 recursion = true;
323 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
325 wxString str(msg);
327 // This is much simpler than manually handling all wx log-types.
328 if (str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "))) {
329 AddLogLineC(str);
330 } else {
331 AddLogLineN(str);
334 recursion = false;
336 #endif
338 CLoggerAccess::CLoggerAccess()
340 m_bufferlen = 4096;
341 m_buffer = new wxCharBuffer(m_bufferlen);
342 m_logfile = NULL;
343 Reset();
347 void CLoggerAccess::Reset()
349 delete m_logfile;
350 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
351 m_pos = 0;
352 m_ready = false;
356 CLoggerAccess::~CLoggerAccess()
358 delete m_buffer;
359 delete m_logfile;
364 // read a line of text from the logfile if available
365 // (can't believe there's no library function for this >:( )
367 bool CLoggerAccess::HasString()
369 while (!m_ready) {
370 int c = m_logfile->GetC();
371 if (c == wxEOF) {
372 break;
374 // check for buffer overrun
375 if (m_pos == m_bufferlen) {
376 m_bufferlen += 1024;
377 m_buffer->extend(m_bufferlen);
379 m_buffer->data()[m_pos++] = c;
380 if (c == '\n') {
381 if (m_buffer->data()[0] == '.') {
382 // Log-only line, skip
383 m_pos = 0;
384 } else {
385 m_ready = true;
389 return m_ready;
393 bool CLoggerAccess::GetString(wxString & s)
395 if (!HasString()) {
396 return false;
398 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
399 m_pos = 0;
400 m_ready = false;
401 return true;
404 // Functions for EC logging
405 bool ECLogIsEnabled()
407 return theLogger.IsEnabled(logEC);
410 void DoECLogLine(const wxString &line)
412 // without file/line
413 theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false);
416 // File_checked_for_headers