ManaPlus
logger.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2017 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "logger.h"
24 
25 #include "settings.h"
26 
28 
29 #include "utils/cast.h"
30 #include "utils/foreach.h"
31 #include "utils/stringutils.h"
32 
33 #include <iostream>
34 
35 #ifdef WIN32
36 #include <windows.h>
37 #elif defined __APPLE__
38 #include <Carbon/Carbon.h>
39 #endif // WIN32
40 
41 #include <sys/time.h>
42 
43 #include <sstream>
44 
45 #ifdef USE_SDL2
46 #include <SDL_messagebox.h>
47 #endif // USE_SDl2
48 
49 #ifdef ENABLEDEBUGLOG
50 #if defined(__ANDROID__)
51 #include <android/log.h>
52 #ifdef SPECIAL_LOGGING
53 #define SPECIALLOG(x) __android_log_print(ANDROID_LOG_INFO, "manaplus", x);
54 #define DSPECIALLOG(x) __android_log_print(ANDROID_LOG_VERBOSE, \
55  "manaplus", x);
56 #else // SPECIAL_LOGGING
57 #define SPECIALLOG(x) if (mDebugLog) \
58  __android_log_print(ANDROID_LOG_INFO, "manaplus", x);
59 #define DSPECIALLOG(x) if (mDebugLog) \
60  __android_log_print(ANDROID_LOG_VERBOSE, "manaplus", x);
61 #endif // SPECIAL_LOGGING
62 #elif defined __native_client__
63 #ifdef SPECIAL_LOGGING
64 #define SPECIALLOG(x) std::cerr << x;
65 #define DSPECIALLOG(x) std::cerr << x;
66 #else // SPECIAL_LOGGING
67 #define SPECIALLOG(x) if (mDebugLog) \
68  std::cerr << x;
69 #define DSPECIALLOG(x) if (mDebugLog) \
70  std::cerr << x;
71 #endif // SPECIAL_LOGGING
72 #else // defined(__ANDROID__)
73 #define SPECIALLOG(x)
74 #define DSPECIALLOG(x)
75 #endif // defined(__ANDROID__)
76 #endif // ENABLEDEBUGLOG
77 
78 #include "debug.h"
79 
80 #define DATESTREAM \
81  timeStr << "[" \
82  << ((((tv.tv_sec / 60) / 60) % 24 < 10) ? "0" : "") \
83  << CAST_S32(((tv.tv_sec / 60) / 60) % 24) \
84  << ":" \
85  << (((tv.tv_sec / 60) % 60 < 10) ? "0" : "") \
86  << CAST_S32((tv.tv_sec / 60) % 60) \
87  << ":" \
88  << ((tv.tv_sec % 60 < 10) ? "0" : "") \
89  << CAST_S32(tv.tv_sec % 60) \
90  << "." \
91  << (((tv.tv_usec / 10000) % 100) < 10 ? "0" : "") \
92  << CAST_S32((tv.tv_usec / 10000) % 100) \
93  << "] ";
94 
95 Logger *logger = nullptr; // Log object
96 
98  mLogFile(),
99  mDelayedLog(),
100  mMutex(SDL_CreateMutex()),
101  mThreadLocked(false),
102  mLogToStandardOut(true),
103  mDebugLog(false),
104  mReportUnimplemented(false)
105 {
106 #if defined __native_client__ && defined(NACL_LOG)
107  std::cout.setf(std::ios_base::unitbuf);
108 #endif // defined __native_client__ && defined(NACL_LOG)
109 }
110 
112 {
113  if (mLogFile.is_open())
114  mLogFile.close();
115  SDL_DestroyMutex(mMutex);
116 }
117 
118 void Logger::setLogFile(const std::string &logFilename)
119 {
120  if (mLogFile.is_open())
121  mLogFile.close();
122 
123  mLogFile.open(logFilename.c_str(), std::ios_base::trunc);
124 
125  if (!mLogFile.is_open())
126  {
127  std::cout << "Warning: error while opening " << logFilename <<
128  " for writing.\n";
129  mLogToStandardOut = true;
130  }
131  else
132  {
133  mLogToStandardOut = false;
134  }
135 }
136 
137 void Logger::log(const std::string &str)
138 {
139  log("%s", str.c_str());
140 }
141 
142 #ifdef ENABLEDEBUGLOG
143 void Logger::dlog(const std::string &str)
144 {
145  if (!mDebugLog)
146  return;
147 
148  // Get the current system time
149  timeval tv;
150  gettimeofday(&tv, nullptr);
151 
152  // Print the log entry
153  std::stringstream timeStr;
154  DATESTREAM
155  DSPECIALLOG(str.c_str())
156 
157  if (mLogFile.is_open())
158  mLogFile << timeStr.str() << str << std::endl;
159 
160  if (mLogToStandardOut)
161  std::cout << timeStr.str() << str << std::endl;
162 }
163 
164 void Logger::dlog2(const std::string &str,
165  const int pos,
166  const char* const comment)
167 {
168  if (!mDebugLog)
169  return;
170 
171  // Get the current system time
172  timeval tv;
173  gettimeofday(&tv, nullptr);
174 
175  // Print the log entry
176  std::stringstream timeStr;
177  DATESTREAM
178  DSPECIALLOG(str.c_str())
179 
180  if (mLogFile.is_open())
181  {
182  if (comment != nullptr)
183  {
184  mLogFile << timeStr.str();
185  mLogFile.fill('0');
186  mLogFile.width(4);
187  mLogFile << pos << " ";
188  mLogFile << str << ": " << comment << std::endl;
189  }
190  else
191  {
192  mLogFile << timeStr.str();
193  mLogFile.fill('0');
194  mLogFile.width(4);
195  mLogFile << pos << " ";
196  mLogFile << str << std::endl;
197  }
198  }
199 
200  if (mLogToStandardOut)
201  {
202  if (comment != nullptr)
203  {
204  std::cout << timeStr.str();
205  std::cout.fill('0');
206  std::cout.width(4);
207  std::cout << pos << " ";
208  std::cout << str << ": " << comment << std::endl;
209  }
210  else
211  {
212  std::cout << timeStr.str();
213  std::cout.fill('0');
214  std::cout.width(4);
215  std::cout << pos << " ";
216  std::cout << str << std::endl;
217  }
218  }
219 }
220 #endif // ENABLEDEBUGLOG
221 
222 void Logger::log1(const char *const buf)
223 {
225  return;
226 
227  // Get the current system time
228  timeval tv;
229  gettimeofday(&tv, nullptr);
230 
231  // Print the log entry
232  std::stringstream timeStr;
233  DATESTREAM
234  SPECIALLOG(buf)
235 
236  if (mLogFile.is_open())
237  mLogFile << timeStr.str() << buf << std::endl;
238 
239  if (mLogToStandardOut)
240  std::cout << timeStr.str() << buf << std::endl;
241 }
242 
243 void Logger::log(const char *const log_text, ...)
244 {
246  return;
247 
248  unsigned size = 1024;
249  if (strlen(log_text) * 3 > size)
250  size = CAST_U32(strlen(log_text) * 3);
251 
252  char* buf = new char[CAST_SIZE(size + 1)];
253  va_list ap;
254 
255  // Use a temporary buffer to fill in the variables
256  va_start(ap, log_text);
257  vsnprintf(buf, size, log_text, ap);
258  buf[size] = 0;
259  va_end(ap);
260 
261  // Get the current system time
262  timeval tv;
263  gettimeofday(&tv, nullptr);
264 
265  // Print the log entry
266  std::stringstream timeStr;
267  DATESTREAM
268  SPECIALLOG(buf)
269 
270  if (mLogFile.is_open())
271  mLogFile << timeStr.str() << buf << std::endl;
272 
273  if (mLogToStandardOut)
274  std::cout << timeStr.str() << buf << std::endl;
275 
276  // Delete temporary buffer
277  delete [] buf;
278 }
279 
280 void Logger::assertLog(const char *const log_text, ...)
281 {
283  return;
284 
285  unsigned size = 1024;
286  if (strlen(log_text) * 3 > size)
287  size = CAST_U32(strlen(log_text) * 3);
288 
289  char* buf = new char[CAST_SIZE(size + 1)];
290  va_list ap;
291 
292  // Use a temporary buffer to fill in the variables
293  va_start(ap, log_text);
294  vsnprintf(buf, size, log_text, ap);
295  buf[size] = 0;
296  va_end(ap);
297 
298  // Get the current system time
299  timeval tv;
300  gettimeofday(&tv, nullptr);
301 
302  // Print the log entry
303  std::stringstream timeStr;
304  DATESTREAM
305  SPECIALLOG(buf)
306 
307  if (mLogFile.is_open())
308  mLogFile << timeStr.str() << buf << std::endl;
309 
310  if (mLogToStandardOut)
311  std::cout << timeStr.str() << buf << std::endl;
312 
314 
315  // Delete temporary buffer
316  delete [] buf;
317 }
318 
319 void Logger::log_r(const char *const log_text, ...)
320 {
322  return;
323 
324  SDL_mutexP(mMutex);
325 
326  unsigned size = 1024;
327  if (strlen(log_text) * 3 > size)
328  size = CAST_U32(strlen(log_text) * 3);
329 
330  char* buf = new char[CAST_SIZE(size + 1)];
331  va_list ap;
332 
333  // Use a temporary buffer to fill in the variables
334  va_start(ap, log_text);
335  vsnprintf(buf, size, log_text, ap);
336  buf[size] = 0;
337  va_end(ap);
338 
339  // Get the current system time
340  timeval tv;
341  gettimeofday(&tv, nullptr);
342 
343  // Print the log entry
344  std::stringstream timeStr;
345  DATESTREAM
346  SPECIALLOG(buf)
347 
348  if (mLogFile.is_open())
349  {
350  timeStr << buf;
351  mThreadLocked = true;
352  mDelayedLog.push_back(timeStr.str());
353  mThreadLocked = false;
354  }
355 
356  if (mLogToStandardOut)
357  std::cout << timeStr.str() << buf << std::endl;
358 
359  // Delete temporary buffer
360  delete [] buf;
361 
362  SDL_mutexV(mMutex);
363 }
364 
366 {
367  if (!mThreadLocked)
368  {
369  SDL_mutexP(mMutex);
370  FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, mDelayedLog)
371  mLogFile << *it << std::endl;
372  mDelayedLog.clear();
373  SDL_mutexV(mMutex);
374  }
375 }
376 
377 // here string must be safe for any usage
378 void Logger::safeError(const std::string &error_text)
379 {
380  log("Error: %s", error_text.c_str());
381 #ifdef USE_SDL2
382  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
383  "Error",
384  error_text.c_str(),
385  nullptr);
386 #else // USE_SDL2
387 #ifdef WIN32
388  MessageBox(nullptr, error_text.c_str(), "Error", MB_ICONERROR | MB_OK);
389 #elif defined __APPLE__
390 // Str255 msg;
391 // CFStringRef error;
392 // error = CFStringCreateWithCString(nullptr,
393 // error_text.c_str(),
394 // kCFStringEncodingMacRoman);
395 // CFStringGetPascalString(error, msg, 255, kCFStringEncodingMacRoman);
396 // StandardAlert(kAlertStopAlert,
397 // (const unsigned char*)"\pError",
398 // (ConstStr255Param) msg, nullptr, nullptr);
399 #elif defined(__linux__) || defined(__linux)
400  std::cerr << "Error: " << error_text << std::endl;
401  const std::string msg = std::string("xmessage \"").append(
402  error_text).append("\"");
403  if (system(msg.c_str()) == -1)
404  std::cerr << "Error: " << error_text << std::endl;
405 #else // WIN32
406 
407  std::cerr << "Error: " << error_text << std::endl;
408 #endif // WIN32
409 #endif // USE_SDL2
410 
411  exit(1);
412 }
413 
414 // here string can be unsafe strings
415 void Logger::error(const std::string &error_text)
416 {
417  log("Error: %s", error_text.c_str());
418 #ifdef USE_SDL2
419  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
420  "Error",
421  error_text.c_str(),
422  nullptr);
423 #else // USE_SDL2
424 #ifdef WIN32
425  MessageBox(nullptr, error_text.c_str(), "Error", MB_ICONERROR | MB_OK);
426 #elif defined __APPLE__
427 // Str255 msg;
428 // CFStringRef error;
429 // error = CFStringCreateWithCString(nullptr,
430 // error_text.c_str(),
431 // kCFStringEncodingMacRoman);
432 // CFStringGetPascalString(error, msg, 255, kCFStringEncodingMacRoman);
433 // StandardAlert(kAlertStopAlert,
434 // (const unsigned char*)"\pError",
435 // (ConstStr255Param) msg, nullptr, nullptr);
436 #elif defined(__linux__) || defined(_linux)
437  std::cerr << "Error: " << error_text << std::endl;
438  const std::string msg("xmessage \"Error happened. "
439  "Please see log file for more information.\"");
440  if (system(msg.c_str()) == -1)
441  std::cerr << "Error: " << error_text << std::endl;
442 #else // WIN32
443 
444  std::cerr << "Error: " << error_text << std::endl;
445 #endif // WIN32
446 #endif // USE_SDL2
447 
448  exit(1);
449 }
450 
451 void Logger::unimplemented(const int id)
452 {
454  return;
455 
456  const std::string str = strprintf("Unimplimented packet: %d (0x%x)",
457  id,
458  CAST_U32(id));
460  log(str);
461 }
462 
463 void Logger::unimplemented(const int id,
464  const int id2)
465 {
467  return;
468 
469  const std::string str = strprintf(
470  "Unimplimented field value %d for packet %d (0x%x)",
471  id2,
472  id,
473  CAST_U32(id));
475  log(str);
476 }
477 
478 void Logger::unimplemented(const uint32_t id,
479  const uint32_t id2,
480  const uint32_t id3) const
481 {
483  return;
484 
485  const std::string str = strprintf(
486  "Wrong actual or planned inbound packet size!. "
487  "Packet id: %u(0x%x), Planned size: %u, Actual size: %u",
488  id,
489  id,
490  id2,
491  id3);
493 }
Definition: logger.h:67
#define CAST_U32
Definition: cast.h:30
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
void log1(const char *const log_text)
Definition: logger.cpp:222
volatile bool mThreadLocked
Definition: logger.h:217
~Logger()
Definition: logger.cpp:111
bool msg(InputEvent &event)
Definition: chat.cpp:38
Logger()
Definition: logger.cpp:97
void log_r(const char *const log_text,...)
Definition: logger.cpp:319
void flush()
Definition: logger.cpp:365
Logger * logger
Definition: logger.cpp:95
Settings settings
Definition: settings.cpp:31
bool mLogToStandardOut
Definition: logger.h:218
void dlog2(const std::string &str, const int pos, const char *const comment)
Definition: logger.cpp:164
std::string strprintf(const char *const format,...)
Definition: stringutils.cpp:99
#define SPECIALLOG(x)
Definition: logger.cpp:73
void dlog(const std::string &str)
Definition: logger.cpp:143
std::vector< std::string > mDelayedLog
Definition: logger.h:215
void safeError(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:378
void unimplemented(const int id)
Definition: logger.cpp:451
bool disableLoggingInGame
Definition: settings.h:158
SDL_mutex * mMutex
Definition: logger.h:216
bool mReportUnimplemented
Definition: logger.h:220
void setLogFile(const std::string &logFilename)
Definition: logger.cpp:118
#define CAST_SIZE
Definition: cast.h:33
void error(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:415
static void distributeEvent(const std::string &msg)
void log(const char *const log_text,...)
Definition: logger.cpp:243
bool mDebugLog
Definition: logger.h:219
#define DSPECIALLOG(x)
Definition: logger.cpp:74
void assertLog(const char *const log_text,...)
Definition: logger.cpp:280
std::ofstream mLogFile
Definition: logger.h:214
#define DATESTREAM
Definition: logger.cpp:80