Go to the documentation of this file.
4 #include <QMutexLocker>
5 #include <QWaitCondition>
10 #include <QStringList>
12 #include <QRegularExpression>
13 #include <QVariantMap>
33 #include <sys/types.h>
45 #if defined(__linux__)
46 #include <sys/syscall.h>
47 #elif defined(__FreeBSD__)
49 #include <sys/ucontext.h>
52 #elif defined(Q_OS_DARWIN)
53 #include <mach/mach.h>
57 #include <android/log.h>
105 void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext);
106 void loglevelAdd(
int value, QString name,
char shortname);
125 m_threadId((uint64_t)(QThread::currentThreadId())),
126 m_line(_line), m_type(_type), m_level(_level),
127 m_function(_function)
129 const char *slash = std::strrchr(_file,
'/');
130 m_file = (slash !=
nullptr) ? slash+1 : _file;
131 m_epoch = nowAsDuration<std::chrono::microseconds>();
139 static constexpr
char const *kSUnknown =
"thread_unknown";
175 #if defined(Q_OS_ANDROID)
176 m_tid = (int64_t)gettid();
177 #elif defined(__linux__)
178 m_tid = syscall(SYS_gettid);
179 #elif defined(__FreeBSD__)
181 [[maybe_unused]]
int dummy = thr_self( &lwpid );
182 m_tid = (int64_t)lwpid;
183 #elif defined(Q_OS_DARWIN)
184 m_tid = (int64_t)mach_thread_self();
193 QDateTime
epoch = QDateTime::fromMSecsSinceEpoch(
m_epoch.count()/1000);
194 QString timestamp =
epoch.toString(format);
201 timestamp += QString(
".%1").arg((
m_epoch % 1s).count(),6,10,QChar(
'0'));
211 return (*it)->shortname;
217 QString ptid = QString::number(
pid());
220 ptid.append(
"/").append(QString::number(
tid()));
222 return qPrintable(QString(
"%1 %2 [%3] %4 %5:%6:%7 %8\n")
228 QString::number(
line()),
236 return qPrintable(QString(
"%1 %2 %3\n")
247 int facility,
bool loglong) :
249 m_waitNotEmpty(new QWaitCondition()),
250 m_waitEmpty(new QWaitCondition()),
253 m_facility(facility), m_pid(getpid())
255 if (qEnvironmentVariableIsSet(
"VERBOSE_THREADS"))
257 LOG(VB_GENERAL, LOG_NOTICE,
258 "Logging thread registration/deregistration enabled!");
264 LOG(VB_GENERAL, LOG_ERR,
265 "Failed to start LogServer thread");
291 LOG(VB_GENERAL, LOG_INFO,
"Added logging to the console");
300 qApp->processEvents(QEventLoop::AllEvents, 10);
301 qApp->sendPostedEvents(
nullptr, QEvent::DeferredDelete);
332 qApp->processEvents();
352 item->
m_message = QString(
"Thread 0x%1 (%2) registered as \'%3\'")
354 QString::number(item->
m_tid),
376 item->
m_message = QString(
"Thread 0x%1 (%2) deregistered as \'%3\'")
378 QString::number(tid),
412 #if !defined(NDEBUG) || CONFIG_FORCE_LOGLONG
426 std::cout << line << std::flush;
428 #else // Q_OS_ANDROID
430 android_LogPriority aprio;
434 aprio = ANDROID_LOG_FATAL;
439 aprio = ANDROID_LOG_ERROR;
442 aprio = ANDROID_LOG_WARN;
446 aprio = ANDROID_LOG_INFO;
449 aprio = ANDROID_LOG_DEBUG;
453 aprio = ANDROID_LOG_UNKNOWN;
457 __android_log_print(aprio,
"mfe",
"%s:%d:%s %s", qPrintable(item->
m_file),
461 __android_log_print(aprio,
"mfe",
"%s", qPrintable(item->
m_message));
492 int left = timeoutMS -
t.elapsed();
520 const char *_function,
521 int _line, LogLevel_t _level,
524 auto *item =
new LoggingItem(_file, _function, _line, _level, _type);
538 const char *
function, QString message)
552 #if defined( _MSC_VER ) && defined( _DEBUG )
553 OutputDebugStringA( qPrintable(item->
m_message) );
554 OutputDebugStringA(
"\n" );
611 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
614 const CODE *syslogname =
nullptr;
615 for (syslogname = &facilitynames[0];
616 (syslogname->c_name &&
622 #if CONFIG_SYSTEMD_JOURNAL
653 LogLevel_t level,
bool propagate,
bool loglong,
bool testHarness)
659 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Setting Log Level to LOG_%1")
669 QFileInfo finfo(logfile);
670 QString path = finfo.path();
740 LOG(VB_GENERAL, LOG_NOTICE,
741 "Windows does not support syslog, disabling" );
743 #elif defined(Q_OS_ANDROID)
744 LOG(VB_GENERAL, LOG_NOTICE,
745 "Android does not support syslog, disabling" );
748 const CODE *name =
nullptr;
749 QByteArray ba = facility.toLocal8Bit();
750 char *
string = (
char *)ba.constData();
752 for (name = &facilitynames[0];
753 name->c_name && (strcmp(name->c_name,
string) != 0); name++);
755 return( name->c_val );
774 if ( item->name == level.toLower() )
775 return (LogLevel_t)item->value;
793 LoglevelMap::iterator it =
loglevelMap.find((
int)level);
807 void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext)
809 auto *item =
new VerboseDef;
814 name = name.toLower();
816 item->additive = additive;
817 item->helpText = std::move(helptext);
834 name = name.toLower();
836 item->shortname = shortname;
857 #undef VERBOSEDEFS_H_
858 #define MYTH_IMPLEMENT_VERBOSE
871 std::cerr <<
"Verbose debug levels.\n"
872 "Accepts any combination (separated by comma) of:\n\n";
874 for (VerboseMap::Iterator vit =
verboseMap.begin();
877 VerboseDef *item = vit.value();
878 QString name = QString(
" %1").arg(item->name, -15,
' ');
879 if (item->helpText.isEmpty())
881 std::cerr << name.toLocal8Bit().constData() <<
" - "
882 << item->helpText.toLocal8Bit().constData() << std::endl;
885 std::cerr << std::endl <<
886 "The default for this program appears to be: '-v " <<
887 m_verbose.toLocal8Bit().constData() <<
"'\n\n"
888 "Most options are additive except for 'none' and 'all'.\n"
889 "These two are semi-exclusive and take precedence over any\n"
890 "other options. However, you may use something like\n"
891 "'-v none,jobqueue' to receive only JobQueue related messages\n"
892 "and override the default verbosity level.\n\n"
893 "Additive options may also be subtracted from 'all' by\n"
894 "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
895 "to view all but database debug messages.\n\n";
898 <<
"The 'global' loglevel is specified with --loglevel, but can be\n"
899 <<
"overridden on a component by component basis by appending "
901 <<
"to the component.\n"
902 <<
" For example: -v gui:debug,channel:notice,record\n\n";
904 std::cerr <<
"Some debug levels may not apply to this program.\n" << std::endl;
922 if (arg.startsWith(
'-'))
924 std::cerr <<
"Invalid or missing argument to -v/--verbose option\n";
928 static const QRegularExpression kSeparatorRE {
"[^\\w:]+" };
929 QStringList verboseOpts = arg.split(kSeparatorRE, Qt::SkipEmptyParts);
930 for (
const auto& opt : std::as_const(verboseOpts))
932 option = opt.toLower();
933 bool reverseOption =
false;
936 if (option !=
"none" && option.startsWith(
"no"))
938 reverseOption =
true;
939 option = option.right(option.length() - 2);
942 if (option ==
"help")
947 if (option ==
"important")
949 std::cerr <<
"The \"important\" log mask is no longer valid.\n";
951 else if (option ==
"extra")
953 std::cerr <<
"The \"extra\" log mask is no longer valid. Please try "
954 "--loglevel debug instead.\n";
956 else if (option ==
"default")
971 int idx = option.indexOf(
':');
974 optionLevel = option.mid(idx + 1);
975 option = option.left(idx);
1004 if (!optionLevel.isEmpty())
1007 if (level != LOG_UNKNOWN)
1014 std::cerr <<
"Unknown argument for -v/--verbose: " <<
1015 option.toLocal8Bit().constData() << std::endl;;
1037 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 logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool propagate, bool loglong, bool testHarness)
Entry point to start logging for the application.
void logForwardStop(void)
QString getTimestamp(const char *format="yyyy-MM-dd HH:mm:ss") const
Convert numerical timestamp to a readable date and time.
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.
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.
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
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.
LogPropagateOpts logPropagateOpts
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.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
bool logForwardStart(void)
std::string toString()
Long format to string.
static bool logThreadFinished
void logForwardMessage(LoggingItem *item)
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)
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.
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
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.
@ GENERIC_EXIT_OK
Exited with no error.
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.
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
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.
std::chrono::microseconds m_epoch
static LoggerThread * logThread
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
std::string toStringShort()
short console format
int syslogGetFacility([[maybe_unused]] const QString &facility)
Map a syslog facility name back to the enumerated value.
bool haveUserDefaultValues
LoggerThread(QString filename, bool progress, bool quiet, int facility, bool loglong)
LoggerThread constructor.
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
QString getTimestampUs(const char *format="yyyy-MM-dd HH:mm:ss") const
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.
static QMutex logThreadTidMutex
static void handleItem(LoggingItem *item)
Handles each LoggingItem.
bool m_loglong
use long log format (console only)
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