GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/logger.cpp Lines: 67 170 39.4 %
Date: 2021-03-17 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
 *  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
28
#include "listeners/debugmessagelistener.h"
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
91
1
Logger::Logger() :
92
    mLogFile(nullptr),
93
    mDelayedLog(),
94
1
    mMutex(SDL_CreateMutex()),
95
    mThreadLocked(false),
96
    mLogToStandardOut(true),
97
    mDebugLog(false),
98
3
    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
1
}
104
105
Logger::~Logger()
106
{
107
    closeFile();
108
    SDL_DestroyMutex(mMutex);
109
}
110
111
void Logger::closeFile()
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
2356
void Logger::log(const std::string &str)
143
{
144

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

280
    DebugMessageListener::distributeEvent(buf);
360
361
    // Delete temporary buffer
362
70
    delete [] buf;
363
}
364
365
9
void Logger::log_r(const char *const log_text, ...)
366
{
367
9
    if (settings.disableLoggingInGame)
368
        return;
369
370
9
    SDL_mutexP(mMutex);
371
372
9
    unsigned size = 1024;
373
9
    if (strlen(log_text) * 3 > size)
374
        size = CAST_U32(strlen(log_text) * 3);
375
376
9
    char* buf = new char[CAST_SIZE(size + 1)];
377
    va_list ap;
378
379
    // Use a temporary buffer to fill in the variables
380
9
    va_start(ap, log_text);
381
18
    vsnprintf(buf, size, log_text, ap);
382
9
    buf[size] = 0;
383
9
    va_end(ap);
384
385
    // Get the current system time
386
    timeval tv;
387
9
    gettimeofday(&tv, nullptr);
388
389
    // Print the log entry
390
18
    DATESTREAM
391
    SPECIALLOG(buf)
392
393
9
    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
9
    if (mLogToStandardOut)
405
    {
406
9
        fprintf(stdout,
407
            "%s %s\n",
408
            timeStr.c_str(),
409
9
            buf);
410
    }
411
412
    // Delete temporary buffer
413
9
    delete [] buf;
414
415
9
    SDL_mutexV(mMutex);
416
}
417
418
void Logger::flush()
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
{
510
    if (!mReportUnimplemented)
511
        return;
512
513
    const std::string str = strprintf("Unimplimented packet: %d (0x%x)",
514
        id,
515
        CAST_U32(id));
516
    DebugMessageListener::distributeEvent(str);
517
    log(str);
518
}
519
520
void Logger::unimplemented(const int id,
521
                           const int id2)
522
{
523
    if (!mReportUnimplemented)
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));
531
    DebugMessageListener::distributeEvent(str);
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
{
539
    if (!mReportUnimplemented)
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);
549
    DebugMessageListener::distributeEvent(str);
550
}
551
552
FILE *Logger::getFile() const
553
{
554
    return mLogFile;
555
2
}