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