1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
#ifndef LOGGING_H_
#define LOGGING_H_
#include <QMutexLocker>
#include <QMutex>
#include <QQueue>
#include <QTime>
#include <QPointer>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include "mythbaseexp.h" // MBASE_PUBLIC , etc.
#include "verbosedefs.h"
#include "mythsignalingtimer.h"
#include "mthread.h"
#include "referencecounter.h"
#include "nzmqt.hpp"
#define LOGLINE_MAX (2048-120)
class QString;
class MSqlQuery;
class LoggingItem;
void loggingRegisterThread(const QString &name);
void loggingDeregisterThread(void);
void loggingGetTimeStamp(qlonglong *epoch, uint *usec);
class QWaitCondition;
typedef enum {
kMessage = 0x01,
kRegistering = 0x02,
kDeregistering = 0x04,
kFlush = 0x08,
kStandardIO = 0x10,
kInitializing = 0x20,
} LoggingType;
class LoggerThread;
typedef struct tm tmType;
/// \brief The logging items that are generated by LOG() and are sent to the
/// console and to mythlogserver via ZeroMQ
class LoggingItem: public QObject, public ReferenceCounter
{
Q_OBJECT
Q_PROPERTY(int pid READ pid WRITE setPid)
Q_PROPERTY(qlonglong tid READ tid WRITE setTid)
Q_PROPERTY(qulonglong threadId READ threadId WRITE setThreadId)
Q_PROPERTY(uint usec READ usec WRITE setUsec)
Q_PROPERTY(int line READ line WRITE setLine)
Q_PROPERTY(int type READ type WRITE setType)
Q_PROPERTY(int level READ level WRITE setLevel)
Q_PROPERTY(int facility READ facility WRITE setFacility)
Q_PROPERTY(qlonglong epoch READ epoch WRITE setEpoch)
Q_PROPERTY(QString file READ file WRITE setFile)
Q_PROPERTY(QString function READ function WRITE setFunction)
Q_PROPERTY(QString threadName READ threadName WRITE setThreadName)
Q_PROPERTY(QString appName READ appName WRITE setAppName)
Q_PROPERTY(QString table READ table WRITE setTable)
Q_PROPERTY(QString logFile READ logFile WRITE setLogFile)
Q_PROPERTY(QString message READ message WRITE setMessage)
friend class LoggerThread;
friend void LogPrintLine(uint64_t, LogLevel_t, const char *, int,
const char *, int, const char *, ... );
public:
char *getThreadName(void);
int64_t getThreadTid(void);
void setThreadTid(void);
static LoggingItem *create(const char *, const char *, int, LogLevel_t,
LoggingType);
static LoggingItem *create(QByteArray &buf);
QByteArray toByteArray(void);
int pid() const { return m_pid; };
qlonglong tid() const { return m_tid; };
qulonglong threadId() const { return m_threadId; };
uint usec() const { return m_usec; };
int line() const { return m_line; };
int type() const { return (int)m_type; };
int level() const { return (int)m_level; };
int facility() const { return m_facility; };
qlonglong epoch() const { return m_epoch; };
QString file() const { return QString(m_file); };
QString function() const { return QString(m_function); };
QString threadName() const { return QString(m_threadName); };
QString appName() const { return QString(m_appName); };
QString table() const { return QString(m_table); };
QString logFile() const { return QString(m_logFile); };
QString message() const { return QString(m_message); };
void setPid(const int val) { m_pid = val; };
void setTid(const qlonglong val) { m_tid = val; };
void setThreadId(const qulonglong val) { m_threadId = val; };
void setUsec(const uint val) { m_usec = val; };
void setLine(const int val) { m_line = val; };
void setType(const int val) { m_type = (LoggingType)val; };
void setLevel(const int val) { m_level = (LogLevel_t)val; };
void setFacility(const int val) { m_facility = val; };
void setEpoch(const qlonglong val) { m_epoch = val; };
void setFile(const QString &val)
{ m_file = strdup(val.toLocal8Bit().constData()); };
void setFunction(const QString &val)
{ m_function = strdup(val.toLocal8Bit().constData()); };
void setThreadName(const QString &val)
{ m_threadName = strdup(val.toLocal8Bit().constData()); };
void setAppName(const QString &val)
{ m_appName = strdup(val.toLocal8Bit().constData()); };
void setTable(const QString &val)
{ m_table = strdup(val.toLocal8Bit().constData()); };
void setLogFile(const QString &val)
{ m_logFile = strdup(val.toLocal8Bit().constData()); };
void setMessage(const QString &val)
{
strncpy(m_message, val.toLocal8Bit().constData(), LOGLINE_MAX);
m_message[LOGLINE_MAX] = '\0';
};
const char *rawFile() const { return m_file; };
const char *rawFunction() const { return m_function; };
const char *rawThreadName() const { return m_threadName; };
const char *rawAppName() const { return m_appName; };
const char *rawTable() const { return m_table; };
const char *rawLogFile() const { return m_logFile; };
const char *rawMessage() const { return m_message; };
protected:
int m_pid;
qlonglong m_tid;
qulonglong m_threadId;
uint m_usec;
int m_line;
LoggingType m_type;
LogLevel_t m_level;
int m_facility;
qlonglong m_epoch;
const char *m_file;
const char *m_function;
char *m_threadName;
const char *m_appName;
const char *m_table;
const char *m_logFile;
char m_message[LOGLINE_MAX+1];
private:
LoggingItem();
LoggingItem(const char *_file, const char *_function,
int _line, LogLevel_t _level, LoggingType _type);
~LoggingItem();
};
/// \brief The logging thread that consumes the logging queue and dispatches
/// each LoggingItem to mythlogserver via ZeroMQ
class LoggerThread : public QObject, public MThread
{
Q_OBJECT
friend void LogPrintLine(uint64_t, LogLevel_t, const char *, int,
const char *, int, const char *, ... );
public:
LoggerThread(QString filename, bool progress, bool quiet, QString table,
int facility);
~LoggerThread();
void run(void);
void stop(void);
bool flush(int timeoutMS = 200000);
void handleItem(LoggingItem *item);
void fillItem(LoggingItem *item);
private:
QWaitCondition *m_waitNotEmpty; ///< Condition variable for waiting
/// for the queue to not be empty
/// Protected by logQueueMutex
QWaitCondition *m_waitEmpty; ///< Condition variable for waiting
/// for the queue to be empty
/// Protected by logQueueMutex
bool m_aborted; ///< Flag to abort the thread.
/// Protected by logQueueMutex
volatile bool m_initialWaiting; ///< Waiting for the initial response from
/// mythlogserver
QString m_filename; ///< Filename of debug logfile
bool m_progress; ///< show only LOG_ERR and more important (console only)
int m_quiet; ///< silence the console (console only)
QString m_appname; ///< Cached application name
QString m_tablename; ///< Cached table name for db logging
int m_facility; ///< Cached syslog facility (or -1 to disable)
pid_t m_pid; ///< Cached pid value
bool m_locallogs; ///< Are we logging locally (i.e. this is the
/// mythlogserver itself)
qlonglong m_epoch; ///< Time last heard from the server (seconds)
nzmqt::ZMQContext *m_zmqContext; ///< ZeroMQ context to use
nzmqt::ZMQSocket *m_zmqSocket; ///< ZeroMQ socket to talk to
/// mythlogserver
MythSignalingTimer *m_initialTimer; ///< Timer for the initial startup
MythSignalingTimer *m_heartbeatTimer; ///< Timer for 1s heartbeats
protected:
bool logConsole(LoggingItem *item);
void launchLogServer(void);
void pingLogServer(void);
protected slots:
void messageReceived(const QList<QByteArray>&);
void checkHeartBeat(void);
void initialTimeout(void);
};
#endif
/*
* vim:ts=4:sw=4:ai:et:si:sts=4
*/
|