2#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3#include <QtSystemDetection>
8#include <QWaitCondition>
15#include <QRegularExpression>
49#include <sys/syscall.h>
50#elif defined(Q_OS_FREEBSD)
52#include <sys/ucontext.h>
55#elif defined(Q_OS_DARWIN)
60#include <android/log.h>
108void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext);
109void loglevelAdd(
int value, QString name,
char shortname);
128 m_threadId((uint64_t)(QThread::currentThreadId())),
129 m_line(_line), m_type(_type), m_level(_level),
130 m_function(_function)
132 const char *slash = std::strrchr(_file,
'/');
133 m_file = (slash !=
nullptr) ? slash+1 : _file;
134 m_epoch = nowAsDuration<std::chrono::microseconds>();
142 static constexpr char const *kSUnknown =
"thread_unknown";
179 m_tid = (int64_t)gettid();
180#elif defined(Q_OS_LINUX)
181 m_tid = syscall(SYS_gettid);
182#elif defined(Q_OS_FREEBSD)
184 [[maybe_unused]]
int dummy = thr_self( &lwpid );
185 m_tid = (int64_t)lwpid;
186#elif defined(Q_OS_DARWIN)
187 m_tid = (int64_t)mach_thread_self();
196 QDateTime
epoch = QDateTime::fromMSecsSinceEpoch(
m_epoch.count()/1000);
197 QString timestamp =
epoch.toString(format);
204 timestamp += QString(
".%1").arg((
m_epoch % 1s).count(),6,10,QChar(
'0'));
214 return (*it)->shortname;
220 QString ptid = QString::number(
pid());
223 ptid.append(
"/").append(QString::number(
tid()));
225 return qPrintable(QString(
"%1 %2 [%3] %4 %5:%6:%7 %8\n")
231 QString::number(
line()),
239 return qPrintable(QString(
"%1 %2 %3\n")
250 int facility,
bool loglong) :
252 m_waitNotEmpty(new QWaitCondition()),
253 m_waitEmpty(new QWaitCondition()),
256 m_facility(facility), m_pid(getpid())
258 if (qEnvironmentVariableIsSet(
"VERBOSE_THREADS"))
260 LOG(VB_GENERAL, LOG_NOTICE,
261 "Logging thread registration/deregistration enabled!");
267 LOG(VB_GENERAL, LOG_ERR,
268 "Failed to start LogServer thread");
294 LOG(VB_GENERAL, LOG_INFO,
"Added logging to the console");
303 qApp->processEvents(QEventLoop::AllEvents, 10);
304 qApp->sendPostedEvents(
nullptr, QEvent::DeferredDelete);
335 qApp->processEvents();
355 item->
m_message = QString(
"Thread 0x%1 (%2) registered as \'%3\'")
357 QString::number(item->
m_tid),
379 item->
m_message = QString(
"Thread 0x%1 (%2) deregistered as \'%3\'")
381 QString::number(tid),
415#if !defined(NDEBUG) || CONFIG_FORCE_LOGLONG
429 std::cout << line << std::flush;
433 android_LogPriority aprio;
437 aprio = ANDROID_LOG_FATAL;
442 aprio = ANDROID_LOG_ERROR;
445 aprio = ANDROID_LOG_WARN;
449 aprio = ANDROID_LOG_INFO;
452 aprio = ANDROID_LOG_DEBUG;
456 aprio = ANDROID_LOG_UNKNOWN;
460 __android_log_print(aprio,
"mfe",
"%s:%d:%s %s", qPrintable(item->
m_file),
464 __android_log_print(aprio,
"mfe",
"%s", qPrintable(item->
m_message));
495 int left = timeoutMS -
t.elapsed();
523 const char *_function,
524 int _line, LogLevel_t _level,
527 auto *item =
new LoggingItem(_file, _function, _line, _level, _type);
541 const char *function, QString message)
555#if defined( _MSC_VER ) && defined( _DEBUG )
556 OutputDebugStringA( qPrintable(item->
m_message) );
557 OutputDebugStringA(
"\n" );
614#if !defined(Q_OS_WINDOWS) && !defined(Q_OS_ANDROID)
617 const CODE *syslogname =
nullptr;
618 for (syslogname = &facilitynames[0];
619 (syslogname->c_name &&
625#if CONFIG_SYSTEMD_JOURNAL
656 LogLevel_t level,
bool propagate,
bool loglong,
bool testHarness)
662 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Setting Log Level to LOG_%1")
672 QFileInfo finfo(logfile);
673 QString path = finfo.path();
747 LOG(VB_GENERAL, LOG_NOTICE,
748 "Windows does not support syslog, disabling" );
750#elif defined(Q_OS_ANDROID)
751 LOG(VB_GENERAL, LOG_NOTICE,
752 "Android does not support syslog, disabling" );
755 const CODE *name =
nullptr;
756 QByteArray ba = facility.toLocal8Bit();
757 char *
string = (
char *)ba.constData();
759 for (name = &facilitynames[0];
760 name->c_name && (strcmp(name->c_name,
string) != 0); name++);
762 return( name->c_val );
781 if ( item->name == level.toLower() )
782 return (LogLevel_t)item->value;
800 LoglevelMap::iterator it =
loglevelMap.find((
int)level);
814void verboseAdd(uint64_t mask, QString name,
bool additive, QString helptext)
821 name = name.toLower();
823 item->additive = additive;
824 item->helpText = std::move(helptext);
841 name = name.toLower();
843 item->shortname = shortname;
867#define MYTH_IMPLEMENT_VERBOSE
880 std::cerr <<
"Verbose debug levels.\n"
881 "Accepts any combination (separated by comma) of:\n\n";
883 for (VerboseMap::Iterator vit =
verboseMap.begin();
887 QString name = QString(
" %1").arg(item->
name, -15,
' ');
890 std::cerr << name.toLocal8Bit().constData() <<
" - "
891 << item->
helpText.toLocal8Bit().constData() << std::endl;
894 std::cerr << std::endl <<
895 "The default for this program appears to be: '-v " <<
896 m_verbose.toLocal8Bit().constData() <<
"'\n\n"
897 "Most options are additive except for 'none' and 'all'.\n"
898 "These two are semi-exclusive and take precedence over any\n"
899 "other options. However, you may use something like\n"
900 "'-v none,jobqueue' to receive only JobQueue related messages\n"
901 "and override the default verbosity level.\n\n"
902 "Additive options may also be subtracted from 'all' by\n"
903 "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
904 "to view all but database debug messages.\n\n";
907 <<
"The 'global' loglevel is specified with --loglevel, but can be\n"
908 <<
"overridden on a component by component basis by appending "
910 <<
"to the component.\n"
911 <<
" For example: -v gui:debug,channel:notice,record\n\n";
913 std::cerr <<
"Some debug levels may not apply to this program.\n" << std::endl;
931 if (arg.startsWith(
'-'))
933 std::cerr <<
"Invalid or missing argument to -v/--verbose option\n";
937 static const QRegularExpression kSeparatorRE {
"[^\\w:]+" };
938 QStringList verboseOpts = arg.split(kSeparatorRE, Qt::SkipEmptyParts);
939 for (
const auto& opt : std::as_const(verboseOpts))
941 option = opt.toLower();
942 bool reverseOption =
false;
945 if (option !=
"none" && option.startsWith(
"no"))
947 reverseOption =
true;
948 option = option.right(option.length() - 2);
951 if (option ==
"help")
956 if (option ==
"important")
958 std::cerr <<
"The \"important\" log mask is no longer valid.\n";
960 else if (option ==
"extra")
962 std::cerr <<
"The \"extra\" log mask is no longer valid. Please try "
963 "--loglevel debug instead.\n";
965 else if (option ==
"default")
980 int idx = option.indexOf(
':');
983 optionLevel = option.mid(idx + 1);
984 option = option.left(idx);
1013 if (!optionLevel.isEmpty())
1016 if (level != LOG_UNKNOWN)
1023 std::cerr <<
"Unknown argument for -v/--verbose: " <<
1024 option.toLocal8Bit().constData() << std::endl;;
1046 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