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
#include <QMessageBox>
29
#include <QTimer>
235 andreas 30
 
23 andreas 31
#if LOGPATH == LPATH_SYSLOG || defined(__ANDROID__)
22 andreas 32
#   ifdef __ANDROID__
33
#       include <android/log.h>
34
#   else
35
#       include <syslog.h>
36
#   endif
37
#endif
38
 
242 andreas 39
#define LOGBUFFER_SIZE      4096
40
 
2 andreas 41
using std::string;
14 andreas 42
std::mutex message_mutex;
2 andreas 43
 
242 andreas 44
bool TError::mHaveError{false};
45
terrtype_t TError::mErrType{TERRNONE};
46
TStreamError *TError::mCurrent{nullptr};
2 andreas 47
std::string TError::msError;
48
 
242 andreas 49
int TStreamError::mIndent{1};
50
std::ostream *TStreamError::mStream{nullptr};
51
std::filebuf TStreamError::mOfStream;
52
char *TStreamError::mBuffer{nullptr};
2 andreas 53
std::string TStreamError::mLogfile;
242 andreas 54
bool TStreamError::mInitialized{false};
55
unsigned int TStreamError::mLogLevel{HLOG_PROTOCOL};
250 andreas 56
unsigned int TStreamError::mLogLevelOld{HLOG_NONE};
57
bool TStreamError::haveTemporaryLogLevel{false};
2 andreas 58
 
23 andreas 59
#if LOGPATH == LPATH_SYSLOG || defined(__ANDROID__)
60
class androidbuf : public std::streambuf
61
{
62
    public:
142 andreas 63
        enum { bufsize = 1024 };
23 andreas 64
        androidbuf() { this->setp(buffer, buffer + bufsize - 1); }
65
 
66
    private:
67
        int overflow(int c)
68
        {
69
            if (c == traits_type::eof())
70
            {
71
                *this->pptr() = traits_type::to_char_type(c);
72
                this->sbumpc();
73
            }
74
 
75
            return this->sync()? traits_type::eof(): traits_type::not_eof(c);
76
        }
77
 
78
        int sync()
79
        {
80
            int rc = 0;
81
 
82
            if (this->pbase() != this->pptr())
83
            {
84
                char writebuf[bufsize+1];
85
                memcpy(writebuf, this->pbase(), this->pptr() - this->pbase());
86
                writebuf[this->pptr() - this->pbase()] = '\0';
87
                int eType;
88
#ifdef __ANDROID__
89
                switch(TError::getErrorType())
90
                {
91
                    case TERRINFO:      eType = ANDROID_LOG_INFO; break;
92
                    case TERRWARNING:   eType = ANDROID_LOG_WARN; break;
93
                    case TERRERROR:     eType = ANDROID_LOG_ERROR; break;
94
                    case TERRTRACE:     eType = ANDROID_LOG_VERBOSE; break;
95
                    case TERRDEBUG:     eType = ANDROID_LOG_DEBUG; break;
26 andreas 96
                    case TERRNONE:      eType = ANDROID_LOG_INFO; break;
23 andreas 97
                }
98
 
99
                rc = __android_log_print(eType, "tpanel", "%s", writebuf) > 0;
100
#else
101
                switch(TError::getErrorType())
102
                {
103
                    case TERRINFO:      eType = LOG_INFO; break;
104
                    case TERRWARNING:   eType = LOG_WARN; break;
105
                    case TERRERROR:     eType = LOG_ERROR; break;
106
                    case TERRTRACE:     eType = LOG_INFO; break;
107
                    case TERRDEBUG:     eType = LOG_DEBUG; break;
108
                    case TERRNONE:      eType = LOG_INFO; break;
109
                }
110
 
111
                syslog(eType, writebuf);
26 andreas 112
                rc = 1;
22 andreas 113
#endif
23 andreas 114
                this->setp(buffer, buffer + bufsize - 1);
115
            }
22 andreas 116
 
23 andreas 117
            return rc;
118
        }
119
 
120
        char buffer[bufsize];
121
};
122
#endif
123
 
2 andreas 124
TStreamError::TStreamError(const string& logFile, const std::string& logLevel)
125
{
116 andreas 126
    if (!TConfig::isInitialized())
127
        return;
128
 
242 andreas 129
    message_mutex.lock();
130
 
14 andreas 131
    if (!logFile.empty())
23 andreas 132
        mLogfile = logFile;
14 andreas 133
    else if (!TConfig::getLogFile().empty())
23 andreas 134
        mLogfile = TConfig::getLogFile();
2 andreas 135
 
14 andreas 136
    if (!logLevel.empty())
137
        setLogLevel(logLevel);
138
    else if (!TConfig::getLogLevel().empty())
139
        setLogLevel(TConfig::getLogFile());
2 andreas 140
 
14 andreas 141
    _init();
242 andreas 142
    message_mutex.unlock();
2 andreas 143
}
144
 
145
TStreamError::~TStreamError()
146
{
242 andreas 147
    if (mOfStream.is_open())
148
        mOfStream.close();
243 andreas 149
 
242 andreas 150
    if (mStream)
14 andreas 151
    {
152
        delete mStream;
153
        mStream = nullptr;
154
    }
242 andreas 155
 
156
    if (mBuffer)
157
        delete mBuffer;
158
 
159
    mInitialized = false;
2 andreas 160
}
161
 
23 andreas 162
void TStreamError::setLogFile(const std::string &lf)
163
{
239 andreas 164
#ifdef Q_OS_IOS
165
    if (!lf.empty())
166
    {
243 andreas 167
        if ((!mLogfile.empty() && mLogfile != lf) || mLogfile.empty())
239 andreas 168
            mLogfile = lf;
169
    }
170
 
171
    if (!mInitialized)
172
        _init();
173
#else
116 andreas 174
    if (mInitialized && mLogfile.compare(lf) == 0)
23 andreas 175
        return;
176
 
177
    mLogfile = lf;
178
    mInitialized = false;
179
    _init();
239 andreas 180
#endif
23 andreas 181
}
182
 
2 andreas 183
void TStreamError::setLogLevel(const std::string& slv)
184
{
14 andreas 185
    size_t pos = slv.find("|");
186
    size_t start = 0;
187
    string lv;
188
    mLogLevel = 0;
2 andreas 189
 
14 andreas 190
    while (pos != string::npos)
191
    {
192
        lv = slv.substr(start, pos - start);
193
        start = pos + 1;
194
        mLogLevel |= _getLevel(lv);
195
        pos = slv.find("|", start);
196
    }
2 andreas 197
 
14 andreas 198
    mLogLevel |= _getLevel(slv.substr(start));
2 andreas 199
}
200
 
201
bool TStreamError::checkFilter(terrtype_t err)
202
{
116 andreas 203
    if (!TConfig::isInitialized())
204
        return false;
205
 
23 andreas 206
    if (err == TERRINFO && (mLogLevel & HLOG_INFO) != 0)
14 andreas 207
        return true;
23 andreas 208
    else if (err == TERRWARNING && (mLogLevel & HLOG_WARNING) != 0)
14 andreas 209
        return true;
23 andreas 210
    else if (err == TERRERROR && (mLogLevel & HLOG_ERROR) != 0)
14 andreas 211
        return true;
23 andreas 212
    else if (err == TERRTRACE && (mLogLevel & HLOG_TRACE) != 0)
14 andreas 213
        return true;
23 andreas 214
    else if (err == TERRDEBUG && (mLogLevel & HLOG_DEBUG) != 0)
14 andreas 215
        return true;
2 andreas 216
 
14 andreas 217
    return false;
2 andreas 218
}
219
 
220
bool TStreamError::checkFilter(int lv)
221
{
116 andreas 222
    if (!TConfig::isInitialized())
223
        return false;
224
 
14 andreas 225
    if ((mLogLevel & lv) != 0)
226
        return true;
2 andreas 227
 
14 andreas 228
    return false;
2 andreas 229
}
230
 
231
unsigned int TStreamError::_getLevel(const std::string& slv)
232
{
14 andreas 233
    if (slv.compare(SLOG_NONE) == 0)
23 andreas 234
        return HLOG_NONE;
2 andreas 235
 
14 andreas 236
    if (slv.compare(SLOG_INFO) == 0)
23 andreas 237
        return HLOG_INFO;
2 andreas 238
 
14 andreas 239
    if (slv.compare(SLOG_WARNING) == 0)
23 andreas 240
        return HLOG_WARNING;
2 andreas 241
 
14 andreas 242
    if (slv.compare(SLOG_ERROR) == 0)
23 andreas 243
        return HLOG_ERROR;
2 andreas 244
 
14 andreas 245
    if (slv.compare(SLOG_TRACE) == 0)
23 andreas 246
        return HLOG_TRACE;
2 andreas 247
 
14 andreas 248
    if (slv.compare(SLOG_DEBUG) == 0)
23 andreas 249
        return HLOG_DEBUG;
2 andreas 250
 
14 andreas 251
    if (slv.compare(SLOG_PROTOCOL) == 0)
23 andreas 252
        return HLOG_PROTOCOL;
2 andreas 253
 
14 andreas 254
    if (slv.compare(SLOG_ALL) == 0)
23 andreas 255
        return HLOG_ALL;
2 andreas 256
 
23 andreas 257
    return HLOG_NONE;
2 andreas 258
}
259
 
242 andreas 260
void TStreamError::_init(bool reinit)
2 andreas 261
{
116 andreas 262
    if (!TConfig::isInitialized() || mInitialized)
14 andreas 263
        return;
2 andreas 264
 
14 andreas 265
    mInitialized = true;
23 andreas 266
 
22 andreas 267
#if LOGPATH == LPATH_FILE
14 andreas 268
    if (!mLogfile.empty())
269
    {
23 andreas 270
        try
271
        {
272
#ifndef __ANDROID__
242 andreas 273
            if (mOfStream.is_open())
274
                mOfStream.close();
275
 
23 andreas 276
            if (mStream && mStream != &std::cout)
277
                delete mStream;
243 andreas 278
 
242 andreas 279
            if (!mBuffer)
280
            {
281
                mBuffer = new char[LOGBUFFER_SIZE];
282
                mOfStream.pubsetbuf(mBuffer, LOGBUFFER_SIZE);
283
            }
116 andreas 284
#if __cplusplus < 201402L
242 andreas 285
            mOfStream.open(mLogfile.c_str(), std::ios::out | std::ios::ate);
240 andreas 286
#else   // __cplusplus < 201402L
242 andreas 287
            mOfStream.open(mLogfile, std::ios::out | std::ios::ate);
240 andreas 288
#endif  //__cplusplus < 201402L
242 andreas 289
            mStream = new std::ostream(&mOfStream);
290
 
291
            if (!isStreamValid())
292
            {
293
                if (mOfStream.is_open())
294
                    mOfStream.close();
295
 
23 andreas 296
                mStream = &std::cout;
242 andreas 297
            }
240 andreas 298
#else   //__ANDROID__
43 andreas 299
            char *HOME = getenv("HOME");
300
            bool bigLog = false;
301
            uint logLevel = _getLevel(TConfig::getLogLevel());
302
 
303
            if ((logLevel & HLOG_TRACE) || (logLevel & HLOG_DEBUG))
304
                bigLog = true;
305
 
306
            if (HOME && !bigLog && mLogfile.find(HOME) == string::npos)
307
            {
251 andreas 308
                if (mOfStream.is_open())
309
                    mOfStream.close();
310
 
43 andreas 311
                if (mStream && mStream != &std::cout)
312
                    delete mStream;
313
 
251 andreas 314
#if __cplusplus < 201402L
315
                mOfStream.open(mLogfile.c_str(), std::ios::out | std::ios::ate);
316
#else   // __cplusplus < 201402L
317
                mOfStream.open(mLogfile, std::ios::out | std::ios::ate);
318
#endif  //__cplusplus < 201402L
319
                mStream = new std::ostream(&mOfStream);
43 andreas 320
 
251 andreas 321
                if (!isStreamValid())
43 andreas 322
                {
251 andreas 323
                    if (mOfStream.is_open())
324
                        mOfStream.close();
325
 
43 andreas 326
                    mStream = &std::cout;
327
                }
328
            }
329
            else
330
            {
331
                std::cout.rdbuf(new androidbuf);
332
                mStream = &std::cout;
333
            }
23 andreas 334
#endif  // __ANDROID__
335
        }
336
        catch (std::exception& e)
337
        {
338
#ifdef __ANDROID__
339
            __android_log_print(ANDROID_LOG_ERROR, "tpanel", "ERROR: %s", e.what());
240 andreas 340
#else   // __ANDROID__
23 andreas 341
            std::cerr << "ERROR: " << e.what() << std::endl;
342
#endif  // __ANDROID__
343
            mStream = &std::cout;
344
        }
14 andreas 345
    }
242 andreas 346
    else if (!isStreamValid())
23 andreas 347
    {
348
#ifdef __ANDROID__
349
        std::cout.rdbuf(new androidbuf);
240 andreas 350
#endif  // __ANDROID__
14 andreas 351
        mStream = &std::cout;
239 andreas 352
        std::cout << "DEBUG: Stream wurde auf std::cout gesetzt." << std::endl;
23 andreas 353
    }
116 andreas 354
#else  // LOGPATH == LPATH_FILE
355
    if (!mStream)
356
    {
357
#ifdef __ANDROID__
358
        std::cout.rdbuf(new androidbuf);
359
#endif
360
        mStream = &std::cout;
361
    }
23 andreas 362
#endif  // LOGPATH == LPATH_FILE
363
 
242 andreas 364
    if (reinit)
365
        return;
366
 
14 andreas 367
    if (!TConfig::isLongFormat())
368
        *mStream << "Logfile started at " << getTime() << std::endl;
2 andreas 369
 
153 andreas 370
    *mStream << TConfig::getProgName() << " version " << VERSION_STRING() << std::endl;
31 andreas 371
    *mStream << "(C) Copyright by Andreas Theofilu <andreas@theosys.at>" << std::endl << " " << std::endl;
2 andreas 372
 
14 andreas 373
    if (TConfig::isLongFormat())
374
        *mStream << "Timestamp           Type LNr., File name           , Message" << std::endl;
375
    else
376
        *mStream << "Type LNr., Message" << std::endl;
2 andreas 377
 
23 andreas 378
    *mStream << "-----------------------------------------------------------------" << std::endl << std::flush;
14 andreas 379
}
2 andreas 380
 
381
void TStreamError::logMsg(std::ostream& str)
382
{
116 andreas 383
    if (!TConfig::isInitialized())
384
        return;
385
 
242 andreas 386
    message_mutex.lock();
387
    try
388
    {
389
        _init();
2 andreas 390
 
242 andreas 391
        if (!isStreamValid(str))
392
        {
393
            message_mutex.unlock();
394
            return;
395
        }
2 andreas 396
 
242 andreas 397
        // Print out the message
398
        std::stringstream s;
399
        s << str.rdbuf() << std::ends;
400
        *mStream << s.str() << std::flush;
401
        resetFlags(mStream);
402
    }
403
    catch(const std::exception& e)
404
    {
405
        std::cerr << "ERROR: Writing a log message: " << e.what() << std::endl;
406
    }
407
 
408
    message_mutex.unlock();
2 andreas 409
}
410
 
23 andreas 411
std::ostream *TStreamError::resetFlags(std::ostream *os)
22 andreas 412
{
238 andreas 413
    if (!isStreamValid(*os))
414
        return os;
415
 
23 andreas 416
    *os << std::resetiosflags(std::ios::boolalpha) <<
417
           std::resetiosflags(std::ios::showbase) <<
418
           std::resetiosflags(std::ios::showpoint) <<
419
           std::resetiosflags(std::ios::showpos) <<
420
           std::resetiosflags(std::ios::skipws) <<
421
           std::resetiosflags(std::ios::unitbuf) <<
422
           std::resetiosflags(std::ios::uppercase) <<
423
           std::resetiosflags(std::ios::dec) <<
424
           std::resetiosflags(std::ios::hex) <<
425
           std::resetiosflags(std::ios::oct) <<
426
           std::resetiosflags(std::ios::fixed) <<
427
           std::resetiosflags(std::ios::scientific) <<
428
           std::resetiosflags(std::ios::internal) <<
429
           std::resetiosflags(std::ios::left) <<
430
           std::resetiosflags(std::ios::right) <<
431
           std::setfill(' ');
432
    return os;
22 andreas 433
}
434
 
247 andreas 435
void TStreamError::resetFlags()
436
{
437
    resetFlags(TError::Current()->getStream());
438
}
439
 
2 andreas 440
void TStreamError::decIndent()
441
{
14 andreas 442
    if (mIndent > 0)
443
        mIndent--;
2 andreas 444
}
445
 
446
string TStreamError::getTime()
447
{
14 andreas 448
    time_t rawtime;
449
    struct tm * timeinfo;
450
    char buffer[80];
2 andreas 451
 
240 andreas 452
    rawtime = time(nullptr);
14 andreas 453
    timeinfo = localtime(&rawtime);
2 andreas 454
 
240 andreas 455
    if (!timeinfo)
456
    {
457
        std::cerr << "ERROR: Couldn't get the local time!" << std::endl;
458
        return string();
459
    }
460
 
14 andreas 461
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
462
    string str(buffer);
463
    return str;
2 andreas 464
}
465
 
242 andreas 466
std::ostream *TStreamError::getStream()
467
{
468
    try
469
    {
470
        if (!isStreamValid())
471
        {
472
            std::cerr << "ERROR: Internal stream is invalid!" << std::endl;
473
            mInitialized = false;
474
            _init();
475
            std::cerr << "INFO: Reinitialized stream." << std::endl;
476
 
477
            if (!isStreamValid())
478
            {
479
                std::cerr << "ERROR: Reinitializing of stream failed! Using \"std::cout\" to write log messages." << std::endl;
480
                return &std::cout;
481
            }
482
        }
483
 
484
        return mStream;
485
    }
486
    catch (std::exception& e)
487
    {
488
        std::cerr << "ERROR: Error retrieving the current stream! Using \"std::cout\" instead." << std::endl;
489
    }
490
 
491
    return &std::cout;
492
}
493
 
2 andreas 494
std::ostream& indent(std::ostream& os)
495
{
238 andreas 496
    if (!TStreamError::isStreamValid(os))
14 andreas 497
        return os;
2 andreas 498
 
14 andreas 499
    if (TStreamError::getIndent() > 0)
500
        os << std::setw(TStreamError::getIndent()) << " ";
2 andreas 501
 
14 andreas 502
    return os;
2 andreas 503
}
504
 
238 andreas 505
bool TStreamError::isStreamValid()
506
{
507
    if (!mStream)
508
        return false;
509
 
242 andreas 510
    if (mStream->rdstate() & std::ostream::failbit)
238 andreas 511
        return false;
512
 
242 andreas 513
    if (mStream->rdstate() & std::ostream::badbit)
238 andreas 514
        return false;
515
 
516
    return true;
517
}
518
 
519
bool TStreamError::isStreamValid(std::ostream& os)
520
{
242 andreas 521
    if (os.rdstate() & std::ostream::failbit)
238 andreas 522
        return false;
523
 
242 andreas 524
    if (os.rdstate() & std::ostream::badbit)
238 andreas 525
        return false;
526
 
527
    return true;
528
}
529
 
250 andreas 530
void TStreamError::startTemporaryLogLevel(unsigned int l)
531
{
532
    if (haveTemporaryLogLevel)
533
        return;
534
 
535
    mLogLevelOld = mLogLevel;
536
    mLogLevel |= l;
537
    haveTemporaryLogLevel = true;
538
}
539
 
540
void TStreamError::endTemporaryLogLevel()
541
{
542
    mLogLevel = mLogLevelOld;
543
    haveTemporaryLogLevel = false;
544
}
545
 
2 andreas 546
/********************************************************************/
547
 
14 andreas 548
std::mutex tracer_mutex;
549
 
239 andreas 550
TTracer::TTracer(const std::string msg, int line, char *file)
2 andreas 551
{
116 andreas 552
    if (!TConfig::isInitialized() || !TStreamError::checkFilter(HLOG_TRACE))
14 andreas 553
        return;
2 andreas 554
 
14 andreas 555
    tracer_mutex.lock();
116 andreas 556
 
14 andreas 557
    mFile = file;
558
    size_t pos = mFile.find_last_of("/");
2 andreas 559
 
14 andreas 560
    if (pos != string::npos)
561
        mFile = mFile.substr(pos + 1);
2 andreas 562
 
23 andreas 563
    TError::setErrorType(TERRTRACE);
242 andreas 564
 
22 andreas 565
#if LOGPATH == LPATH_FILE
14 andreas 566
    if (!TConfig::isLongFormat())
242 andreas 567
        *TError::Current()->getStream() << "TRC " << std::setw(5) << std::right << line << ", " << indent << "{entry " << msg << std::endl;
568
//        TError::Current()->logMsg(*TStreamError::getStream() << "TRC " << std::setw(5) << std::right << line << ", " << indent << "{entry " << msg << std::endl);
14 andreas 569
    else
242 andreas 570
        *TError::Current()->getStream() << TStreamError::getTime() <<  " TRC " << std::setw(5) << std::right << line << ", " << std::setw(20) << std::left << mFile << ", " << indent << "{entry " << msg << std::endl;
571
//        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 572
#else
573
    std::stringstream s;
2 andreas 574
 
22 andreas 575
    if (!TConfig::isLongFormat())
576
        s  << "TRC " << std::setw(5) << std::right << line << ", " << &indents << "{entry " << msg << std::endl;
577
    else
578
        s << TStreamError::getTime() <<  " TRC " << std::setw(5) << std::right << line << ", " << std::setw(20) << std::left << mFile << ", " << &indents << "{entry " << msg << std::endl;
579
 
580
    TError::Current()->logMsg(s);
581
#endif
14 andreas 582
    TError::Current()->incIndent();
583
    mHeadMsg = msg;
584
    mLine = line;
35 andreas 585
 
586
    if (TConfig::getProfiling())
587
        mTimePoint = std::chrono::steady_clock::now();
588
 
14 andreas 589
    tracer_mutex.unlock();
2 andreas 590
}
591
 
592
TTracer::~TTracer()
593
{
116 andreas 594
    if (!TConfig::isInitialized() || !TStreamError::checkFilter(HLOG_TRACE))
14 andreas 595
        return;
2 andreas 596
 
14 andreas 597
    tracer_mutex.lock();
23 andreas 598
    TError::setErrorType(TERRTRACE);
14 andreas 599
    TError::Current()->decIndent();
35 andreas 600
    string nanosecs;
601
 
602
    if (TConfig::getProfiling())
603
    {
604
        std::chrono::steady_clock::time_point endPoint = std::chrono::steady_clock::now();
605
        std::chrono::nanoseconds difftime = endPoint - mTimePoint;
606
        std::chrono::seconds secs = std::chrono::duration_cast<std::chrono::seconds>(difftime);
607
        std::chrono::milliseconds msecs = std::chrono::duration_cast<std::chrono::milliseconds>(difftime) - std::chrono::duration_cast<std::chrono::seconds>(secs);
608
        std::stringstream s;
609
        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";
610
        nanosecs = s.str();
611
    }
612
 
22 andreas 613
#if LOGPATH == LPATH_FILE
35 andreas 614
    if (TConfig::getProfiling())
615
    {
616
        if (!TConfig::isLongFormat())
617
            TError::Current()->logMsg(*TStreamError::getStream() << "TRC      , " << indent << "}exit " << mHeadMsg << " Elapsed time: " << nanosecs << std::endl);
618
        else
619
            TError::Current()->logMsg(*TStreamError::getStream() << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << indent << "}exit " << mHeadMsg << " Elapsed time: " << nanosecs << std::endl);
620
    }
14 andreas 621
    else
35 andreas 622
    {
623
        if (!TConfig::isLongFormat())
624
            TError::Current()->logMsg(*TStreamError::getStream() << "TRC      , " << indent << "}exit " << mHeadMsg << std::endl);
625
        else
626
            TError::Current()->logMsg(*TStreamError::getStream() << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << indent << "}exit " << mHeadMsg << std::endl);
627
    }
22 andreas 628
#else
629
    std::stringstream s;
14 andreas 630
 
22 andreas 631
    if (!TConfig::isLongFormat())
35 andreas 632
        s << "TRC      , " << &indents << "}exit " << mHeadMsg;
22 andreas 633
    else
35 andreas 634
        s << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << &indents << "}exit " << mHeadMsg;
22 andreas 635
 
35 andreas 636
    if (TConfig::getProfiling())
637
        s  << " Elapsed time: " << nanosecs << std::endl;
638
    else
639
        s << std::endl;
640
 
22 andreas 641
    TError::Current()->logMsg(s);
642
#endif
14 andreas 643
    mHeadMsg.clear();
644
    tracer_mutex.unlock();
2 andreas 645
}
646
 
647
/********************************************************************/
648
 
649
TError::~TError()
650
{
14 andreas 651
    if (mCurrent)
652
    {
653
        delete mCurrent;
654
        mCurrent = nullptr;
655
    }
2 andreas 656
}
242 andreas 657
/*
14 andreas 658
void TError::lock()
659
{
660
    message_mutex.lock();
661
}
662
 
663
void TError::unlock()
664
{
665
    message_mutex.unlock();
666
}
242 andreas 667
*/
2 andreas 668
TStreamError* TError::Current()
669
{
14 andreas 670
    if (!mCurrent)
671
        mCurrent = new TStreamError(TConfig::getLogFile(), TConfig::getLogLevel());
2 andreas 672
 
14 andreas 673
    return mCurrent;
2 andreas 674
}
675
 
5 andreas 676
void TError::logHex(char* str, size_t size)
677
{
678
    if (!str || !size)
679
        return;
680
 
21 andreas 681
    message_mutex.lock();
116 andreas 682
 
683
    if (!Current())
684
    {
685
        message_mutex.unlock();
686
        return;
687
    }
5 andreas 688
    // Print out the message
689
    std::ostream *stream = mCurrent->getStream();
21 andreas 690
    *stream << strToHex(str, size, 16, true, 12) << std::endl;
23 andreas 691
    *stream << mCurrent->resetFlags(stream);
21 andreas 692
    message_mutex.unlock();
693
}
5 andreas 694
 
21 andreas 695
string TError::toHex(int num, int width)
696
{
697
    string ret;
698
    std::stringstream stream;
699
    stream << std::setfill ('0') << std::setw(width) << std::hex << num;
700
    ret = stream.str();
701
    return ret;
702
}
703
 
704
string TError::strToHex(const char *str, size_t size, int width, bool format, int indent)
705
{
706
    int len = 0, pos = 0, old = 0;
707
    int w = (format) ? 1 : width;
708
    string out, left, right;
709
    string ind;
710
 
711
    if (indent > 0)
712
    {
713
        for (int j = 0; j < indent; j++)
714
            ind.append(" ");
715
    }
716
 
5 andreas 717
    for (size_t i = 0; i < size; i++)
718
    {
21 andreas 719
        if (len >= w)
720
        {
721
            left.append(" ");
722
            len = 0;
723
        }
5 andreas 724
 
21 andreas 725
        if (format && i > 0 && (pos % width) == 0)
5 andreas 726
        {
21 andreas 727
            out += ind + toHex(old, 4) + ": " + left + " | " + right + "\n";
728
            left.clear();
729
            right.clear();
730
            old = pos;
5 andreas 731
        }
21 andreas 732
 
733
        int c = *(str+i) & 0x000000ff;
734
        left.append(toHex(c, 2));
735
 
736
        if (format)
737
        {
738
            if (std::isprint(c))
739
                right.push_back(c);
740
            else
741
                right.push_back('.');
742
        }
743
 
744
        len++;
745
        pos++;
5 andreas 746
    }
747
 
21 andreas 748
    if (!format)
749
        return left;
750
    else if (pos > 0)
751
    {
752
        if ((pos % width) != 0)
753
        {
754
            for (int i = 0; i < (width - (pos % width)); i++)
755
                left.append("   ");
756
        }
757
 
758
        out += ind + toHex(old, 4)+": "+left + "  | " + right;
759
    }
760
 
761
    return out;
5 andreas 762
}
763
 
2 andreas 764
void TError::setErrorMsg(const std::string& msg)
765
{
14 andreas 766
    if (msg.empty())
767
        return;
2 andreas 768
 
14 andreas 769
    msError = msg;
770
    mHaveError = true;
771
    mErrType = TERRERROR;
2 andreas 772
}
773
 
774
void TError::setErrorMsg(terrtype_t t, const std::string& msg)
775
{
14 andreas 776
    if (msg.empty())
777
        return;
2 andreas 778
 
14 andreas 779
    msError = msg;
780
    mHaveError = true;
781
    mErrType = t;
2 andreas 782
}
783
 
784
std::ostream & TError::append(int lv, std::ostream& os)
785
{
14 andreas 786
    Current();
2 andreas 787
 
242 andreas 788
    if (!TConfig::isInitialized() && (lv == HLOG_ERROR || lv == HLOG_WARNING))
789
    {
790
        std::cerr << append(lv);
791
        return std::cerr;
792
    }
793
 
794
    return os << append(lv);
795
}
796
 
797
std::string TError::append(int lv)
798
{
799
    std::string prefix, out;
800
 
14 andreas 801
    switch (lv)
802
    {
94 andreas 803
        case HLOG_PROTOCOL: prefix = "PRT    ++, "; mErrType = TERRINFO; break;
23 andreas 804
        case HLOG_INFO:     prefix = "INF    >>, "; mErrType = TERRINFO; break;
805
        case HLOG_WARNING:  prefix = "WRN    !!, "; mErrType = TERRWARNING; break;
806
        case HLOG_ERROR:    prefix = "ERR *****, "; mErrType = TERRERROR; break;
807
        case HLOG_TRACE:    prefix = "TRC      , "; mErrType = TERRTRACE; break;
808
        case HLOG_DEBUG:    prefix = "DBG    --, "; mErrType = TERRDEBUG; break;
14 andreas 809
 
810
        default:
22 andreas 811
            prefix = "           ";
23 andreas 812
            mErrType = TERRNONE;
14 andreas 813
    }
814
 
242 andreas 815
    if (!TConfig::isLongFormat())
816
        out = prefix;
817
    else
116 andreas 818
    {
242 andreas 819
        std::stringstream s;
820
        s << TStreamError::getTime() << " " << prefix << std::setw(20) << " " << ", ";
821
        out = s.str();
116 andreas 822
    }
823
 
242 andreas 824
    return out;
2 andreas 825
}
22 andreas 826
 
827
void TError::displayMessage(const std::string& msg)
828
{
829
    QMessageBox m;
830
    m.setText(msg.c_str());
831
 
832
    int cnt = 10;
833
 
834
    QTimer cntDown;
835
    QObject::connect(&cntDown, &QTimer::timeout, [&m, &cnt, &cntDown]()->void
836
        {
837
            if (--cnt < 0)
838
            {
839
                cntDown.stop();
840
                m.close();
841
            }
842
        });
843
 
239 andreas 844
    cntDown.start(1000);
845
    m.exec();
22 andreas 846
}