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