5#include <QWaitCondition>
12#include <QRegularExpression>
46#include <sys/syscall.h>
47#elif defined(__FreeBSD__)
49#include <sys/ucontext.h>
52#elif defined(Q_OS_DARWIN)
57#include <android/log.h>
105void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext);
106void 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;
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();
744 LOG(VB_GENERAL, LOG_NOTICE,
745 "Windows does not support syslog, disabling" );
747#elif defined(Q_OS_ANDROID)
748 LOG(VB_GENERAL, LOG_NOTICE,
749 "Android does not support syslog, disabling" );
752 const CODE *name =
nullptr;
753 QByteArray ba = facility.toLocal8Bit();
754 char *
string = (
char *)ba.constData();
756 for (name = &facilitynames[0];
757 name->c_name && (strcmp(name->c_name,
string) != 0); name++);
759 return( name->c_val );
778 if ( item->name == level.toLower() )
779 return (LogLevel_t)item->value;
797 LoglevelMap::iterator it =
loglevelMap.find((
int)level);
811void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext)
818 name = name.toLower();
820 item->additive = additive;
821 item->helpText = std::move(helptext);
838 name = name.toLower();
840 item->shortname = shortname;
864#define MYTH_IMPLEMENT_VERBOSE
877 std::cerr <<
"Verbose debug levels.\n"
878 "Accepts any combination (separated by comma) of:\n\n";
880 for (VerboseMap::Iterator vit =
verboseMap.begin();
884 QString name = QString(
" %1").arg(item->
name, -15,
' ');
887 std::cerr << name.toLocal8Bit().constData() <<
" - "
888 << item->
helpText.toLocal8Bit().constData() << std::endl;
891 std::cerr << std::endl <<
892 "The default for this program appears to be: '-v " <<
893 m_verbose.toLocal8Bit().constData() <<
"'\n\n"
894 "Most options are additive except for 'none' and 'all'.\n"
895 "These two are semi-exclusive and take precedence over any\n"
896 "other options. However, you may use something like\n"
897 "'-v none,jobqueue' to receive only JobQueue related messages\n"
898 "and override the default verbosity level.\n\n"
899 "Additive options may also be subtracted from 'all' by\n"
900 "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
901 "to view all but database debug messages.\n\n";
904 <<
"The 'global' loglevel is specified with --loglevel, but can be\n"
905 <<
"overridden on a component by component basis by appending "
907 <<
"to the component.\n"
908 <<
" For example: -v gui:debug,channel:notice,record\n\n";
910 std::cerr <<
"Some debug levels may not apply to this program.\n" << std::endl;
928 if (arg.startsWith(
'-'))
930 std::cerr <<
"Invalid or missing argument to -v/--verbose option\n";
934 static const QRegularExpression kSeparatorRE {
"[^\\w:]+" };
935 QStringList verboseOpts = arg.split(kSeparatorRE, Qt::SkipEmptyParts);
936 for (
const auto& opt : std::as_const(verboseOpts))
938 option = opt.toLower();
939 bool reverseOption =
false;
942 if (option !=
"none" && option.startsWith(
"no"))
944 reverseOption =
true;
945 option = option.right(option.length() - 2);
948 if (option ==
"help")
953 if (option ==
"important")
955 std::cerr <<
"The \"important\" log mask is no longer valid.\n";
957 else if (option ==
"extra")
959 std::cerr <<
"The \"extra\" log mask is no longer valid. Please try "
960 "--loglevel debug instead.\n";
962 else if (option ==
"default")
977 int idx = option.indexOf(
':');
980 optionLevel = option.mid(idx + 1);
981 option = option.left(idx);
1010 if (!optionLevel.isEmpty())
1013 if (level != LOG_UNKNOWN)
1020 std::cerr <<
"Unknown argument for -v/--verbose: " <<
1021 option.toLocal8Bit().constData() << std::endl;;
1043 return QString(
"%1 (%2)").arg(strerror(errnum)).arg(errnum);
The logging thread that consumes the logging queue and dispatches each LoggingItem.
void stop(void)
Stop the thread by setting the abort flag after waiting a second for the queue to be flushed.
LoggerThread(QString filename, bool progress, bool quiet, int facility, bool loglong)
LoggerThread constructor.
bool m_quiet
silence the console (console only)
bool m_progress
show only LOG_ERR and more important (console only)
QString m_appname
Cached application name.
int m_facility
Cached syslog facility (or -1 to disable)
void run(void) override
Run the logging thread.
~LoggerThread() override
LoggerThread destructor. Triggers the deletion of all loggers.
QWaitCondition * m_waitEmpty
Condition variable for waiting for the queue to be empty Protected by logQueueMutex.
void fillItem(LoggingItem *item)
bool flush(int timeoutMS=200000)
Wait for the queue to be flushed (up to a timeout)
pid_t m_pid
Cached pid value.
bool logConsole(LoggingItem *item) const
Process a log message, writing to the console.
bool m_aborted
Flag to abort the thread.
QWaitCondition * m_waitNotEmpty
Condition variable for waiting for the queue to not be empty Protected by logQueueMutex.
bool m_loglong
use long log format (console only)
QString m_filename
Filename of debug logfile.
static void handleItem(LoggingItem *item)
Handles each LoggingItem.
The logging items that are generated by LOG() and are sent to the console.
char getLevelChar(void)
Get the message log level as a single character.
static LoggingItem * create(const char *_file, const char *_function, int _line, LogLevel_t _level, LoggingType _type)
Create a new LoggingItem.
void setThreadName(const QString &val)
QString getTimestampUs(const char *format="yyyy-MM-dd HH:mm:ss") const
void setAppName(const QString &val)
std::string toString()
Long format to string.
void setPid(const int val)
void setFacility(const int val)
QString getTimestamp(const char *format="yyyy-MM-dd HH:mm:ss") const
Convert numerical timestamp to a readable date and time.
int64_t getThreadTid(void)
Get the thread ID of the thread that produced the LoggingItem.
void setThreadTid(void)
Set the thread ID of the thread that produced the LoggingItem.
void setLogFile(const QString &val)
std::string toStringShort()
short console format
std::chrono::microseconds m_epoch
QString getThreadName(void)
Get the name of the thread that produced the LoggingItem.
This is a wrapper around QThread that does several additional things.
bool isRunning(void) const
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
General purpose reference counter.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual int IncrRef(void)
Increments reference count.
@ GENERIC_EXIT_OK
Exited with no error.
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
QString userDefaultValueStr
void verboseHelp(void)
Outputs the Verbose levels and their descriptions (for –verbose help)
void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
Add a verbose level to the verboseMap.
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
void verboseInit(void)
Initialize the logging levels and verbose levels.
uint64_t userDefaultValueInt
static QHash< uint64_t, int64_t > logThreadTidHash
void loggingDeregisterThread(void)
Deregister the current thread's name.
void loggingRegisterThread(const QString &name)
Register the current thread with the given name.
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.
const QString verboseDefaultStr
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
static QHash< uint64_t, QString > logThreadHash
const uint64_t verboseDefaultInt
ComponentLogLevelMap componentLogLevel
static bool logThreadFinished
void logStop(void)
Entry point for stopping logging for an application.
void loglevelAdd(int value, QString name, char shortname)
Add a log level to the logLevelMap.
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
QStringList logPropagateArgList
static QMutex logThreadTidMutex
LogPropagateOpts logPropagateOpts
static QMutex logQueueMutex
bool haveUserDefaultValues
static QMutex logThreadMutex
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
void resetLogging(void)
Intended for use only by the test harness.
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.
int syslogGetFacility(const QString &facility)
Map a syslog facility name back to the enumerated value.
void logPropagateCalc(void)
Generate the logPropagateArgs global with the latest logging level, mask, etc to propagate to all of ...
static bool debugRegistration
QString logStrerror(int errnum)
Verbose helper function for ENO macro.
static LoggerThread * logThread
static QQueue< LoggingItem * > logQueue
void logForwardMessage(LoggingItem *item)
bool logForwardStart(void)
void logForwardStop(void)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QMap< uint64_t, LogLevel_t > ComponentLogLevelMap
QMap< int, LoglevelDef * > LoglevelMap
QMap< QString, VerboseDef * > VerboseMap