GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/logger.cpp Lines: 67 170 39.4 %
Date: 2018-12-09 Branches: 22 110 20.0 %

Line Branch Exec Source
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
27
#include "listeners/debugmessagelistener.h"
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
90
1
Logger::Logger() :
91
    mLogFile(nullptr),
92
    mDelayedLog(),
93
1
    mMutex(SDL_CreateMutex()),
94
    mThreadLocked(false),
95
    mLogToStandardOut(true),
96
    mDebugLog(false),
97
3
    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
1
}
103
104
Logger::~Logger()
105
{
106
    closeFile();
107
    SDL_DestroyMutex(mMutex);
108
}
109
110
void Logger::closeFile()
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
2356
void Logger::log(const std::string &str)
138
{
139

2356
    log("%s", str.c_str());
140
2356
}
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
10750
void Logger::log1(const char *const buf)
234
{
235
10750
    if (settings.disableLoggingInGame)
236
        return;
237
238
    // Get the current system time
239
    timeval tv;
240
10750
    gettimeofday(&tv, nullptr);
241
242
    // Print the log entry
243
21500
    DATESTREAM
244
    SPECIALLOG(buf)
245
246
10750
    if (mLogFile != nullptr)
247
    {
248
        fprintf(mLogFile,
249
            "%s %s\n",
250
            timeStr.c_str(),
251
            buf);
252
        fflush(mLogFile);
253
    }
254
255
10750
    if (mLogToStandardOut)
256
    {
257
10750
        fprintf(stdout,
258
            "%s %s\n",
259
            timeStr.c_str(),
260
10750
            buf);
261
    }
262
}
263
264
23249
void Logger::log(const char *const log_text, ...)
265
{
266
23249
    if (settings.disableLoggingInGame)
267
        return;
268
269
23249
    unsigned size = 1024;
270
23249
    if (strlen(log_text) * 3 > size)
271
        size = CAST_U32(strlen(log_text) * 3);
272
273
23249
    char* buf = new char[CAST_SIZE(size + 1)];
274
    va_list ap;
275
276
    // Use a temporary buffer to fill in the variables
277
23249
    va_start(ap, log_text);
278
46498
    vsnprintf(buf, size, log_text, ap);
279
23249
    buf[size] = 0;
280
23249
    va_end(ap);
281
282
    // Get the current system time
283
    timeval tv;
284
23249
    gettimeofday(&tv, nullptr);
285
286
    // Print the log entry
287
46498
    DATESTREAM
288
    SPECIALLOG(buf)
289
290
23249
    if (mLogFile != nullptr)
291
    {
292
        fprintf(mLogFile,
293
            "%s %s\n",
294
            timeStr.c_str(),
295
            buf);
296
        fflush(mLogFile);
297
    }
298
299
23249
    if (mLogToStandardOut)
300
    {
301
23249
        fprintf(stdout,
302
            "%s %s\n",
303
            timeStr.c_str(),
304
23249
            buf);
305
    }
306
307
    // Delete temporary buffer
308
23249
    delete [] buf;
309
}
310
311
70
void Logger::assertLog(const char *const log_text, ...)
312
{
313
70
    if (settings.disableLoggingInGame)
314
        return;
315
316
70
    unsigned size = 1024;
317
70
    if (strlen(log_text) * 3 > size)
318
        size = CAST_U32(strlen(log_text) * 3);
319
320
70
    char* buf = new char[CAST_SIZE(size + 1)];
321
    va_list ap;
322
323
    // Use a temporary buffer to fill in the variables
324
70
    va_start(ap, log_text);
325
140
    vsnprintf(buf, size, log_text, ap);
326
70
    buf[size] = 0;
327
70
    va_end(ap);
328
329
    // Get the current system time
330
    timeval tv;
331
70
    gettimeofday(&tv, nullptr);
332
333
    // Print the log entry
334
140
    DATESTREAM
335
    SPECIALLOG(buf)
336
337
70
    if (mLogFile != nullptr)
338
    {
339
        fprintf(mLogFile,
340
            "%s %s\n",
341
            timeStr.c_str(),
342
            buf);
343
        fflush(mLogFile);
344
    }
345
346
70
    if (mLogToStandardOut)
347
    {
348
70
        fprintf(stdout,
349
            "%s %s\n",
350
            timeStr.c_str(),
351
70
            buf);
352
    }
353
354

280
    DebugMessageListener::distributeEvent(buf);
355
356
    // Delete temporary buffer
357
70
    delete [] buf;
358
}
359
360
9
void Logger::log_r(const char *const log_text, ...)
361
{
362
9
    if (settings.disableLoggingInGame)
363
        return;
364
365
9
    SDL_mutexP(mMutex);
366
367
9
    unsigned size = 1024;
368
9
    if (strlen(log_text) * 3 > size)
369
        size = CAST_U32(strlen(log_text) * 3);
370
371
9
    char* buf = new char[CAST_SIZE(size + 1)];
372
    va_list ap;
373
374
    // Use a temporary buffer to fill in the variables
375
9
    va_start(ap, log_text);
376
18
    vsnprintf(buf, size, log_text, ap);
377
9
    buf[size] = 0;
378
9
    va_end(ap);
379
380
    // Get the current system time
381
    timeval tv;
382
9
    gettimeofday(&tv, nullptr);
383
384
    // Print the log entry
385
18
    DATESTREAM
386
    SPECIALLOG(buf)
387
388
9
    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
9
    if (mLogToStandardOut)
400
    {
401
9
        fprintf(stdout,
402
            "%s %s\n",
403
            timeStr.c_str(),
404
9
            buf);
405
    }
406
407
    // Delete temporary buffer
408
9
    delete [] buf;
409
410
9
    SDL_mutexV(mMutex);
411
}
412
413
void Logger::flush()
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
{
505
    if (!mReportUnimplemented)
506
        return;
507
508
    const std::string str = strprintf("Unimplimented packet: %d (0x%x)",
509
        id,
510
        CAST_U32(id));
511
    DebugMessageListener::distributeEvent(str);
512
    log(str);
513
}
514
515
void Logger::unimplemented(const int id,
516
                           const int id2)
517
{
518
    if (!mReportUnimplemented)
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));
526
    DebugMessageListener::distributeEvent(str);
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
{
534
    if (!mReportUnimplemented)
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);
544
    DebugMessageListener::distributeEvent(str);
545
}
546
547
FILE *Logger::getFile() const
548
{
549
    return mLogFile;
550
2
}