Subversion Repositories tpanel

Rev

Rev 446 | Rev 484 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
446 andreas 1
/*
474 andreas 2
 * Copyright (C) 2020 to 2024 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));
268
#ifdef __ANDROID__
269
    __android_log_print(ANDROID_LOG_INFO, "tpanel", "TStreamError::setLogLevel: New loglevel: %s", slv.c_str());
270
#else
271
    if (mInitialized && mStream)
272
        *mStream << TError::append(HLOG_INFO) << "New loglevel: " << slv << std::endl;
273
    else
274
        std::cout << TError::append(HLOG_INFO) << "New loglevel: " << slv << std::endl;
275
#endif
276
}
277
 
278
bool TStreamError::checkFilter(terrtype_t err)
279
{
280
    if (!TConfig::isInitialized())
281
        return false;
282
 
283
    if (err == TERRINFO && (mLogLevel & HLOG_INFO) != 0)
284
        return true;
285
    else if (err == TERRWARNING && (mLogLevel & HLOG_WARNING) != 0)
286
        return true;
287
    else if (err == TERRERROR && (mLogLevel & HLOG_ERROR) != 0)
288
        return true;
289
    else if (err == TERRTRACE && (mLogLevel & HLOG_TRACE) != 0)
290
        return true;
291
    else if (err == TERRDEBUG && (mLogLevel & HLOG_DEBUG) != 0)
292
        return true;
293
 
294
    return false;
295
}
296
 
297
bool TStreamError::checkFilter(unsigned int lv)
298
{
299
    if (!TConfig::isInitialized())
300
        return false;
301
 
302
    if ((mLogLevel & HLOG_INFO) != 0 &&
303
        (mLogLevel & HLOG_WARNING) != 0 &&
304
        (mLogLevel & HLOG_ERROR) != 0 &&
305
        lv == HLOG_PROTOCOL)
306
        return true;
307
 
308
    if ((mLogLevel & lv) != 0 && lv != HLOG_PROTOCOL)
309
        return true;
310
 
311
    return false;
312
}
313
 
314
unsigned int TStreamError::_getLevel(const std::string& slv)
315
{
316
    if (slv.compare(SLOG_NONE) == 0)
317
        return HLOG_NONE;
318
 
319
    if (slv.compare(SLOG_INFO) == 0)
320
        return HLOG_INFO;
321
 
322
    if (slv.compare(SLOG_WARNING) == 0)
323
        return HLOG_WARNING;
324
 
325
    if (slv.compare(SLOG_ERROR) == 0)
326
        return HLOG_ERROR;
327
 
328
    if (slv.compare(SLOG_TRACE) == 0)
329
        return HLOG_TRACE;
330
 
331
    if (slv.compare(SLOG_DEBUG) == 0)
332
        return HLOG_DEBUG;
333
 
334
    if (slv.compare(SLOG_PROTOCOL) == 0)
335
        return HLOG_PROTOCOL;
336
 
337
    if (slv.compare(SLOG_ALL) == 0)
338
        return HLOG_ALL;
339
 
340
    return HLOG_NONE;
341
}
342
 
343
void TStreamError::_init(bool reinit)
344
{
345
    if (!TConfig::isInitialized() || mInitialized)
346
        return;
347
 
348
    mInitialized = true;
349
 
350
#ifdef __ANDROID__
351
    __android_log_print(ANDROID_LOG_DEBUG, "tpanel", "TStreamError::_init: Logfile is %s", (mLogFileEnabled ? "ENABLED" : "DISABLED"));
352
#endif
353
 
354
#if LOGPATH == LPATH_FILE
355
    if (mLogFileEnabled && !mLogfile.empty())
356
    {
357
        try
358
        {
359
#ifndef __ANDROID__
360
            if (mOfStream.is_open())
361
                mOfStream.close();
362
 
363
            if (mStream && mStream != &std::cout)
364
                delete mStream;
365
 
366
            if (!mBuffer)
367
            {
368
                mBuffer = new char[LOGBUFFER_SIZE];
369
                mOfStream.pubsetbuf(mBuffer, LOGBUFFER_SIZE);
370
            }
371
#if __cplusplus < 201402L
372
            mOfStream.open(mLogfile.c_str(), std::ios::out | std::ios::ate);
373
#else   // __cplusplus < 201402L
374
            mOfStream.open(mLogfile, std::ios::out | std::ios::ate);
375
#endif  //__cplusplus < 201402L
376
            mStream = new std::ostream(&mOfStream);
377
 
378
            if (!isStreamValid())
379
            {
380
                if (mOfStream.is_open())
381
                    mOfStream.close();
382
 
383
                delete mStream;
384
                mStream = &std::cout;
385
            }
386
#else   //__ANDROID__
387
            char *HOME = getenv("HOME");
388
            bool bigLog = false;
389
            uint logLevel = _getLevel(TConfig::getLogLevel());
390
 
391
            if ((logLevel & HLOG_TRACE) || (logLevel & HLOG_DEBUG))
392
                bigLog = true;
393
 
394
            if (HOME && !bigLog && mLogfile.find(HOME) == string::npos)
395
            {
396
                if (mOfStream.is_open())
397
                    mOfStream.close();
398
 
399
                if (mStream && mStream != &std::cout)
400
                    delete mStream;
401
 
402
                __android_log_print(ANDROID_LOG_DEBUG, "tpanel", "TStreamError::_init: Opening logfile: \"%s\"", mLogfile.c_str());
403
 
404
                if (!mOfStream.open(mLogfile, std::ios::out | std::ios::trunc))
405
                {
406
                    __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::_init: Could not open logfile!");
407
                    std::cout.rdbuf(new androidbuf);
408
                    mStream = &std::cout;
409
                    mLogFileEnabled = false;
410
                }
411
                else
412
                {
413
                    mStream = new std::ostream(&mOfStream);
414
 
415
                    if (!isStreamValid())
416
                    {
417
                        delete mStream;
418
 
419
                        if (mOfStream.is_open())
420
                            mOfStream.close();
421
 
422
                        std::cout.rdbuf(new androidbuf);
423
                        mStream = &std::cout;
424
                        mLogFileEnabled = false;
425
                    }
426
                }
427
            }
428
            else
429
            {
430
                std::cout.rdbuf(new androidbuf);
431
                mStream = &std::cout;
432
            }
433
#endif  // __ANDROID__
434
        }
435
        catch (std::exception& e)
436
        {
437
#ifdef __ANDROID__
438
            __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::_init: %s", e.what());
439
#else   // __ANDROID__
440
            std::cerr << "ERROR: " << e.what() << std::endl;
441
#endif  // __ANDROID__
442
            mStream = &std::cout;
443
        }
444
    }
445
    else if (!isStreamValid())
446
    {
447
#ifdef __ANDROID__
448
        std::cout.rdbuf(new androidbuf);
449
#endif  // __ANDROID__
450
        mStream = &std::cout;
451
#if defined(QT_DEBUG) || defined(DEBUG)
452
#ifdef __ANDROID__
453
        __android_log_print(ANDROID_LOG_DEBUG, "tpanel", "TStreamError::_init: Stream wurde auf std::cout gesetzt.");
454
#else
455
        std::cout << "DEBUG: Stream wurde auf std::cout gesetzt." << std::endl;
456
#endif  // __ANDROID__
457
#endif  // defined(QT_DEBUG) || defined(DEBUG)
458
    }
459
#else  // LOGPATH == LPATH_FILE
460
    if (!mStream)
461
    {
462
#if defined(__ANDROID__) || defined(__IOS_AVAILABLE)
463
        std::cout.rdbuf(new androidbuf);
464
#endif
465
        mStream = &std::cout;
466
    }
467
#endif  // LOGPATH == LPATH_FILE
468
 
469
    if (reinit)
470
        return;
471
 
472
    if (mLogLevel > 0)
473
        *mStream << "Logfile started at " << getTime() << std::endl;
474
 
475
    *mStream << TConfig::getProgName() << " version " << VERSION_STRING() << std::endl;
476
    *mStream << "(C) Copyright by Andreas Theofilu <andreas@theosys.at>\n" << std::endl;
477
 
478
    if (mLogLevel > 0)
479
    {
480
        if (TConfig::isLongFormat())
481
            *mStream << "Timestamp           Type LNr., File name           , ThreadID Message" << std::endl;
482
        else
483
            *mStream << "Type LNr., ThreadID Message" << std::endl;
484
 
485
        *mStream << "-----------------------------------------------------------------" << std::endl << std::flush;
486
    }
487
    else
488
        *mStream << std::flush;
489
}
490
 
491
std::ostream *TStreamError::resetFlags(std::ostream *os)
492
{
493
    if (!isStreamValid(*os))
494
        return os;
495
 
496
    *os << std::resetiosflags(std::ios::boolalpha) <<
497
           std::resetiosflags(std::ios::showbase) <<
498
           std::resetiosflags(std::ios::showpoint) <<
499
           std::resetiosflags(std::ios::showpos) <<
500
           std::resetiosflags(std::ios::skipws) <<
501
           std::resetiosflags(std::ios::unitbuf) <<
502
           std::resetiosflags(std::ios::uppercase) <<
503
           std::resetiosflags(std::ios::dec) <<
504
           std::resetiosflags(std::ios::hex) <<
505
           std::resetiosflags(std::ios::oct) <<
506
           std::resetiosflags(std::ios::fixed) <<
507
           std::resetiosflags(std::ios::scientific) <<
508
           std::resetiosflags(std::ios::internal) <<
509
           std::resetiosflags(std::ios::left) <<
510
           std::resetiosflags(std::ios::right) <<
511
           std::setfill(' ');
512
    return os;
513
}
514
 
515
void TStreamError::resetFlags()
516
{
517
    std::lock_guard<mutex> guard(message_mutex);
518
    resetFlags(TError::Current()->getStream());
519
}
520
 
521
void TStreamError::decIndent()
522
{
523
    if (mIndent > 0)
524
        mIndent--;
525
}
526
 
527
string TStreamError::getTime()
528
{
529
    time_t rawtime;
530
    struct tm * timeinfo;
531
    char buffer[80];
532
 
533
    rawtime = time(nullptr);
534
    timeinfo = localtime(&rawtime);
535
 
536
    if (!timeinfo)
537
    {
538
#ifdef __ANDROID__
539
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::getTime: Couldn't get the local time!");
540
#else
541
        std::cerr << "ERROR: Couldn't get the local time!" << std::endl;
542
#endif
543
        return string();
544
    }
545
 
546
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
547
    string str(buffer);
548
    return str;
549
}
550
 
551
std::ostream *TStreamError::getStream()
552
{
553
    try
554
    {
555
        if (!isStreamValid())
556
        {
557
#ifdef __ANDROID__
558
            __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::getStream: Internal stream is invalid!");
559
#else
560
            std::cerr << "ERROR: Internal stream is invalid!" << std::endl;
561
#endif
562
            mInitialized = false;
563
            _init();
564
#ifdef __ANDROID__
565
            __android_log_print(ANDROID_LOG_INFO, "tpanel", "TStreamError::getStream: Reinitialized stream.");
566
#else
567
            std::cerr << "INFO: Reinitialized stream." << std::endl;
568
#endif
569
 
570
            if (!isStreamValid())
571
            {
572
#ifdef __ANDROID__
573
                __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::getStream: Reinitializing of stream failed!");
574
#else
575
                std::cerr << "ERROR: Reinitializing of stream failed! Using \"std::cout\" to write log messages." << std::endl;
576
#endif
577
                return &std::cout;
578
            }
579
        }
580
 
581
        return mStream;
582
    }
583
    catch (std::exception& e)
584
    {
585
#ifdef __ANDROID__
586
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::getStream: Error retrieving the current stream!");
587
#else
588
        std::cerr << "ERROR: Error retrieving the current stream! Using \"std::cout\" instead." << std::endl;
589
#endif
590
    }
591
 
592
    return &std::cout;
593
}
594
 
595
std::ostream& indent(std::ostream& os)
596
{
597
    if (!TStreamError::isStreamValid(os))
598
        return os;
599
 
600
    if (TStreamError::getIndent() > 0)
601
        os << std::setw(TStreamError::getIndent()) << " ";
602
 
603
    return os;
604
}
605
 
606
bool TStreamError::isStreamValid()
607
{
608
    if (!mStream)
609
    {
610
#ifdef __ANDROID__
611
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::isStreamValid: Stream is nullptr!");
612
#else
613
        std::cerr << "ERROR: TStreamError::isStreamValid: Stream is nullptr!" << std::endl;
614
#endif
615
        return false;
616
    }
617
 
618
    if (mStream->rdstate() & std::ostream::failbit)
619
    {
620
#ifdef __ANDROID__
621
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::isStreamValid: Stream has failbit set!");
622
#else
623
        std::cerr << "ERROR: TStreamError::isStreamValid: Stream has failbit set!" << std::endl;
624
#endif
625
        return false;
626
    }
627
 
628
    if (mStream->rdstate() & std::ostream::badbit)
629
    {
630
#ifdef __ANDROID__
631
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "TStreamError::isStreamValid: Stream has badbit set!");
632
#else
633
        std::cerr << "ERROR: TStreamError::isStreamValid: Stream has badbit set!" << std::endl;
634
#endif
635
        return false;
636
    }
637
 
638
    return true;
639
}
640
 
641
bool TStreamError::isStreamValid(std::ostream& os)
642
{
643
    if (os.rdstate() & std::ostream::failbit)
644
        return false;
645
 
646
    if (os.rdstate() & std::ostream::badbit)
647
        return false;
648
 
649
    return true;
650
}
651
 
652
void TStreamError::startTemporaryLogLevel(unsigned int l)
653
{
654
    if (haveTemporaryLogLevel)
655
        return;
656
 
657
    mLogLevelOld = mLogLevel;
658
    mLogLevel |= l;
659
    haveTemporaryLogLevel = true;
660
}
661
 
662
void TStreamError::endTemporaryLogLevel()
663
{
664
    if (!haveTemporaryLogLevel)
665
        return;
666
 
667
    mLogLevel = mLogLevelOld;
668
    haveTemporaryLogLevel = false;
669
}
670
 
671
/********************************************************************/
672
 
673
std::mutex tracer_mutex;
674
 
675
TTracer::TTracer(const std::string& msg, int line, const char *file, threadID_t tid)
676
    : mThreadID(tid)
677
{
678
    if (!TConfig::isInitialized() || !TStreamError::checkFilter(HLOG_TRACE))
679
        return;
680
 
681
    std::lock_guard<mutex> guard(tracer_mutex);
682
 
683
    mFile = file;
684
    size_t pos = mFile.find_last_of("/");
685
 
686
    if (pos != string::npos)
687
        mFile = mFile.substr(pos + 1);
688
 
689
    TError::setErrorType(TERRTRACE);
690
    std::lock_guard<mutex> guardm(message_mutex);
691
 
692
    if (!TConfig::isLongFormat())
693
        *TError::Current()->getStream() << "TRC " << std::setw(5) << std::right << line << ", " << _threadIDtoStr(mThreadID) << " " << indent << "{entry " << msg << std::endl;
694
    else
695
        *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;
696
 
697
    TError::Current()->incIndent();
698
    mHeadMsg = msg;
699
    mLine = line;
700
 
701
    if (TConfig::getProfiling())
702
        mTimePoint = std::chrono::steady_clock::now();
703
}
704
 
705
TTracer::~TTracer()
706
{
707
    if (!TConfig::isInitialized() || !TStreamError::checkFilter(HLOG_TRACE))
708
        return;
709
 
710
    std::lock_guard<mutex> guard(tracer_mutex);
711
    TError::setErrorType(TERRTRACE);
712
    TError::Current()->decIndent();
713
    string nanosecs;
714
 
715
    if (TConfig::getProfiling())
716
    {
717
        std::chrono::steady_clock::time_point endPoint = std::chrono::steady_clock::now();
718
        std::chrono::nanoseconds difftime = endPoint - mTimePoint;
719
        std::chrono::seconds secs = std::chrono::duration_cast<std::chrono::seconds>(difftime);
720
        std::chrono::milliseconds msecs = std::chrono::duration_cast<std::chrono::milliseconds>(difftime) - std::chrono::duration_cast<std::chrono::seconds>(secs);
721
        std::stringstream s;
722
        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";
723
        nanosecs = s.str();
724
    }
725
 
726
    std::lock_guard<mutex> guardm(message_mutex);
727
 
728
    if (TConfig::getProfiling())
729
    {
730
        if (!TConfig::isLongFormat())
731
            *TError::Current()->getStream() << "TRC      , " << _threadIDtoStr(mThreadID) << " " << indent << "}exit " << mHeadMsg << " Elapsed time: " << nanosecs << std::endl;
732
        else
733
            *TError::Current()->getStream() << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << _threadIDtoStr(mThreadID) << " " << indent << "}exit " << mHeadMsg << " Elapsed time: " << nanosecs << std::endl;
734
    }
735
    else
736
    {
737
        if (!TConfig::isLongFormat())
738
            *TError::Current()->getStream() << "TRC      , " << _threadIDtoStr(mThreadID) << " " << indent << "}exit " << mHeadMsg << std::endl;
739
        else
740
            *TError::Current()->getStream() << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << _threadIDtoStr(mThreadID) << " " << indent << "}exit " << mHeadMsg << std::endl;
741
    }
742
 
743
    mHeadMsg.clear();
744
}
745
 
746
/********************************************************************/
747
 
748
TError::~TError()
749
{
750
    if (mCurrent)
751
    {
752
        delete mCurrent;
753
        mCurrent = nullptr;
754
    }
755
}
756
 
757
TStreamError* TError::Current()
758
{
759
    if (!mCurrent)
760
        mCurrent = new TStreamError(TConfig::getLogFile(), TConfig::getLogLevel());
761
 
762
    return mCurrent;
763
}
764
 
765
TStreamError *TError::Current(threadID_t tid)
766
{
767
    mThreadID = tid;
768
    return Current();
769
}
770
 
474 andreas 771
void TError::logHex(const char* str, size_t size)
446 andreas 772
{
773
    if (!str || !size)
774
        return;
775
 
776
    if (!Current())
777
        return;
778
 
779
    // Print out the message
780
    std::ostream *stream = mCurrent->getStream();
781
    *stream << strToHex(str, size, 16, true, 12) << std::endl;
782
    *stream << mCurrent->resetFlags(stream);
783
}
784
 
785
string TError::toHex(int num, int width)
786
{
787
    string ret;
788
    std::stringstream stream;
789
    stream << std::setfill ('0') << std::setw(width) << std::hex << num;
790
    ret = stream.str();
791
    return ret;
792
}
793
 
794
string TError::strToHex(const char *str, size_t size, int width, bool format, int indent)
795
{
796
    int len = 0, pos = 0, old = 0;
797
    int w = (format) ? 1 : width;
798
    string out, left, right;
799
    string ind;
800
 
801
    if (indent > 0)
802
    {
803
        for (int j = 0; j < indent; j++)
804
            ind.append(" ");
805
    }
806
 
807
    for (size_t i = 0; i < size; i++)
808
    {
809
        if (len >= w)
810
        {
811
            left.append(" ");
812
            len = 0;
813
        }
814
 
815
        if (format && i > 0 && (pos % width) == 0)
816
        {
817
            out += ind + toHex(old, 4) + ": " + left + " | " + right + "\n";
818
            left.clear();
819
            right.clear();
820
            old = pos;
821
        }
822
 
823
        int c = *(str+i) & 0x000000ff;
824
        left.append(toHex(c, 2));
825
 
826
        if (format)
827
        {
828
            if (std::isprint(c))
829
                right.push_back(c);
830
            else
831
                right.push_back('.');
832
        }
833
 
834
        len++;
835
        pos++;
836
    }
837
 
838
    if (!format)
839
        return left;
840
    else if (pos > 0)
841
    {
842
        if ((pos % width) != 0)
843
        {
844
            for (int i = 0; i < (width - (pos % width)); i++)
845
                left.append("   ");
846
        }
847
 
848
        out += ind + toHex(old, 4)+": "+left + "  | " + right;
849
    }
850
 
851
    return out;
852
}
853
 
854
void TError::setErrorMsg(const std::string& msg)
855
{
856
    if (msg.empty())
857
        return;
858
 
859
    msError = msg;
860
    mHaveError = true;
861
    mErrType = TERRERROR;
862
}
863
 
864
void TError::setErrorMsg(terrtype_t t, const std::string& msg)
865
{
866
    if (msg.empty())
867
        return;
868
 
869
    msError = msg;
870
    mHaveError = true;
871
    mErrType = t;
872
}
873
 
874
std::ostream & TError::append(int lv, std::ostream& os)
875
{
876
    Current();
877
 
878
    if (!TConfig::isInitialized() && (lv == HLOG_ERROR || lv == HLOG_WARNING))
879
    {
880
        std::cerr << append(lv);
881
        return std::cerr;
882
    }
883
 
884
    return os << append(lv);
885
}
886
 
887
std::string TError::append(int lv)
888
{
889
    std::lock_guard<mutex> guard(message_mutex);
890
    std::string prefix, out;
891
 
892
    switch (lv)
893
    {
894
        case HLOG_PROTOCOL: prefix = "PRT    ++, "; mErrType = TERRINFO; break;
895
        case HLOG_INFO:     prefix = "INF    >>, "; mErrType = TERRINFO; break;
896
        case HLOG_WARNING:  prefix = "WRN    !!, "; mErrType = TERRWARNING; break;
897
        case HLOG_ERROR:    prefix = "ERR *****, "; mErrType = TERRERROR; break;
898
        case HLOG_TRACE:    prefix = "TRC      , "; mErrType = TERRTRACE; break;
899
        case HLOG_DEBUG:    prefix = "DBG    --, "; mErrType = TERRDEBUG; break;
900
 
901
        default:
902
            prefix = "           ";
903
            mErrType = TERRNONE;
904
    }
905
 
906
    if (!TConfig::isLongFormat())
907
        out = prefix + _threadIDtoStr(mThreadID) + " ";
908
    else
909
    {
910
        std::stringstream s;
911
        s << TStreamError::getTime() << " " << prefix << std::setw(20) << " " << ", " << _threadIDtoStr(mThreadID) << " ";
912
        out = s.str();
913
    }
914
 
915
    return out;
916
}
917
 
918
void TError::displayMessage(const std::string& msg)
919
{
920
    QMessageBox m;
921
    m.setText(msg.c_str());
922
 
923
    int cnt = 10;
924
 
925
    QTimer cntDown;
926
    QObject::connect(&cntDown, &QTimer::timeout, [&m, &cnt, &cntDown]()->void
927
        {
928
            if (--cnt < 0)
929
            {
930
                cntDown.stop();
931
                m.close();
932
            }
933
        });
934
 
935
    cntDown.start(1000);
936
    m.exec();
937
}