Fix language getting reset to system default on saving preferences
[amule.git] / src / Logger.cpp
blob03e870875003b0a8c7dbb56c6c8b52db0cb5fcec
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& DEBUG_ONLY(file),
121 int DEBUG_ONLY(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,
179 cat.GetName() + wxT(": ") + char2unicode(msg.str().c_str()));
184 const CDebugCategory& CLogger::GetDebugCategory( int index )
186 wxASSERT( index >= 0 && index < categoryCount );
188 return g_debugcats[ index ];
192 unsigned int CLogger::GetDebugCategoryCount()
194 return categoryCount;
198 bool CLogger::OpenLogfile(const wxString & name)
200 applog = new wxFFileOutputStream(name);
201 bool ret = applog->Ok();
202 if (ret) {
203 FlushApplog();
204 m_LogfileName = name;
205 } else {
206 CloseLogfile();
208 return ret;
212 void CLogger::CloseLogfile()
214 delete applog;
215 applog = NULL;
216 m_LogfileName.Clear();
220 void CLogger::OnLoggingEvent(class CLoggingEvent& evt)
222 // Remove newspace at end
223 wxString bufferline = evt.Message().Strip(wxString::trailing);
225 // Create the timestamp
226 wxString stamp = wxDateTime::Now().FormatISODate() + wxT(" ") + wxDateTime::Now().FormatISOTime()
227 #ifdef CLIENT_GUI
228 + wxT(" (remote-GUI): ");
229 #else
230 + wxT(": ");
231 #endif
233 // critical lines get a ! prepended, ordinary lines a blank
234 // logfile-only lines get a . to prevent transmission on EC
235 wxString prefix = !evt.ToGUI() ? wxT(".") : (evt.IsCritical() ? wxT("!") : wxT(" "));
237 if ( bufferline.IsEmpty() ) {
238 // If it's empty we just write a blank line with no timestamp.
239 DoLine(wxT(" \n"), evt.ToStdout(), evt.ToGUI());
240 } else {
241 // Split multi-line messages into individual lines
242 wxStringTokenizer tokens( bufferline, wxT("\n") );
243 while ( tokens.HasMoreTokens() ) {
244 wxString fullline = prefix + stamp + tokens.GetNextToken() + wxT("\n");
245 DoLine(fullline, evt.ToStdout(), evt.ToGUI());
251 void CLogger::DoLine(const wxString & line, bool toStdout, bool GUI_ONLY(toGUI))
253 ++m_count;
255 // write to logfile
256 m_ApplogBuf += line;
257 FlushApplog();
259 // write to Stdout
260 if (m_StdoutLog || toStdout) {
261 printf("%s", (const char*)unicode2char(line));
263 #ifndef AMULE_DAEMON
264 // write to Listcontrol
265 if (toGUI) {
266 theApp->AddGuiLogLine(line);
268 #endif
272 void CLogger::FlushApplog()
274 if (applog) { // Wait with output until logfile is actually opened
275 wxStringInputStream stream(m_ApplogBuf);
276 (*applog) << stream;
277 applog->Sync();
278 m_ApplogBuf.Clear();
282 CLogger theLogger;
284 BEGIN_EVENT_TABLE(CLogger, wxEvtHandler)
285 EVT_MULE_LOGGING(CLogger::OnLoggingEvent)
286 END_EVENT_TABLE()
289 CLoggerTarget::CLoggerTarget()
293 #if wxCHECK_VERSION(2, 9, 0)
294 void CLoggerTarget::DoLogText(const wxString &msg)
296 // prevent infinite recursion
297 static bool recursion = false;
298 if (recursion) {
299 return;
301 recursion = true;
303 // This is much simpler than manually handling all wx log-types.
304 if (msg.StartsWith(_("ERROR: ")) || msg.StartsWith(_("WARNING: "))) {
305 AddLogLineC(msg);
306 } else {
307 AddLogLineN(msg);
310 recursion = false;
312 #else
313 void CLoggerTarget::DoLogString(const wxChar* msg, time_t)
315 // prevent infinite recursion
316 static bool recursion = false;
317 if (recursion) {
318 return;
320 recursion = true;
322 wxCHECK_RET(msg, wxT("Log message is NULL in DoLogString!"));
324 wxString str(msg);
326 // This is much simpler than manually handling all wx log-types.
327 if (str.StartsWith(_("ERROR: ")) || str.StartsWith(_("WARNING: "))) {
328 AddLogLineC(str);
329 } else {
330 AddLogLineN(str);
333 recursion = false;
335 #endif
337 CLoggerAccess::CLoggerAccess()
339 m_bufferlen = 4096;
340 m_buffer = new wxCharBuffer(m_bufferlen);
341 m_logfile = NULL;
342 Reset();
346 void CLoggerAccess::Reset()
348 delete m_logfile;
349 m_logfile = new wxFFileInputStream(theLogger.GetLogfileName());
350 m_pos = 0;
351 m_ready = false;
355 CLoggerAccess::~CLoggerAccess()
357 delete m_buffer;
358 delete m_logfile;
363 // read a line of text from the logfile if available
364 // (can't believe there's no library function for this >:( )
366 bool CLoggerAccess::HasString()
368 while (!m_ready) {
369 int c = m_logfile->GetC();
370 if (c == wxEOF) {
371 break;
373 // check for buffer overrun
374 if (m_pos == m_bufferlen) {
375 m_bufferlen += 1024;
376 m_buffer->extend(m_bufferlen);
378 m_buffer->data()[m_pos++] = c;
379 if (c == '\n') {
380 if (m_buffer->data()[0] == '.') {
381 // Log-only line, skip
382 m_pos = 0;
383 } else {
384 m_ready = true;
388 return m_ready;
392 bool CLoggerAccess::GetString(wxString & s)
394 if (!HasString()) {
395 return false;
397 s = wxString(m_buffer->data(), wxConvUTF8, m_pos);
398 m_pos = 0;
399 m_ready = false;
400 return true;
403 // Functions for EC logging
404 bool ECLogIsEnabled()
406 return theLogger.IsEnabled(logEC);
409 void DoECLogLine(const wxString &line)
411 // without file/line
412 theLogger.AddLogLine(wxEmptyString, 0, false, logStandard, line, false, false);
415 // File_checked_for_headers