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-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
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  * any later version.
14  *
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, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "logger.h"
25 
26 #include "settings.h"
27 
29 
30 #include "utils/cast.h"
31 #include "utils/foreach.h"
32 #include "utils/stringutils.h"
33 
34 #include <iostream>
35 
36 #ifdef WIN32
37 #include <windows.h>
38 #elif defined __APPLE__
39 #include <Carbon/Carbon.h>
40 #endif // WIN32
41 
42 #include <sys/time.h>
43 
44 #include <sstream>
45 
46 #ifdef USE_SDL2
47 #include <SDL_messagebox.h>
48 #endif // USE_SDl2
49 
50 #ifdef ENABLEDEBUGLOG
51 #if defined(__ANDROID__)
52 #include <android/log.h>
53 #ifdef SPECIAL_LOGGING
54 #define SPECIALLOG(x) __android_log_print(ANDROID_LOG_INFO, "manaplus", x);
55 #define DSPECIALLOG(x) __android_log_print(ANDROID_LOG_VERBOSE, \
56  "manaplus", x);
57 #else // SPECIAL_LOGGING
58 #define SPECIALLOG(x) if (mDebugLog) \
59  __android_log_print(ANDROID_LOG_INFO, "manaplus", x);
60 #define DSPECIALLOG(x) if (mDebugLog) \
61  __android_log_print(ANDROID_LOG_VERBOSE, "manaplus", x);
62 #endif // SPECIAL_LOGGING
63 #elif defined __native_client__
64 #ifdef SPECIAL_LOGGING
65 #define SPECIALLOG(x) std::cerr << x;
66 #define DSPECIALLOG(x) std::cerr << x;
67 #else // SPECIAL_LOGGING
68 #define SPECIALLOG(x) if (mDebugLog) \
69  std::cerr << x;
70 #define DSPECIALLOG(x) if (mDebugLog) \
71  std::cerr << x;
72 #endif // SPECIAL_LOGGING
73 #else // defined(__ANDROID__)
74 #define SPECIALLOG(x)
75 #define DSPECIALLOG(x)
76 #endif // defined(__ANDROID__)
77 #endif // ENABLEDEBUGLOG
78 
79 #include "debug.h"
80 
81 #define DATESTREAM \
82  std::string timeStr = strprintf( \
83  "[%02d:%02d:%02d.%02d]", \
84  CAST_S32(((tv.tv_sec / 60) / 60) % 24), \
85  CAST_S32((tv.tv_sec / 60) % 60), \
86  CAST_S32(tv.tv_sec % 60), \
87  CAST_S32((tv.tv_usec / 10000) % 100));
88 
89 Logger *logger = nullptr; // Log object
90 
92  mLogFile(nullptr),
93  mDelayedLog(),
94  mMutex(SDL_CreateMutex()),
95  mThreadLocked(false),
96  mLogToStandardOut(true),
97  mDebugLog(false),
98  mReportUnimplemented(false)
99 {
100 #if defined __native_client__ && defined(NACL_LOG)
101  std::cout.setf(std::ios_base::unitbuf);
102 #endif // defined __native_client__ && defined(NACL_LOG)
103 }
104 
106 {
107  closeFile();
108  SDL_DestroyMutex(mMutex);
109 }
110 
112 {
113  if (mLogFile != nullptr)
114  {
115  fclose(mLogFile);
116  mLogFile = nullptr;
117  }
118 }
119 
120 void Logger::setLogFile(const std::string &logFilename)
121 {
122  closeFile();
123 
124 #ifdef __SWITCH__
125  mLogFile = nullptr;
126 #else
127  mLogFile = fopen(logFilename.c_str(), "wt");
128 #endif
129 
130  if (mLogFile == nullptr)
131  {
132  std::cout << "Warning: error while opening " << logFilename <<
133  " for writing.\n";
134  mLogToStandardOut = true;
135  }
136  else
137  {
138  mLogToStandardOut = false;
139  }
140 }
141 
142 void Logger::log(const std::string &str)
143 {
144  log("%s", str.c_str());
145 }
146 
147 #ifdef ENABLEDEBUGLOG
148 void Logger::dlog(const std::string &str)
149 {
150  if (!mDebugLog)
151  return;
152 
153  // Get the current system time
154  timeval tv;
155  gettimeofday(&tv, nullptr);
156 
157  // Print the log entry
158  DATESTREAM
159  DSPECIALLOG(str.c_str())
160 
161  if (mLogFile != nullptr)
162  {
163  fprintf(mLogFile,
164  "%s %s\n",
165  timeStr.c_str(),
166  str.c_str());
167  }
168 
169  if (mLogToStandardOut)
170  {
171  fprintf(stdout,
172  "%s %s\n",
173  timeStr.c_str(),
174  str.c_str());
175  }
176 }
177 
178 void Logger::dlog2(const std::string &str,
179  const int pos,
180  const char* const comment)
181 {
182  if (!mDebugLog)
183  return;
184 
185  // Get the current system time
186  timeval tv;
187  gettimeofday(&tv, nullptr);
188 
189  // Print the log entry
190  DATESTREAM
191  DSPECIALLOG(str.c_str())
192 
193  if (mLogFile != nullptr)
194  {
195  if (comment != nullptr)
196  {
197  fprintf(mLogFile,
198  "%s %04d %s: %s\n",
199  timeStr.c_str(),
200  pos,
201  str.c_str(),
202  comment);
203  }
204  else
205  {
206  fprintf(mLogFile,
207  "%s %04d %s\n",
208  timeStr.c_str(),
209  pos,
210  str.c_str());
211  }
212  fflush(mLogFile);
213  }
214 
215  if (mLogToStandardOut)
216  {
217  if (comment != nullptr)
218  {
219  fprintf(stdout,
220  "%s %04d %s: %s\n",
221  timeStr.c_str(),
222  pos,
223  str.c_str(),
224  comment);
225  }
226  else
227  {
228  fprintf(stdout,
229  "%s %04d %s\n",
230  timeStr.c_str(),
231  pos,
232  str.c_str());
233  }
234  }
235 }
236 #endif // ENABLEDEBUGLOG
237 
238 void Logger::log1(const char *const buf)
239 {
241  return;
242 
243  // Get the current system time
244  timeval tv;
245  gettimeofday(&tv, nullptr);
246 
247  // Print the log entry
248  DATESTREAM
249  SPECIALLOG(buf)
250 
251  if (mLogFile != nullptr)
252  {
253  fprintf(mLogFile,
254  "%s %s\n",
255  timeStr.c_str(),
256  buf);
257  fflush(mLogFile);
258  }
259 
260  if (mLogToStandardOut)
261  {
262  fprintf(stdout,
263  "%s %s\n",
264  timeStr.c_str(),
265  buf);
266  }
267 }
268 
269 void Logger::log(const char *const log_text, ...)
270 {
272  return;
273 
274  unsigned size = 1024;
275  if (strlen(log_text) * 3 > size)
276  size = CAST_U32(strlen(log_text) * 3);
277 
278  char* buf = new char[CAST_SIZE(size + 1)];
279  va_list ap;
280 
281  // Use a temporary buffer to fill in the variables
282  va_start(ap, log_text);
283  vsnprintf(buf, size, log_text, ap);
284  buf[size] = 0;
285  va_end(ap);
286 
287  // Get the current system time
288  timeval tv;
289  gettimeofday(&tv, nullptr);
290 
291  // Print the log entry
292  DATESTREAM
293  SPECIALLOG(buf)
294 
295  if (mLogFile != nullptr)
296  {
297  fprintf(mLogFile,
298  "%s %s\n",
299  timeStr.c_str(),
300  buf);
301  fflush(mLogFile);
302  }
303 
304  if (mLogToStandardOut)
305  {
306  fprintf(stdout,
307  "%s %s\n",
308  timeStr.c_str(),
309  buf);
310  }
311 
312  // Delete temporary buffer
313  delete [] buf;
314 }
315 
316 void Logger::assertLog(const char *const log_text, ...)
317 {
319  return;
320 
321  unsigned size = 1024;
322  if (strlen(log_text) * 3 > size)
323  size = CAST_U32(strlen(log_text) * 3);
324 
325  char* buf = new char[CAST_SIZE(size + 1)];
326  va_list ap;
327 
328  // Use a temporary buffer to fill in the variables
329  va_start(ap, log_text);
330  vsnprintf(buf, size, log_text, ap);
331  buf[size] = 0;
332  va_end(ap);
333 
334  // Get the current system time
335  timeval tv;
336  gettimeofday(&tv, nullptr);
337 
338  // Print the log entry
339  DATESTREAM
340  SPECIALLOG(buf)
341 
342  if (mLogFile != nullptr)
343  {
344  fprintf(mLogFile,
345  "%s %s\n",
346  timeStr.c_str(),
347  buf);
348  fflush(mLogFile);
349  }
350 
351  if (mLogToStandardOut)
352  {
353  fprintf(stdout,
354  "%s %s\n",
355  timeStr.c_str(),
356  buf);
357  }
358 
360 
361  // Delete temporary buffer
362  delete [] buf;
363 }
364 
365 void Logger::log_r(const char *const log_text, ...)
366 {
368  return;
369 
370  SDL_mutexP(mMutex);
371 
372  unsigned size = 1024;
373  if (strlen(log_text) * 3 > size)
374  size = CAST_U32(strlen(log_text) * 3);
375 
376  char* buf = new char[CAST_SIZE(size + 1)];
377  va_list ap;
378 
379  // Use a temporary buffer to fill in the variables
380  va_start(ap, log_text);
381  vsnprintf(buf, size, log_text, ap);
382  buf[size] = 0;
383  va_end(ap);
384 
385  // Get the current system time
386  timeval tv;
387  gettimeofday(&tv, nullptr);
388 
389  // Print the log entry
390  DATESTREAM
391  SPECIALLOG(buf)
392 
393  if (mLogFile != nullptr)
394  {
395  std::string tmpStr = strprintf(
396  "%s %s\n",
397  timeStr.c_str(),
398  buf);
399  mThreadLocked = true;
400  mDelayedLog.push_back(tmpStr);
401  mThreadLocked = false;
402  }
403 
404  if (mLogToStandardOut)
405  {
406  fprintf(stdout,
407  "%s %s\n",
408  timeStr.c_str(),
409  buf);
410  }
411 
412  // Delete temporary buffer
413  delete [] buf;
414 
415  SDL_mutexV(mMutex);
416 }
417 
419 {
420  if (!mThreadLocked)
421  {
422  SDL_mutexP(mMutex);
423  FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, mDelayedLog)
424  {
425  fputs((*it).c_str(), mLogFile);
426  fputs("\n", mLogFile);
427  }
428  fflush(mLogFile);
429  mDelayedLog.clear();
430  SDL_mutexV(mMutex);
431  }
432 }
433 
434 // here string must be safe for any usage
435 void Logger::safeError(const std::string &error_text)
436 {
437  log("Error: %s", error_text.c_str());
438 #ifdef USE_SDL2
439  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
440  "Error",
441  error_text.c_str(),
442  nullptr);
443 #else // USE_SDL2
444 #ifdef WIN32
445  MessageBox(nullptr, error_text.c_str(), "Error", MB_ICONERROR | MB_OK);
446 #elif defined __APPLE__
447 // Str255 msg;
448 // CFStringRef error;
449 // error = CFStringCreateWithCString(nullptr,
450 // error_text.c_str(),
451 // kCFStringEncodingMacRoman);
452 // CFStringGetPascalString(error, msg, 255, kCFStringEncodingMacRoman);
453 // StandardAlert(kAlertStopAlert,
454 // (const unsigned char*)"\pError",
455 // (ConstStr255Param) msg, nullptr, nullptr);
456 #elif defined(__linux__) || defined(__linux)
457  std::cerr << "Error: " << error_text << std::endl;
458  const std::string msg = std::string("xmessage \"").append(
459  error_text).append("\"");
460  if (system(msg.c_str()) == -1)
461  std::cerr << "Error: " << error_text << std::endl;
462 #else // WIN32
463 
464  std::cerr << "Error: " << error_text << std::endl;
465 #endif // WIN32
466 #endif // USE_SDL2
467 
468  exit(1);
469 }
470 
471 // here string can be unsafe strings
472 void Logger::error(const std::string &error_text)
473 {
474  log("Error: %s", error_text.c_str());
475 #ifdef USE_SDL2
476  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
477  "Error",
478  error_text.c_str(),
479  nullptr);
480 #else // USE_SDL2
481 #ifdef WIN32
482  MessageBox(nullptr, error_text.c_str(), "Error", MB_ICONERROR | MB_OK);
483 #elif defined __APPLE__
484 // Str255 msg;
485 // CFStringRef error;
486 // error = CFStringCreateWithCString(nullptr,
487 // error_text.c_str(),
488 // kCFStringEncodingMacRoman);
489 // CFStringGetPascalString(error, msg, 255, kCFStringEncodingMacRoman);
490 // StandardAlert(kAlertStopAlert,
491 // (const unsigned char*)"\pError",
492 // (ConstStr255Param) msg, nullptr, nullptr);
493 #elif defined(__linux__) || defined(__linux)
494  std::cerr << "Error: " << error_text << std::endl;
495  const std::string msg("xmessage \"Error happened. "
496  "Please see log file for more information.\"");
497  if (system(msg.c_str()) == -1)
498  std::cerr << "Error: " << error_text << std::endl;
499 #else // WIN32
500 
501  std::cerr << "Error: " << error_text << std::endl;
502 #endif // WIN32
503 #endif // USE_SDL2
504 
505  exit(1);
506 }
507 
508 void Logger::unimplemented(const int id)
509 {
511  return;
512 
513  const std::string str = strprintf("Unimplimented packet: %d (0x%x)",
514  id,
515  CAST_U32(id));
517  log(str);
518 }
519 
520 void Logger::unimplemented(const int id,
521  const int id2)
522 {
524  return;
525 
526  const std::string str = strprintf(
527  "Unimplimented field value %d for packet %d (0x%x)",
528  id2,
529  id,
530  CAST_U32(id));
532  log(str);
533 }
534 
535 void Logger::unimplemented(const uint32_t id,
536  const uint32_t id2,
537  const uint32_t id3) const
538 {
540  return;
541 
542  const std::string str = strprintf(
543  "Wrong actual or planned inbound packet size!. "
544  "Packet id: %u(0x%x), Planned size: %u, Actual size: %u",
545  id,
546  id,
547  id2,
548  id3);
550 }
551 
552 FILE *Logger::getFile() const
553 {
554  return mLogFile;
555 }
#define CAST_U32
Definition: cast.h:31
#define CAST_SIZE
Definition: cast.h:34
static void distributeEvent(const std::string &msg)
Definition: logger.h:69
bool mLogToStandardOut
Definition: logger.h:223
bool mDebugLog
Definition: logger.h:224
void log(const char *const log_text,...)
Definition: logger.cpp:269
void log_r(const char *const log_text,...)
Definition: logger.cpp:365
FILE * getFile() const
Definition: logger.cpp:552
SDL_mutex * mMutex
Definition: logger.h:221
void unimplemented(const int id)
Definition: logger.cpp:508
void assertLog(const char *const log_text,...)
Definition: logger.cpp:316
void log1(const char *const log_text)
Definition: logger.cpp:238
void safeError(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:435
void flush()
Definition: logger.cpp:418
bool mReportUnimplemented
Definition: logger.h:225
FILE * mLogFile
Definition: logger.h:219
void error(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:472
volatile bool mThreadLocked
Definition: logger.h:222
void closeFile()
Definition: logger.cpp:111
Logger()
Definition: logger.cpp:91
void dlog2(const std::string &str, const int pos, const char *const comment)
Definition: logger.cpp:178
void dlog(const std::string &str)
Definition: logger.cpp:148
~Logger()
Definition: logger.cpp:105
std::vector< std::string > mDelayedLog
Definition: logger.h:220
void setLogFile(const std::string &logFilename)
Definition: logger.cpp:120
bool disableLoggingInGame
Definition: settings.h:161
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define nullptr
Definition: localconsts.h:45
Logger * logger
Definition: logger.cpp:89
#define DSPECIALLOG(x)
Definition: logger.cpp:75
#define SPECIALLOG(x)
Definition: logger.cpp:74
#define DATESTREAM
Definition: logger.cpp:81
bool msg(InputEvent &event)
Definition: chat.cpp:39
int size()
Definition: emotedb.cpp:306
Settings settings
Definition: settings.cpp:32
std::string strprintf(const char *const format,...)