Subversion Repositories tpanel

Rev

Rev 484 | Details | Compare with Previous | Last modification | View Log | RSS feed

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