summaryrefslogtreecommitdiffstats
path: root/mythtv/libs/libmythbase/logging.h
blob: be339cee95cac5884b6ea54ade2ecdcd9bd05fce (plain)
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
 */