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