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
 
28
using std::string;
14 andreas 29
std::mutex message_mutex;
2 andreas 30
 
31
bool TError::mHaveError = false;
32
terrtype_t TError::mErrType = TERRNONE;
33
TStreamError *TError::mCurrent = nullptr;
34
std::string TError::msError;
35
 
36
int TStreamError::mIndent = 1;
37
std::ostream *TStreamError::mStream = nullptr;
38
std::string TStreamError::mLogfile;
39
bool TStreamError::mInitialized = false;
40
unsigned int TStreamError::mLogLevel = LOG_PROTOCOL;
41
 
42
TStreamError::TStreamError(const string& logFile, const std::string& logLevel)
43
{
14 andreas 44
    if (!logFile.empty())
45
        setLogFile(logFile);
46
    else if (!TConfig::getLogFile().empty())
47
        setLogFile(TConfig::getLogFile());
2 andreas 48
 
14 andreas 49
    if (!logLevel.empty())
50
        setLogLevel(logLevel);
51
    else if (!TConfig::getLogLevel().empty())
52
        setLogLevel(TConfig::getLogFile());
2 andreas 53
 
14 andreas 54
    _init();
2 andreas 55
}
56
 
57
TStreamError::~TStreamError()
58
{
14 andreas 59
    if (mStream && mStream != &std::cout)
60
    {
61
        delete mStream;
62
        mStream = nullptr;
63
        mInitialized = false;
64
    }
2 andreas 65
}
66
 
67
void TStreamError::setLogLevel(const std::string& slv)
68
{
14 andreas 69
    size_t pos = slv.find("|");
70
    size_t start = 0;
71
    string lv;
72
    mLogLevel = 0;
2 andreas 73
 
14 andreas 74
    while (pos != string::npos)
75
    {
76
        lv = slv.substr(start, pos - start);
77
        start = pos + 1;
78
        mLogLevel |= _getLevel(lv);
79
        pos = slv.find("|", start);
80
    }
2 andreas 81
 
14 andreas 82
    mLogLevel |= _getLevel(slv.substr(start));
2 andreas 83
}
84
 
85
bool TStreamError::checkFilter(terrtype_t err)
86
{
14 andreas 87
    if (err == TERRINFO && (mLogLevel & LOG_INFO) != 0)
88
        return true;
89
    else if (err == TERRWARNING && (mLogLevel & LOG_WARNING) != 0)
90
        return true;
91
    else if (err == TERRERROR && (mLogLevel & LOG_ERROR) != 0)
92
        return true;
93
    else if (err == TERRTRACE && (mLogLevel & LOG_TRACE) != 0)
94
        return true;
95
    else if (err == TERRDEBUG && (mLogLevel & LOG_DEBUG) != 0)
96
        return true;
2 andreas 97
 
14 andreas 98
    return false;
2 andreas 99
}
100
 
101
bool TStreamError::checkFilter(int lv)
102
{
14 andreas 103
    if ((mLogLevel & lv) != 0)
104
        return true;
2 andreas 105
 
14 andreas 106
    return false;
2 andreas 107
}
108
 
109
unsigned int TStreamError::_getLevel(const std::string& slv)
110
{
14 andreas 111
    if (slv.compare(SLOG_NONE) == 0)
112
        return LOG_NONE;
2 andreas 113
 
14 andreas 114
    if (slv.compare(SLOG_INFO) == 0)
115
        return LOG_INFO;
2 andreas 116
 
14 andreas 117
    if (slv.compare(SLOG_WARNING) == 0)
118
        return LOG_WARNING;
2 andreas 119
 
14 andreas 120
    if (slv.compare(SLOG_ERROR) == 0)
121
        return LOG_ERROR;
2 andreas 122
 
14 andreas 123
    if (slv.compare(SLOG_TRACE) == 0)
124
        return LOG_TRACE;
2 andreas 125
 
14 andreas 126
    if (slv.compare(SLOG_DEBUG) == 0)
127
        return LOG_DEBUG;
2 andreas 128
 
14 andreas 129
    if (slv.compare(SLOG_PROTOCOL) == 0)
130
        return LOG_PROTOCOL;
2 andreas 131
 
14 andreas 132
    if (slv.compare(SLOG_ALL) == 0)
133
        return LOG_ALL;
2 andreas 134
 
14 andreas 135
    return LOG_NONE;
2 andreas 136
}
137
 
138
void TStreamError::_init()
139
{
14 andreas 140
    if (mInitialized)
141
        return;
2 andreas 142
 
14 andreas 143
    mInitialized = true;
2 andreas 144
 
14 andreas 145
    if (!mLogfile.empty())
146
    {
147
        if (mStream)
148
            delete mStream;
2 andreas 149
 
14 andreas 150
        mStream = new std::ofstream(mLogfile.c_str(), std::ios::out | std::ios::ate);
2 andreas 151
 
14 andreas 152
        if (!mStream || mStream->fail())
153
            mStream = &std::cout;
154
    }
155
    else
156
        mStream = &std::cout;
2 andreas 157
 
14 andreas 158
    if (!TConfig::isLongFormat())
159
        *mStream << "Logfile started at " << getTime() << std::endl;
2 andreas 160
 
14 andreas 161
    *mStream << TConfig::getProgName() << " version " << V_MAJOR << "." << V_MINOR << "." << V_PATCH << std::endl;
162
    *mStream << "(C) Copyright by Andreas Theofilu <andreas@theosys.at>" << std::endl << std::endl << std::flush;
2 andreas 163
 
14 andreas 164
    if (TConfig::isLongFormat())
165
        *mStream << "Timestamp           Type LNr., File name           , Message" << std::endl;
166
    else
167
        *mStream << "Type LNr., Message" << std::endl;
2 andreas 168
 
14 andreas 169
    *mStream << "-----------------------------------------------------------------" << std::endl;
170
}
2 andreas 171
 
172
void TStreamError::logMsg(std::ostream& str)
173
{
5 andreas 174
    _init();
2 andreas 175
 
5 andreas 176
    if (!mStream || str.fail())
177
        return;
2 andreas 178
 
5 andreas 179
    // Save the old format settings in case they were manipulated
180
    std::ios oldstate(nullptr);
181
    oldstate.copyfmt(std::cout);
182
    // Print out the message
183
    std::stringstream s;
184
    s << str.rdbuf() << std::ends;
185
    *mStream << s.str() << std::flush;
186
 
187
    mStream->copyfmt(oldstate);     // Restore old format (reset)
2 andreas 188
}
189
 
190
void TStreamError::decIndent()
191
{
14 andreas 192
    if (mIndent > 0)
193
        mIndent--;
2 andreas 194
}
195
 
196
string TStreamError::getTime()
197
{
14 andreas 198
    time_t rawtime;
199
    struct tm * timeinfo;
200
    char buffer[80];
2 andreas 201
 
14 andreas 202
    time(&rawtime);
203
    timeinfo = localtime(&rawtime);
2 andreas 204
 
14 andreas 205
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
206
    string str(buffer);
207
    return str;
2 andreas 208
}
209
 
210
std::ostream& indent(std::ostream& os)
211
{
14 andreas 212
    if (os.fail())
213
        return os;
2 andreas 214
 
14 andreas 215
    if (TStreamError::getIndent() > 0)
216
        os << std::setw(TStreamError::getIndent()) << " ";
2 andreas 217
 
14 andreas 218
    return os;
2 andreas 219
}
220
 
221
/********************************************************************/
222
 
14 andreas 223
std::mutex tracer_mutex;
224
 
2 andreas 225
TTracer::TTracer(const std::string& msg, int line, char *file)
226
{
14 andreas 227
    if (!TStreamError::checkFilter(LOG_TRACE))
228
        return;
2 andreas 229
 
14 andreas 230
    tracer_mutex.lock();
231
    mFile = file;
232
    size_t pos = mFile.find_last_of("/");
2 andreas 233
 
14 andreas 234
    if (pos != string::npos)
235
        mFile = mFile.substr(pos + 1);
2 andreas 236
 
14 andreas 237
    if (!TConfig::isLongFormat())
238
        TError::Current()->logMsg(*TStreamError::getStream() << "TRC " << std::setw(5) << std::right << line << ", " << indent << "{entry " << msg << std::endl);
239
    else
240
        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);
2 andreas 241
 
14 andreas 242
    TError::Current()->incIndent();
243
    mHeadMsg = msg;
244
    mLine = line;
245
    tracer_mutex.unlock();
2 andreas 246
}
247
 
248
TTracer::~TTracer()
249
{
14 andreas 250
    if (!TStreamError::checkFilter(LOG_TRACE))
251
        return;
2 andreas 252
 
14 andreas 253
    tracer_mutex.lock();
254
    TError::Current()->decIndent();
2 andreas 255
 
14 andreas 256
    if (!TConfig::isLongFormat())
257
        TError::Current()->logMsg(*TStreamError::getStream() << "TRC      , " << indent << "}exit " << mHeadMsg << std::endl);
258
    else
259
        TError::Current()->logMsg(*TStreamError::getStream() << TStreamError::getTime() << " TRC      , " << std::setw(20) << std::left << mFile << ", " << indent << "}exit " << mHeadMsg << std::endl);
260
 
261
    mHeadMsg.clear();
262
    tracer_mutex.unlock();
2 andreas 263
}
264
 
265
/********************************************************************/
266
 
267
TError::~TError()
268
{
14 andreas 269
    if (mCurrent)
270
    {
271
        delete mCurrent;
272
        mCurrent = nullptr;
273
    }
2 andreas 274
}
275
 
14 andreas 276
void TError::lock()
277
{
278
    message_mutex.lock();
279
}
280
 
281
void TError::unlock()
282
{
283
    message_mutex.unlock();
284
}
285
 
2 andreas 286
TStreamError* TError::Current()
287
{
14 andreas 288
    if (!mCurrent)
289
        mCurrent = new TStreamError(TConfig::getLogFile(), TConfig::getLogLevel());
2 andreas 290
 
14 andreas 291
    return mCurrent;
2 andreas 292
}
293
 
5 andreas 294
void TError::logHex(char* str, size_t size)
295
{
296
    if (!str || !size)
297
        return;
298
 
21 andreas 299
    message_mutex.lock();
5 andreas 300
    Current();
301
    // Save the old format settings in case they were manipulated
302
    std::ios oldstate(nullptr);
303
    oldstate.copyfmt(std::cout);
304
    // Print out the message
305
    std::ostream *stream = mCurrent->getStream();
21 andreas 306
    *stream << strToHex(str, size, 16, true, 12) << std::endl;
307
    stream->copyfmt(oldstate);     // Restore old format (reset)
308
    message_mutex.unlock();
309
}
5 andreas 310
 
21 andreas 311
string TError::toHex(int num, int width)
312
{
313
    string ret;
314
    std::stringstream stream;
315
    stream << std::setfill ('0') << std::setw(width) << std::hex << num;
316
    ret = stream.str();
317
    return ret;
318
}
319
 
320
string TError::strToHex(const char *str, size_t size, int width, bool format, int indent)
321
{
322
    DECL_TRACER("TError::strToHex(const char *str, size_t size, int width, bool format, int indent)");
323
 
324
    int len = 0, pos = 0, old = 0;
325
    int w = (format) ? 1 : width;
326
    string out, left, right;
327
    string ind;
328
 
329
    if (indent > 0)
330
    {
331
        for (int j = 0; j < indent; j++)
332
            ind.append(" ");
333
    }
334
 
5 andreas 335
    for (size_t i = 0; i < size; i++)
336
    {
21 andreas 337
        if (len >= w)
338
        {
339
            left.append(" ");
340
            len = 0;
341
        }
5 andreas 342
 
21 andreas 343
        if (format && i > 0 && (pos % width) == 0)
5 andreas 344
        {
21 andreas 345
            out += ind + toHex(old, 4) + ": " + left + " | " + right + "\n";
346
            left.clear();
347
            right.clear();
348
            old = pos;
5 andreas 349
        }
21 andreas 350
 
351
        int c = *(str+i) & 0x000000ff;
352
        left.append(toHex(c, 2));
353
 
354
        if (format)
355
        {
356
            if (std::isprint(c))
357
                right.push_back(c);
358
            else
359
                right.push_back('.');
360
        }
361
 
362
        len++;
363
        pos++;
5 andreas 364
    }
365
 
21 andreas 366
    if (!format)
367
        return left;
368
    else if (pos > 0)
369
    {
370
        if ((pos % width) != 0)
371
        {
372
            for (int i = 0; i < (width - (pos % width)); i++)
373
                left.append("   ");
374
        }
375
 
376
        out += ind + toHex(old, 4)+": "+left + "  | " + right;
377
    }
378
 
379
    return out;
5 andreas 380
}
381
 
2 andreas 382
void TError::setErrorMsg(const std::string& msg)
383
{
14 andreas 384
    if (msg.empty())
385
        return;
2 andreas 386
 
14 andreas 387
    msError = msg;
388
    mHaveError = true;
389
    mErrType = TERRERROR;
2 andreas 390
}
391
 
392
void TError::setErrorMsg(terrtype_t t, const std::string& msg)
393
{
14 andreas 394
    if (msg.empty())
395
        return;
2 andreas 396
 
14 andreas 397
    msError = msg;
398
    mHaveError = true;
399
    mErrType = t;
2 andreas 400
}
401
 
402
std::ostream & TError::append(int lv, std::ostream& os)
403
{
14 andreas 404
    std::string prefix;
405
    Current();
2 andreas 406
 
14 andreas 407
    switch (lv)
408
    {
409
        case LOG_INFO:      prefix = "INF    >>, "; break;
2 andreas 410
 
14 andreas 411
        case LOG_WARNING:   prefix = "WRN    !!, "; break;
2 andreas 412
 
14 andreas 413
        case LOG_ERROR:     prefix = "ERR *****, "; break;
414
 
415
        case LOG_TRACE:     prefix = "TRC      , "; break;
416
 
417
        case LOG_DEBUG:     prefix = "DBG    --, "; break;
418
 
419
        default:
420
            prefix = "    ";
421
    }
422
 
423
    if (!TConfig::isLongFormat())
424
        return os << prefix;
425
    else
426
        return os << TStreamError::getTime() << " " << prefix << std::setw(20) << " " << ", ";
2 andreas 427
}