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