Go to the documentation of this file.
3 #include <QMutexLocker>
4 #include <QWaitCondition>
11 #include <QRegularExpression>
12 #include <QVariantMap>
33 #include <sys/types.h>
46 #include <sys/syscall.h>
47 #elif defined(__FreeBSD__)
49 #include <sys/ucontext.h>
53 #include <mach/mach.h>
57 #include "qjsonwrapper/Json.h"
60 #include <android/log.h>
109 void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext);
110 void loglevelAdd(
int value, QString name,
char shortname);
128 #if HAVE_GETTIMEOFDAY
129 struct timeval tv {};
130 gettimeofday(&tv,
nullptr);
137 *epoch = date.toTime_t();
140 QTime time = date.time();
141 *usec = time.msec() * 1000;
149 m_threadId((uint64_t)(QThread::currentThreadId())),
150 m_line(_line), m_type(_type), m_level(_level),
151 m_file(_file), m_function(_function)
159 QVariantMap variant = QJsonWrapper::qobject2qvariant(
this);
160 QByteArray json = QJsonWrapper::toJson(variant);
171 static constexpr
char const *kSUnknown =
"thread_unknown";
207 #if defined(Q_OS_ANDROID)
208 m_tid = (int64_t)gettid();
210 m_tid = syscall(SYS_gettid);
211 #elif defined(__FreeBSD__)
213 int dummy = thr_self( &lwpid );
215 m_tid = (int64_t)lwpid;
217 m_tid = (int64_t)mach_thread_self();
227 QString timestamp =
epoch.toString(
"yyyy-MM-dd HH:mm:ss");
234 timestamp += QString(
".%1").arg(
m_usec,6,10,QChar(
'0'));
244 return (*it)->shortname;
252 QString table,
int facility) :
254 m_waitNotEmpty(new QWaitCondition()),
255 m_waitEmpty(new QWaitCondition()),
257 m_tablename(std::move(table)), m_facility(facility), m_pid(getpid())
259 if (qEnvironmentVariableIsSet(
"VERBOSE_THREADS"))
261 LOG(VB_GENERAL, LOG_NOTICE,
262 "Logging thread registration/deregistration enabled!");
268 LOG(VB_GENERAL, LOG_ERR,
269 "Failed to start LogServer thread");
295 LOG(VB_GENERAL, LOG_INFO,
"Added logging to the console");
304 qApp->processEvents(QEventLoop::AllEvents, 10);
305 qApp->sendPostedEvents(
nullptr, QEvent::DeferredDelete);
336 qApp->processEvents();
356 item->
m_message = QString(
"Thread 0x%1 (%2) registered as \'%3\'")
358 QString::number(item->
m_tid),
380 item->
m_message = QString(
"Thread 0x%1 (%2) deregistered as \'%3\'")
382 QString::number(tid),
398 QList<QByteArray> list;
399 list.append(QByteArray());
432 line = qPrintable(QString(
"%1 %2 [%3/%4] %5 %6:%7:%8 %9\n")
433 .
arg(timestamp, QString(shortname),
434 QString::number(item->
pid()),
435 QString::number(item->
tid()),
438 QString::number(item->
m_line),
444 line = qPrintable(QString(
"%1 %2 [%3] %4 %5:%6:%7 %8\n")
445 .
arg(timestamp, QString(shortname),
446 QString::number(item->
pid()),
449 QString::number(item->
m_line),
454 line = qPrintable(QString(
"%1 %2 %3\n")
455 .
arg(timestamp, QString(shortname),
460 (void)
write(1, line.data(), line.size());
462 #else // Q_OS_ANDROID
464 android_LogPriority aprio;
468 aprio = ANDROID_LOG_FATAL;
473 aprio = ANDROID_LOG_ERROR;
476 aprio = ANDROID_LOG_WARN;
480 aprio = ANDROID_LOG_INFO;
483 aprio = ANDROID_LOG_DEBUG;
487 aprio = ANDROID_LOG_UNKNOWN;
491 __android_log_print(aprio,
"mfe",
"%s:%d:%s %s", qPrintable(item->
m_file),
495 __android_log_print(aprio,
"mfe",
"%s", qPrintable(item->
m_message));
526 int left = timeoutMS -
t.elapsed();
555 const char *_function,
556 int _line, LogLevel_t _level,
559 auto *item =
new LoggingItem(_file, _function, _line, _level, _type);
567 QVariant variant = QJsonWrapper::parseJson(buf);
570 QJsonWrapper::qvariant2qobject(variant.toMap(), item);
585 const char *
function, QString message)
599 #if defined( _MSC_VER ) && defined( _DEBUG )
600 OutputDebugStringA( qPrintable(item->
m_message) );
601 OutputDebugStringA(
"\n" );
658 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
661 const CODE *syslogname =
nullptr;
662 for (syslogname = &facilitynames[0];
663 (syslogname->c_name &&
669 #if CONFIG_SYSTEMD_JOURNAL
701 LogLevel_t level,
bool dblog,
bool propagate,
bool testHarness)
707 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Setting Log Level to LOG_%1")
718 QString path = finfo.path();
726 QString table = dblog ? QString(
"logging") : QString(
"");
790 LOG(VB_GENERAL, LOG_NOTICE,
791 "Windows does not support syslog, disabling" );
794 #elif defined(Q_OS_ANDROID)
795 LOG(VB_GENERAL, LOG_NOTICE,
796 "Android does not support syslog, disabling" );
800 const CODE *name =
nullptr;
802 QByteArray ba = facility.toLocal8Bit();
803 char *
string = (
char *)ba.constData();
805 for (i = 0, name = &facilitynames[0];
806 name->c_name && (strcmp(name->c_name,
string) != 0); i++, name++);
808 return( name->c_val );
827 if ( item->name == level.toLower() )
828 return (LogLevel_t)item->value;
846 LoglevelMap::iterator it =
loglevelMap.find((
int)level);
849 return QString(
"unknown");
860 void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext)
862 auto *item =
new VerboseDef;
867 name = name.toLower();
869 item->additive = additive;
870 item->helpText = std::move(helptext);
887 name = name.toLower();
889 item->shortname = shortname;
910 #undef VERBOSEDEFS_H_
911 #define MYTH_IMPLEMENT_VERBOSE
924 std::cerr <<
"Verbose debug levels.\n"
925 "Accepts any combination (separated by comma) of:\n\n";
927 for (VerboseMap::Iterator vit =
verboseMap.begin();
930 VerboseDef *item = vit.value();
931 QString name = QString(
" %1").arg(item->name, -15,
' ');
932 if (item->helpText.isEmpty())
934 std::cerr << name.toLocal8Bit().constData() <<
" - "
935 << item->helpText.toLocal8Bit().constData() << std::endl;
938 std::cerr << std::endl <<
939 "The default for this program appears to be: '-v " <<
940 m_verbose.toLocal8Bit().constData() <<
"'\n\n"
941 "Most options are additive except for 'none' and 'all'.\n"
942 "These two are semi-exclusive and take precedence over any\n"
943 "other options. However, you may use something like\n"
944 "'-v none,jobqueue' to receive only JobQueue related messages\n"
945 "and override the default verbosity level.\n\n"
946 "Additive options may also be subtracted from 'all' by\n"
947 "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
948 "to view all but database debug messages.\n\n";
951 <<
"The 'global' loglevel is specified with --loglevel, but can be\n"
952 <<
"overridden on a component by component basis by appending "
954 <<
"to the component.\n"
955 <<
" For example: -v gui:debug,channel:notice,record\n\n";
957 std::cerr <<
"Some debug levels may not apply to this program.\n" << std::endl;
975 if (
arg.startsWith(
'-'))
977 std::cerr <<
"Invalid or missing argument to -v/--verbose option\n";
981 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
982 QStringList verboseOpts =
arg.split(QRegularExpression(
"[^\\w:]+"),
983 QString::SkipEmptyParts);
985 QStringList verboseOpts =
arg.split(QRegularExpression(
"[^\\w:]+"),
988 for (
const auto& opt : qAsConst(verboseOpts))
990 option = opt.toLower();
991 bool reverseOption =
false;
994 if (option !=
"none" && option.startsWith(
"no"))
996 reverseOption =
true;
997 option = option.right(option.length() - 2);
1000 if (option ==
"help")
1005 if (option ==
"important")
1007 std::cerr <<
"The \"important\" log mask is no longer valid.\n";
1009 else if (option ==
"extra")
1011 std::cerr <<
"The \"extra\" log mask is no longer valid. Please try "
1012 "--loglevel debug instead.\n";
1014 else if (option ==
"default")
1029 int idx = option.indexOf(
':');
1032 optionLevel = option.mid(idx + 1);
1033 option = option.left(idx);
1062 if (!optionLevel.isEmpty())
1065 if (level != LOG_UNKNOWN)
1072 std::cerr <<
"Unknown argument for -v/--verbose: " <<
1073 option.toLocal8Bit().constData() << std::endl;;
1095 return QString(
"%1 (%2)").arg(strerror(errnum)).arg(errnum);
void loggingDeregisterThread(void)
Deregister the current thread's name.
QMap< int, LoglevelDef * > LoglevelMap
static bool debugRegistration
void logForwardStop(void)
static QHash< uint64_t, QString > logThreadHash
QString logStrerror(int errnum)
Verbose helper function for ENO macro.
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
#define GENERIC_EXIT_OK
Exited with no error.
QString m_tablename
Cached table name for db logging.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
static QQueue< LoggingItem * > logQueue
void logPropagateCalc(void)
Generate the logPropagateArgs global with the latest logging level, mask, etc to propagate to all of ...
ComponentLogLevelMap componentLogLevel
QWaitCondition * m_waitNotEmpty
Condition variable for waiting for the queue to not be empty Protected by logQueueMutex.
QString m_appname
Cached application name.
void verboseHelp(void)
Outputs the Verbose levels and their descriptions (for –verbose help)
QString getThreadName(void)
Get the name of the thread that produced the LoggingItem.
void verboseInit(void)
Initialize the logging levels and verbose levels.
def write(text, progress=True)
void logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool dblog, bool propagate, bool testHarness)
Entry point to start logging for the application.
LogPropagateOpts logPropagateOpts
int syslogGetFacility(const QString &facility)
Map a syslog facility name back to the enumerated value.
arg(title).arg(filename).arg(doDelete))
The logging thread that consumes the logging queue and dispatches each LoggingItem.
QWaitCondition * m_waitEmpty
Condition variable for waiting for the queue to be empty Protected by logQueueMutex.
void logForwardMessage(const QList< QByteArray > &msg)
LoggerThread(QString filename, bool progress, bool quiet, QString table, int facility)
LoggerThread constructor.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
bool logForwardStart(void)
#define GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
static bool logThreadFinished
void setThreadName(const QString &val)
The logging items that are generated by LOG() and are sent to the console.
bool m_progress
show only LOG_ERR and more important (console only)
void fillItem(LoggingItem *item)
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(uint seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
char getLevelChar(void)
Get the message log level as a single character.
void LogPrintLine(uint64_t mask, LogLevel_t level, const char *file, int line, const char *function, QString message)
Format and send a log message into the queue.
void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
Add a verbose level to the verboseMap.
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
void loggingRegisterThread(const QString &name)
Register the current thread with the given name.
bool m_aborted
Flag to abort the thread.
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
static QMutex logThreadMutex
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
const QString verboseDefaultStr
void setThreadTid(void)
Set the thread ID of the thread that produced the LoggingItem.
QString m_filename
Filename of debug logfile.
void run(void) override
Run the logging thread.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
uint64_t userDefaultValueInt
bool logConsole(LoggingItem *item) const
Process a log message, writing to the console.
QString getTimestamp(void) const
Convert numerical timestamp to a readable date and time.
bool flush(int timeoutMS=200000)
Wait for the queue to be flushed (up to a timeout)
void setFacility(const int val)
void stop(void)
Stop the thread by setting the abort flag after waiting a second for the queue to be flushed.
QString userDefaultValueStr
void setTable(const QString &val)
bool m_quiet
silence the console (console only)
int m_facility
Cached syslog facility (or -1 to disable)
void logStop(void)
Entry point for stopping logging for an application.
static LoggerThread * logThread
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
QString getTimestampUs(void) const
void loggingGetTimeStamp(qlonglong *epoch, uint *usec)
bool haveUserDefaultValues
const uint64_t verboseDefaultInt
static QMutex logQueueMutex
static LoggingItem * create(const char *_file, const char *_function, int _line, LogLevel_t _level, LoggingType _type)
Create a new LoggingItem.
static QHash< uint64_t, int64_t > logThreadTidHash
QStringList logPropagateArgList
This is a wrapper around QThread that does several additional things.
QMap< uint64_t, LogLevel_t > ComponentLogLevelMap
bool isRunning(void) const
void loglevelAdd(int value, QString name, char shortname)
Add a log level to the logLevelMap.
void setAppName(const QString &val)
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
pid_t m_pid
Cached pid value.
int64_t getThreadTid(void)
Get the thread ID of the thread that produced the LoggingItem.
QByteArray toByteArray(void)
static QMutex logThreadTidMutex
static void handleItem(LoggingItem *item)
Handles each LoggingItem.
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
virtual int IncrRef(void)
Increments reference count.
~LoggerThread() override
LoggerThread destructor. Triggers the deletion of all loggers.
void setPid(const int val)
void setLogFile(const QString &val)
void resetLogging(void)
Intended for use only by the test harness.
General purpose reference counter.
QMap< QString, VerboseDef * > VerboseMap