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