GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/logger.cpp Lines: 67 170 39.4 %
Date: 2020-06-04 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-2019  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
#ifdef __SWITCH__
124
    mLogFile = nullptr;
125
#else
126
    mLogFile = fopen(logFilename.c_str(), "wt");
127
#endif
128
129
    if (mLogFile == nullptr)
130
    {
131
        std::cout << "Warning: error while opening " << logFilename <<
132
            " for writing.\n";
133
        mLogToStandardOut = true;
134
    }
135
    else
136
    {
137
        mLogToStandardOut = false;
138
    }
139
}
140
141
2356
void Logger::log(const std::string &str)
142
{
143

2356
    log("%s", str.c_str());
144
2356
}
145
146
#ifdef ENABLEDEBUGLOG
147
void Logger::dlog(const std::string &str)
148
{
149
    if (!mDebugLog)
150
        return;
151
152
    // Get the current system time
153
    timeval tv;
154
    gettimeofday(&tv, nullptr);
155
156
    // Print the log entry
157
    DATESTREAM
158
    DSPECIALLOG(str.c_str())
159
160
    if (mLogFile != nullptr)
161
    {
162
        fprintf(mLogFile,
163
            "%s %s\n",
164
            timeStr.c_str(),
165
            str.c_str());
166
    }
167
168
    if (mLogToStandardOut)
169
    {
170
        fprintf(stdout,
171
            "%s %s\n",
172
            timeStr.c_str(),
173
            str.c_str());
174
    }
175
}
176
177
void Logger::dlog2(const std::string &str,
178
                   const int pos,
179
                   const char* const comment)
180
{
181
    if (!mDebugLog)
182
        return;
183
184
    // Get the current system time
185
    timeval tv;
186
    gettimeofday(&tv, nullptr);
187
188
    // Print the log entry
189
    DATESTREAM
190
    DSPECIALLOG(str.c_str())
191
192
    if (mLogFile != nullptr)
193
    {
194
        if (comment != nullptr)
195
        {
196
            fprintf(mLogFile,
197
                "%s %04d %s: %s\n",
198
                timeStr.c_str(),
199
                pos,
200
                str.c_str(),
201
                comment);
202
        }
203
        else
204
        {
205
            fprintf(mLogFile,
206
                "%s %04d %s\n",
207
                timeStr.c_str(),
208
                pos,
209
                str.c_str());
210
        }
211
        fflush(mLogFile);
212
    }
213
214
    if (mLogToStandardOut)
215
    {
216
        if (comment != nullptr)
217
        {
218
            fprintf(stdout,
219
                "%s %04d %s: %s\n",
220
                timeStr.c_str(),
221
                pos,
222
                str.c_str(),
223
                comment);
224
        }
225
        else
226
        {
227
            fprintf(stdout,
228
                "%s %04d %s\n",
229
                timeStr.c_str(),
230
                pos,
231
                str.c_str());
232
        }
233
    }
234
}
235
#endif  // ENABLEDEBUGLOG
236
237
10750
void Logger::log1(const char *const buf)
238
{
239
10750
    if (settings.disableLoggingInGame)
240
        return;
241
242
    // Get the current system time
243
    timeval tv;
244
10750
    gettimeofday(&tv, nullptr);
245
246
    // Print the log entry
247
21500
    DATESTREAM
248
    SPECIALLOG(buf)
249
250
10750
    if (mLogFile != nullptr)
251
    {
252
        fprintf(mLogFile,
253
            "%s %s\n",
254
            timeStr.c_str(),
255
            buf);
256
        fflush(mLogFile);
257
    }
258
259
10750
    if (mLogToStandardOut)
260
    {
261
10750
        fprintf(stdout,
262
            "%s %s\n",
263
            timeStr.c_str(),
264
10750
            buf);
265
    }
266
}
267
268
23249
void Logger::log(const char *const log_text, ...)
269
{
270
23249
    if (settings.disableLoggingInGame)
271
        return;
272
273
23249
    unsigned size = 1024;
274
23249
    if (strlen(log_text) * 3 > size)
275
        size = CAST_U32(strlen(log_text) * 3);
276
277
23249
    char* buf = new char[CAST_SIZE(size + 1)];
278
    va_list ap;
279
280
    // Use a temporary buffer to fill in the variables
281
23249
    va_start(ap, log_text);
282
46498
    vsnprintf(buf, size, log_text, ap);
283
23249
    buf[size] = 0;
284
23249
    va_end(ap);
285
286
    // Get the current system time
287
    timeval tv;
288
23249
    gettimeofday(&tv, nullptr);
289
290
    // Print the log entry
291
46498
    DATESTREAM
292
    SPECIALLOG(buf)
293
294
23249
    if (mLogFile != nullptr)
295
    {
296
        fprintf(mLogFile,
297
            "%s %s\n",
298
            timeStr.c_str(),
299
            buf);
300
        fflush(mLogFile);
301
    }
302
303
23249
    if (mLogToStandardOut)
304
    {
305
23249
        fprintf(stdout,
306
            "%s %s\n",
307
            timeStr.c_str(),
308
23249
            buf);
309
    }
310
311
    // Delete temporary buffer
312
23249
    delete [] buf;
313
}
314
315
70
void Logger::assertLog(const char *const log_text, ...)
316
{
317
70
    if (settings.disableLoggingInGame)
318
        return;
319
320
70
    unsigned size = 1024;
321
70
    if (strlen(log_text) * 3 > size)
322
        size = CAST_U32(strlen(log_text) * 3);
323
324
70
    char* buf = new char[CAST_SIZE(size + 1)];
325
    va_list ap;
326
327
    // Use a temporary buffer to fill in the variables
328
70
    va_start(ap, log_text);
329
140
    vsnprintf(buf, size, log_text, ap);
330
70
    buf[size] = 0;
331
70
    va_end(ap);
332
333
    // Get the current system time
334
    timeval tv;
335
70
    gettimeofday(&tv, nullptr);
336
337
    // Print the log entry
338
140
    DATESTREAM
339
    SPECIALLOG(buf)
340
341
70
    if (mLogFile != nullptr)
342
    {
343
        fprintf(mLogFile,
344
            "%s %s\n",
345
            timeStr.c_str(),
346
            buf);
347
        fflush(mLogFile);
348
    }
349
350
70
    if (mLogToStandardOut)
351
    {
352
70
        fprintf(stdout,
353
            "%s %s\n",
354
            timeStr.c_str(),
355
70
            buf);
356
    }
357
358

280
    DebugMessageListener::distributeEvent(buf);
359
360
    // Delete temporary buffer
361
70
    delete [] buf;
362
}
363
364
9
void Logger::log_r(const char *const log_text, ...)
365
{
366
9
    if (settings.disableLoggingInGame)
367
        return;
368
369
9
    SDL_mutexP(mMutex);
370
371
9
    unsigned size = 1024;
372
9
    if (strlen(log_text) * 3 > size)
373
        size = CAST_U32(strlen(log_text) * 3);
374
375
9
    char* buf = new char[CAST_SIZE(size + 1)];
376
    va_list ap;
377
378
    // Use a temporary buffer to fill in the variables
379
9
    va_start(ap, log_text);
380
18
    vsnprintf(buf, size, log_text, ap);
381
9
    buf[size] = 0;
382
9
    va_end(ap);
383
384
    // Get the current system time
385
    timeval tv;
386
9
    gettimeofday(&tv, nullptr);
387
388
    // Print the log entry
389
18
    DATESTREAM
390
    SPECIALLOG(buf)
391
392
9
    if (mLogFile != nullptr)
393
    {
394
        std::string tmpStr = strprintf(
395
            "%s %s\n",
396
            timeStr.c_str(),
397
            buf);
398
        mThreadLocked = true;
399
        mDelayedLog.push_back(tmpStr);
400
        mThreadLocked = false;
401
    }
402
403
9
    if (mLogToStandardOut)
404
    {
405
9
        fprintf(stdout,
406
            "%s %s\n",
407
            timeStr.c_str(),
408
9
            buf);
409
    }
410
411
    // Delete temporary buffer
412
9
    delete [] buf;
413
414
9
    SDL_mutexV(mMutex);
415
}
416
417
void Logger::flush()
418
{
419
    if (!mThreadLocked)
420
    {
421
        SDL_mutexP(mMutex);
422
        FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, mDelayedLog)
423
        {
424
            fputs((*it).c_str(), mLogFile);
425
            fputs("\n", mLogFile);
426
        }
427
        fflush(mLogFile);
428
        mDelayedLog.clear();
429
        SDL_mutexV(mMutex);
430
    }
431
}
432
433
// here string must be safe for any usage
434
void Logger::safeError(const std::string &error_text)
435
{
436
    log("Error: %s", error_text.c_str());
437
#ifdef USE_SDL2
438
    SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
439
        "Error",
440
        error_text.c_str(),
441
        nullptr);
442
#else  // USE_SDL2
443
#ifdef WIN32
444
    MessageBox(nullptr, error_text.c_str(), "Error", MB_ICONERROR | MB_OK);
445
#elif defined __APPLE__
446
//    Str255 msg;
447
//    CFStringRef error;
448
//    error = CFStringCreateWithCString(nullptr,
449
//                                      error_text.c_str(),
450
//                                      kCFStringEncodingMacRoman);
451
//    CFStringGetPascalString(error, msg, 255, kCFStringEncodingMacRoman);
452
//    StandardAlert(kAlertStopAlert,
453
//                  (const unsigned char*)"\pError",
454
//                  (ConstStr255Param) msg, nullptr, nullptr);
455
#elif defined(__linux__) || defined(__linux)
456
    std::cerr << "Error: " << error_text << std::endl;
457
    const std::string msg = std::string("xmessage \"").append(
458
        error_text).append("\"");
459
    if (system(msg.c_str()) == -1)
460
        std::cerr << "Error: " << error_text << std::endl;
461
#else  // WIN32
462
463
    std::cerr << "Error: " << error_text << std::endl;
464
#endif  // WIN32
465
#endif  // USE_SDL2
466
467
    exit(1);
468
}
469
470
// here string can be unsafe strings
471
void Logger::error(const std::string &error_text)
472
{
473
    log("Error: %s", error_text.c_str());
474
#ifdef USE_SDL2
475
    SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
476
        "Error",
477
        error_text.c_str(),
478
        nullptr);
479
#else  // USE_SDL2
480
#ifdef WIN32
481
    MessageBox(nullptr, error_text.c_str(), "Error", MB_ICONERROR | MB_OK);
482
#elif defined __APPLE__
483
//    Str255 msg;
484
//    CFStringRef error;
485
//    error = CFStringCreateWithCString(nullptr,
486
//                                      error_text.c_str(),
487
//                                      kCFStringEncodingMacRoman);
488
//    CFStringGetPascalString(error, msg, 255, kCFStringEncodingMacRoman);
489
//    StandardAlert(kAlertStopAlert,
490
//                  (const unsigned char*)"\pError",
491
//                  (ConstStr255Param) msg, nullptr, nullptr);
492
#elif defined(__linux__) || defined(__linux)
493
    std::cerr << "Error: " << error_text << std::endl;
494
    const std::string msg("xmessage \"Error happened. "
495
        "Please see log file for more information.\"");
496
    if (system(msg.c_str()) == -1)
497
        std::cerr << "Error: " << error_text << std::endl;
498
#else  // WIN32
499
500
    std::cerr << "Error: " << error_text << std::endl;
501
#endif  // WIN32
502
#endif  // USE_SDL2
503
504
    exit(1);
505
}
506
507
void Logger::unimplemented(const int id)
508
{
509
    if (!mReportUnimplemented)
510
        return;
511
512
    const std::string str = strprintf("Unimplimented packet: %d (0x%x)",
513
        id,
514
        CAST_U32(id));
515
    DebugMessageListener::distributeEvent(str);
516
    log(str);
517
}
518
519
void Logger::unimplemented(const int id,
520
                           const int id2)
521
{
522
    if (!mReportUnimplemented)
523
        return;
524
525
    const std::string str = strprintf(
526
        "Unimplimented field value %d for packet %d (0x%x)",
527
        id2,
528
        id,
529
        CAST_U32(id));
530
    DebugMessageListener::distributeEvent(str);
531
    log(str);
532
}
533
534
void Logger::unimplemented(const uint32_t id,
535
                           const uint32_t id2,
536
                           const uint32_t id3) const
537
{
538
    if (!mReportUnimplemented)
539
        return;
540
541
    const std::string str = strprintf(
542
        "Wrong actual or planned inbound packet size!. "
543
        "Packet id: %u(0x%x), Planned size: %u, Actual size: %u",
544
        id,
545
        id,
546
        id2,
547
        id3);
548
    DebugMessageListener::distributeEvent(str);
549
}
550
551
FILE *Logger::getFile() const
552
{
553
    return mLogFile;
554
2
}