Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
2 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
#include <iostream>
19
#include <fstream>
20
#include <sstream>
21
#include <ios>
22
#include <time.h>
14 andreas 23
#include <mutex>
24
 
2 andreas 25
#include "terror.h"
26
#include "tconfig.h"
27
 
22 andreas 28
#if defined(__linux__) || defined(Q_OS_ANDROID)
29
#include <QMessageBox>
30
#include <QTimer>
31
#endif
23 andreas 32
#if LOGPATH == LPATH_SYSLOG || defined(__ANDROID__)
22 andreas 33
#   ifdef __ANDROID__
34
#       include <android/log.h>
35
#   else
36
#       include <syslog.h>
37
#   endif
38
#endif
39
 
2 andreas 40
using std::string;
14 andreas 41
std::mutex message_mutex;
2 andreas 42
 
43
bool TError::mHaveError = false;
44
terrtype_t TError::mErrType = TERRNONE;
45
TStreamError *TError::mCurrent = nullptr;
46
std::string TError::msError;
47
 
48
int TStreamError::mIndent = 1;
49
std::ostream *TStreamError::mStream = nullptr;
50
std::string TStreamError::mLogfile;
51
bool TStreamError::mInitialized = false;
23 andreas 52
unsigned int TStreamError::mLogLevel = HLOG_PROTOCOL;
2 andreas 53
 
23 andreas 54
#if LOGPATH == LPATH_SYSLOG || defined(__ANDROID__)
55
class androidbuf : public std::streambuf
56
{
57
    public:
58
        enum { bufsize = 512 };
59
        androidbuf() { this->setp(buffer, buffer + bufsize - 1); }
60
 
61
    private:
62
        int overflow(int c)
63
        {
64
            if (c == traits_type::eof())
65
            {
66
                *this->pptr() = traits_type::to_char_type(c);
67
                this->sbumpc();
68
            }
69
 
70
            return this->sync()? traits_type::eof(): traits_type::not_eof(c);
71
        }
72
 
73
        int sync()
74
        {
75
            int rc = 0;
76
 
77
            if (this->pbase() != this->pptr())
78
            {
79
                char writebuf[bufsize+1];
80
                memcpy(writebuf, this->pbase(), this->pptr() - this->pbase());
81
                writebuf[this->pptr() - this->pbase()] = '\0';
82
                int eType;
83
#ifdef __ANDROID__
84
                switch(TError::getErrorType())
85
                {
86
                    case TERRINFO:      eType = ANDROID_LOG_INFO; break;
87
                    case TERRWARNING:   eType = ANDROID_LOG_WARN; break;
88
                    case TERRERROR:     eType = ANDROID_LOG_ERROR; break;
89
                    case TERRTRACE:     eType = ANDROID_LOG_VERBOSE; break;
90
                    case TERRDEBUG:     eType = ANDROID_LOG_DEBUG; break;
26 andreas 91
                    case TERRNONE:      eType = ANDROID_LOG_INFO; break;
23 andreas 92
                }
93
 
94
                rc = __android_log_print(eType, "tpanel", "%s", writebuf) > 0;
95
#else
96
                switch(TError::getErrorType())
97
                {
98
                    case TERRINFO:      eType = LOG_INFO; break;
99
                    case TERRWARNING:   eType = LOG_WARN; break;
100
                    case TERRERROR:     eType = LOG_ERROR; break;
101
                    case TERRTRACE:     eType = LOG_INFO; break;
102
                    case TERRDEBUG:     eType = LOG_DEBUG; break;
103
                    case TERRNONE:      eType = LOG_INFO; break;
104
                }
105
 
106
                syslog(eType, writebuf);
26 andreas 107
                rc = 1;
22 andreas 108
#endif
23 andreas 109
                this->setp(buffer, buffer + bufsize - 1);
110
            }
22 andreas 111
 
23 andreas 112
            return rc;
113
        }
114
 
115
        char buffer[bufsize];
116
};
117
#endif
118
 
2 andreas 119
TStreamError::TStreamError(const string& logFile, const std::string& logLevel)
120
{
116 andreas 121
    if (!TConfig::isInitialized())
122
        return;
123
 
14 andreas 124
    if (!logFile.empty())
23 andreas 125
        mLogfile = logFile;
14 andreas 126
    else if (!TConfig::getLogFile().empty())
23 andreas 127
        mLogfile = TConfig::getLogFile();
2 andreas 128
 
14 andreas 129
    if (!logLevel.empty())
130
        setLogLevel(logLevel);
131
    else if (!TConfig::getLogLevel().empty())
132
        setLogLevel(TConfig::getLogFile());
2 andreas 133
 
14 andreas 134
    _init();
2 andreas 135
}
136
 
137
TStreamError::~TStreamError()
138
{
14 andreas 139
    if (mStream && mStream != &std::cout)
140
    {
141
        delete mStream;
142
        mStream = nullptr;
143
        mInitialized = false;
144
    }
2 andreas 145
}
146
 
23 andreas 147
void TStreamError::setLogFile(const std::string &lf)
148
{
116 andreas 149
    if (mInitialized && mLogfile.compare(lf) == 0)
23 andreas 150
        return;
151
 
152
    mLogfile = lf;
153
    mInitialized = false;
154
    _init();
155
}
156
 
2 andreas 157
void TStreamError::setLogLevel(const std::string& slv)
158
{
14 andreas 159
    size_t pos = slv.find("|");
160
    size_t start = 0;
161
    string lv;
162
    mLogLevel = 0;
2 andreas 163
 
14 andreas 164
    while (pos != string::npos)
165
    {
166
        lv = slv.substr(start, pos - start);
167
        start = pos + 1;
168
        mLogLevel |= _getLevel(lv);
169
        pos = slv.find("|", start);
170
    }
2 andreas 171
 
14 andreas 172
    mLogLevel |= _getLevel(slv.substr(start));
2 andreas 173
}
174
 
175
bool TStreamError::checkFilter(terrtype_t err)
176
{
116 andreas 177
    if (!TConfig::isInitialized())
178
        return false;
179
 
23 andreas 180
    if (err == TERRINFO && (mLogLevel & HLOG_INFO) != 0)
14 andreas 181
        return true;
23 andreas 182
    else if (err == TERRWARNING && (mLogLevel & HLOG_WARNING) != 0)
14 andreas 183
        return true;
23 andreas 184
    else if (err == TERRERROR && (mLogLevel & HLOG_ERROR) != 0)
14 andreas 185
        return true;
23 andreas 186
    else if (err == TERRTRACE && (mLogLevel & HLOG_TRACE) != 0)
14 andreas 187
        return true;
23 andreas 188
    else if (err == TERRDEBUG && (mLogLevel & HLOG_DEBUG) != 0)
14 andreas 189
        return true;
2 andreas 190
 
14 andreas 191
    return false;
2 andreas 192
}
193
 
194
bool TStreamError::checkFilter(int lv)
195
{
116 andreas 196
    if (!TConfig::isInitialized())
197
        return false;
198
 
14 andreas 199
    if ((mLogLevel & lv) != 0)
200
        return true;
2 andreas 201
 
14 andreas 202
    return false;
2 andreas 203
}
204
 
205
unsigned int TStreamError::_getLevel(const std::string& slv)
206
{
14 andreas 207
    if (slv.compare(SLOG_NONE) == 0)
23 andreas 208
        return HLOG_NONE;
2 andreas 209
 
14 andreas 210
    if (slv.compare(SLOG_INFO) == 0)
23 andreas 211
        return HLOG_INFO;
2 andreas 212
 
14 andreas 213
    if (slv.compare(SLOG_WARNING) == 0)
23 andreas 214
        return HLOG_WARNING;
2 andreas 215
 
14 andreas 216
    if (slv.compare(SLOG_ERROR) == 0)
23 andreas 217
        return HLOG_ERROR;
2 andreas 218
 
14 andreas 219
    if (slv.compare(SLOG_TRACE) == 0)
23 andreas 220
        return HLOG_TRACE;
2 andreas 221
 
14 andreas 222
    if (slv.compare(SLOG_DEBUG) == 0)
23 andreas 223
        return HLOG_DEBUG;
2 andreas 224
 
14 andreas 225
    if (slv.compare(SLOG_PROTOCOL) == 0)
23 andreas 226
        return HLOG_PROTOCOL;
2 andreas 227
 
14 andreas 228
    if (slv.compare(SLOG_ALL) == 0)
23 andreas 229
        return HLOG_ALL;
2 andreas 230
 
23 andreas 231
    return HLOG_NONE;
2 andreas 232
}
233
 
234
void TStreamError::_init()
235
{
116 andreas 236
    if (!TConfig::isInitialized() || mInitialized)
14 andreas 237
        return;
2 andreas 238
 
14 andreas 239
    mInitialized = true;
23 andreas 240
 
22 andreas 241
#if LOGPATH == LPATH_FILE
14 andreas 242
    if (!mLogfile.empty())
243
    {
23 andreas 244
        try
245
        {
246
#ifndef __ANDROID__
247
            if (mStream && mStream != &std::cout)
248
                delete mStream;
116 andreas 249
#if __cplusplus < 201402L
23 andreas 250
            mStream = new std::ofstream(mLogfile.c_str(), std::ios::out | std::ios::ate);
116 andreas 251
#else
252
            mStream = new std::ofstream(mLogfile, std::ios::out | std::ios::ate);
253
#endif
23 andreas 254
            if (!mStream || mStream->fail())
255
                mStream = &std::cout;
256
#else
43 andreas 257
            char *HOME = getenv("HOME");
258
            bool bigLog = false;
259
            uint logLevel = _getLevel(TConfig::getLogLevel());
260
 
261
            if ((logLevel & HLOG_TRACE) || (logLevel & HLOG_DEBUG))
262
                bigLog = true;
263
 
264
            if (HOME && !bigLog && mLogfile.find(HOME) == string::npos)
265
            {
266
                if (mStream && mStream != &std::cout)
267
                    delete mStream;
268
 
269
                mStream = new std::ofstream(mLogfile.c_str(), std::ios::out | std::ios::ate);
270
 
271
                if (!mStream || mStream->fail())
272
                {
273
                    std::cout.rdbuf(new androidbuf);
274
                    mStream = &std::cout;
275
                }
276
            }
277
            else
278
            {
279
                std::cout.rdbuf(new androidbuf);
280
                mStream = &std::cout;
281
            }
23 andreas 282
#endif  // __ANDROID__
283
        }
284
        catch (std::exception& e)
285
        {
286
#ifdef __ANDROID__
287
            __android_log_print(ANDROID_LOG_ERROR, "tpanel", "ERROR: %s", e.what());
288
#else
289
            std::cerr << "ERROR: " << e.what() << std::endl;
290
#endif  // __ANDROID__
291
            mStream = &std::cout;
292
        }
14 andreas 293
    }
116 andreas 294
    else if (!mStream)
23 andreas 295
    {
296
#ifdef __ANDROID__
297
        std::cout.rdbuf(new androidbuf);
22 andreas 298
#endif
14 andreas 299
        mStream = &std::cout;
23 andreas 300
    }
116 andreas 301
#else  // LOGPATH == LPATH_FILE
302
    if (!mStream)
303
    {
304
#ifdef __ANDROID__
305
        std::cout.rdbuf(new androidbuf);
306
#endif
307
        mStream = &std::cout;
308
    }
23 andreas 309
#endif  // LOGPATH == LPATH_FILE
310
 
14 andreas 311
    if (!TConfig::isLongFormat())
312
        *mStream << "Logfile started at " << getTime() << std::endl;
2 andreas 313
 
14 andreas 314
    *mStream << TConfig::getProgName() << " version " << V_MAJOR << "." << V_MINOR << "." << V_PATCH << std::endl;
31 andreas 315
    *mStream << "(C) Copyright by Andreas Theofilu <andreas@theosys.at>" << std::endl << " " << std::endl;
2 andreas 316
 
14 andreas 317
    if (TConfig::isLongFormat())
318
        *mStream << "Timestamp           Type LNr., File name           , Message" << std::endl;
319
    else
320
        *mStream << "Type LNr., Message" << std::endl;
2 andreas 321
 
23 andreas 322
    *mStream << "-----------------------------------------------------------------" << std::endl << std::flush;
14 andreas 323
}
2 andreas 324
 
325
void TStreamError::logMsg(std::ostream& str)
326
{
116 andreas 327
    if (!TConfig::isInitialized())
328
        return;
329
 
5 andreas 330
    _init();
2 andreas 331
 
5 andreas 332
    if (!mStream || str.fail())
333
        return;
2 andreas 334
 
5 andreas 335
    // Print out the message
336
    std::stringstream s;
337
    s << str.rdbuf() << std::ends;
338
    *mStream << s.str() << std::flush;
26 andreas 339
    resetFlags(mStream);
2 andreas 340
}
341
 
23 andreas 342
std::ostream *TStreamError::resetFlags(std::ostream *os)
22 andreas 343
{
23 andreas 344
    *os << std::resetiosflags(std::ios::boolalpha) <<
345
           std::resetiosflags(std::ios::showbase) <<
346
           std::resetiosflags(std::ios::showpoint) <<
347
           std::resetiosflags(std::ios::showpos) <<
348
           std::resetiosflags(std::ios::skipws) <<
349
           std::resetiosflags(std::ios::unitbuf) <<
350
           std::resetiosflags(std::ios::uppercase) <<
351
           std::resetiosflags(std::ios::dec) <<
352
           std::resetiosflags(std::ios::hex) <<
353
           std::resetiosflags(std::ios::oct) <<
354
           std::resetiosflags(std::ios::fixed) <<
355
           std::resetiosflags(std::ios::scientific) <<
356
           std::resetiosflags(std::ios::internal) <<
357
           std::resetiosflags(std::ios::left) <<
358
           std::resetiosflags(std::ios::right) <<
359
           std::setfill(' ');
360
    return os;
22 andreas 361
}
362
 
2 andreas 363
void TStreamError::decIndent()
364
{
14 andreas 365
    if (mIndent > 0)
366
        mIndent--;
2 andreas 367
}
368
 
369
string TStreamError::getTime()
370
{
14 andreas 371
    time_t rawtime;
372
    struct tm * timeinfo;
373
    char buffer[80];
2 andreas 374
 
14 andreas 375
    time(&rawtime);
376
    timeinfo = localtime(&rawtime);
2 andreas 377
 
14 andreas 378
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
379
    string str(buffer);
380
    return str;
2 andreas 381
}
382
 
383
std::ostream& indent(std::ostream& os)
384
{
14 andreas 385
    if (os.fail())
386
        return os;
2 andreas 387
 
14 andreas 388
    if (TStreamError::getIndent() > 0)
389
        os << std::setw(TStreamError::getIndent()) << " ";
2 andreas 390
 
14 andreas 391
    return os;
2 andreas 392
}
393
 
394
/********************************************************************/
395
 
14 andreas 396
std::mutex tracer_mutex;
397
 
2 andreas 398
TTracer::TTracer(const std::string& msg, int line, char *file)
399
{
116 andreas 400
    if (!TConfig::isInitialized() || !TStreamError::checkFilter(HLOG_TRACE))
14 andreas 401
        return;
2 andreas 402
 
14 andreas 403
    tracer_mutex.lock();
116 andreas 404
 
14 andreas 405
    mFile = file;
406
    size_t pos = mFile.find_last_of("/");
2 andreas 407
 
14 andreas 408
    if (pos != string::npos)
409
        mFile = mFile.substr(pos + 1);
2 andreas 410
 
23 andreas 411
    TError::setErrorType(TERRTRACE);
22 andreas 412
#if LOGPATH == LPATH_FILE
14 andreas 413
    if (!TConfig::isLongFormat())
414
        TError::Current()->logMsg(*TStreamError::getStream() << "TRC " << std::setw(5) << std::right << line << ", " << indent << "{entry " << msg << std::endl);
415
    else
416
        TError::Current()->logMsg(*TStreamError::getStream() << TStreamError::getTime() <<  " TRC " << std::setw(5) << std::right << line << ", " << std::setw(20) << std::left << mFile << ", " << indent << "{entry " << msg << std::endl);
22 andreas 417
#else
418
    std::stringstream s;
2 andreas 419
 
22 andreas 420
    if (!TConfig::isLongFormat())
421
        s  << "TRC " << std::setw(5) << std::right << line << ", " << &indents << "{entry " << msg << std::endl;
422
    else
423
        s << TStreamError::getTime() <<  " TRC " << std::setw(5) << std::right << line << ", " << std::setw(20) << std::left << mFile << ", " << &indents << "{entry " << msg << std::endl;
424
 
425
    TError::Current()->logMsg(s);
426
#endif
14 andreas 427
    TError::Current()->incIndent();
428
    mHeadMsg = msg;
429
    mLine = line;
35 andreas 430
 
431
    if (TConfig::getProfiling())
432
        mTimePoint = std::chrono::steady_clock::now();
433
 
14 andreas 434
    tracer_mutex.unlock();
2 andreas 435
}
436
 
437
TTracer::~TTracer()
438
{
116 andreas 439
    if (!TConfig::isInitialized() || !TStreamError::checkFilter(HLOG_TRACE))
14 andreas 440
        return;
2 andreas 441
 
14 andreas 442
    tracer_mutex.lock();
23 andreas 443
    TError::setErrorType(TERRTRACE);
14 andreas 444
    TError::Current()->decIndent();
35 andreas 445
    string nanosecs;
446
 
447
    if (TConfig::getProfiling())
448
    {
449
        std::chrono::steady_clock::time_point endPoint = std::chrono::steady_clock::now();
450
        std::chrono::nanoseconds difftime = endPoint - mTimePoint;
451
        std::chrono::seconds secs = std::chrono::duration_cast<std::chrono::seconds>(difftime);
452
        std::chrono::milliseconds msecs = std::chrono::duration_cast<std::chrono::milliseconds>(difftime) - std::chrono::duration_cast<std::chrono::seconds>(secs);
453
        std::stringstream s;
454
        s << std::chrono::duration_cast<std::chrono::nanoseconds> (difftime).count() << "[ns]" << " --> " << std::chrono::duration_cast<std::chrono::seconds>(secs).count() << "s " << std::chrono::duration_cast<std::chrono::milliseconds>(msecs).count() << "ms";
455
        nanosecs = s.str();
456
    }
457
 
22 andreas 458
#if LOGPATH == LPATH_FILE
35 andreas 459
    if (TConfig::getProfiling())
460
    {
461
        if (!TConfig::isLongFormat())
462
            TError::Current()->logMsg(*TStreamError::getStream() << "TRC      , " << indent << "}exit " << mHeadMsg << " Elapsed time: " << nanosecs << std::endl);
463
        else
464
            TError::Current()->logMsg(*TStreamError::getStream() << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << indent << "}exit " << mHeadMsg << " Elapsed time: " << nanosecs << std::endl);
465
    }
14 andreas 466
    else
35 andreas 467
    {
468
        if (!TConfig::isLongFormat())
469
            TError::Current()->logMsg(*TStreamError::getStream() << "TRC      , " << indent << "}exit " << mHeadMsg << std::endl);
470
        else
471
            TError::Current()->logMsg(*TStreamError::getStream() << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << indent << "}exit " << mHeadMsg << std::endl);
472
    }
22 andreas 473
#else
474
    std::stringstream s;
14 andreas 475
 
22 andreas 476
    if (!TConfig::isLongFormat())
35 andreas 477
        s << "TRC      , " << &indents << "}exit " << mHeadMsg;
22 andreas 478
    else
35 andreas 479
        s << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << &indents << "}exit " << mHeadMsg;
22 andreas 480
 
35 andreas 481
    if (TConfig::getProfiling())
482
        s  << " Elapsed time: " << nanosecs << std::endl;
483
    else
484
        s << std::endl;
485
 
22 andreas 486
    TError::Current()->logMsg(s);
487
#endif
14 andreas 488
    mHeadMsg.clear();
489
    tracer_mutex.unlock();
2 andreas 490
}
491
 
492
/********************************************************************/
493
 
494
TError::~TError()
495
{
14 andreas 496
    if (mCurrent)
497
    {
498
        delete mCurrent;
499
        mCurrent = nullptr;
500
    }
2 andreas 501
}
502
 
14 andreas 503
void TError::lock()
504
{
505
    message_mutex.lock();
506
}
507
 
508
void TError::unlock()
509
{
510
    message_mutex.unlock();
511
}
512
 
2 andreas 513
TStreamError* TError::Current()
514
{
14 andreas 515
    if (!mCurrent)
516
        mCurrent = new TStreamError(TConfig::getLogFile(), TConfig::getLogLevel());
2 andreas 517
 
14 andreas 518
    return mCurrent;
2 andreas 519
}
520
 
5 andreas 521
void TError::logHex(char* str, size_t size)
522
{
523
    if (!str || !size)
524
        return;
525
 
21 andreas 526
    message_mutex.lock();
116 andreas 527
 
528
    if (!Current())
529
    {
530
        message_mutex.unlock();
531
        return;
532
    }
5 andreas 533
    // Print out the message
534
    std::ostream *stream = mCurrent->getStream();
21 andreas 535
    *stream << strToHex(str, size, 16, true, 12) << std::endl;
23 andreas 536
    *stream << mCurrent->resetFlags(stream);
21 andreas 537
    message_mutex.unlock();
538
}
5 andreas 539
 
21 andreas 540
string TError::toHex(int num, int width)
541
{
542
    string ret;
543
    std::stringstream stream;
544
    stream << std::setfill ('0') << std::setw(width) << std::hex << num;
545
    ret = stream.str();
546
    return ret;
547
}
548
 
549
string TError::strToHex(const char *str, size_t size, int width, bool format, int indent)
550
{
551
    int len = 0, pos = 0, old = 0;
552
    int w = (format) ? 1 : width;
553
    string out, left, right;
554
    string ind;
555
 
556
    if (indent > 0)
557
    {
558
        for (int j = 0; j < indent; j++)
559
            ind.append(" ");
560
    }
561
 
5 andreas 562
    for (size_t i = 0; i < size; i++)
563
    {
21 andreas 564
        if (len >= w)
565
        {
566
            left.append(" ");
567
            len = 0;
568
        }
5 andreas 569
 
21 andreas 570
        if (format && i > 0 && (pos % width) == 0)
5 andreas 571
        {
21 andreas 572
            out += ind + toHex(old, 4) + ": " + left + " | " + right + "\n";
573
            left.clear();
574
            right.clear();
575
            old = pos;
5 andreas 576
        }
21 andreas 577
 
578
        int c = *(str+i) & 0x000000ff;
579
        left.append(toHex(c, 2));
580
 
581
        if (format)
582
        {
583
            if (std::isprint(c))
584
                right.push_back(c);
585
            else
586
                right.push_back('.');
587
        }
588
 
589
        len++;
590
        pos++;
5 andreas 591
    }
592
 
21 andreas 593
    if (!format)
594
        return left;
595
    else if (pos > 0)
596
    {
597
        if ((pos % width) != 0)
598
        {
599
            for (int i = 0; i < (width - (pos % width)); i++)
600
                left.append("   ");
601
        }
602
 
603
        out += ind + toHex(old, 4)+": "+left + "  | " + right;
604
    }
605
 
606
    return out;
5 andreas 607
}
608
 
2 andreas 609
void TError::setErrorMsg(const std::string& msg)
610
{
14 andreas 611
    if (msg.empty())
612
        return;
2 andreas 613
 
14 andreas 614
    msError = msg;
615
    mHaveError = true;
616
    mErrType = TERRERROR;
2 andreas 617
}
618
 
619
void TError::setErrorMsg(terrtype_t t, const std::string& msg)
620
{
14 andreas 621
    if (msg.empty())
622
        return;
2 andreas 623
 
14 andreas 624
    msError = msg;
625
    mHaveError = true;
626
    mErrType = t;
2 andreas 627
}
628
 
629
std::ostream & TError::append(int lv, std::ostream& os)
630
{
14 andreas 631
    std::string prefix;
632
    Current();
2 andreas 633
 
14 andreas 634
    switch (lv)
635
    {
94 andreas 636
        case HLOG_PROTOCOL: prefix = "PRT    ++, "; mErrType = TERRINFO; break;
23 andreas 637
        case HLOG_INFO:     prefix = "INF    >>, "; mErrType = TERRINFO; break;
638
        case HLOG_WARNING:  prefix = "WRN    !!, "; mErrType = TERRWARNING; break;
639
        case HLOG_ERROR:    prefix = "ERR *****, "; mErrType = TERRERROR; break;
640
        case HLOG_TRACE:    prefix = "TRC      , "; mErrType = TERRTRACE; break;
641
        case HLOG_DEBUG:    prefix = "DBG    --, "; mErrType = TERRDEBUG; break;
14 andreas 642
 
643
        default:
22 andreas 644
            prefix = "           ";
23 andreas 645
            mErrType = TERRNONE;
14 andreas 646
    }
647
 
116 andreas 648
    if (!TConfig::isInitialized() && (lv == HLOG_ERROR || lv == HLOG_WARNING))
649
    {
650
        if (!TConfig::isLongFormat())
651
            std::cerr << prefix;
652
        else
653
            std::cerr << TStreamError::getTime() << " " << prefix << std::setw(20) << " " << ", ";
654
    }
655
 
14 andreas 656
    if (!TConfig::isLongFormat())
657
        return os << prefix;
658
    else
659
        return os << TStreamError::getTime() << " " << prefix << std::setw(20) << " " << ", ";
2 andreas 660
}
22 andreas 661
 
662
#if defined(__linux__) || defined(Q_OS_ANDROID)
663
void TError::displayMessage(const std::string& msg)
664
{
665
    QMessageBox m;
666
    m.setText(msg.c_str());
667
 
668
    int cnt = 10;
669
 
670
    QTimer cntDown;
671
    QObject::connect(&cntDown, &QTimer::timeout, [&m, &cnt, &cntDown]()->void
672
        {
673
            if (--cnt < 0)
674
            {
675
                cntDown.stop();
676
                m.close();
677
            }
678
        });
679
 
680
        cntDown.start(1000);
681
        m.exec();
682
}
683
#endif