summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qcore_mac.cpp
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2017-12-08 18:46:44 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2018-02-12 23:35:13 +0000
commit211791d01cf89bb75691f965d3a4ebc42c5ed8ee (patch)
tree6a85f8b7066144efb9dca3e73942265191aeb9d1 /src/corelib/kernel/qcore_mac.cpp
parentb2b32682a95401f863e2b71a553c1375136e2595 (diff)
Add support for Apple Unified Logging
If the OS supports it, we will now log to the Apple unified logging system in addition to the normal stderr output. These logs can be inspected via the Console application, or the 'log' command line tool. See https://developer.apple.com/documentation/os/logging [ChangeLog][QtCore] Apple Unified Logging is now supported on Apple platforms. Task-number: QTBUG-38156 Done-with: Jake Petroules <jake.petroules@qt.io> Change-Id: I2ab92bd192d5b98aaf77e41501ea7b1ca6ef2425 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qcore_mac.cpp')
-rw-r--r--src/corelib/kernel/qcore_mac.cpp95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/corelib/kernel/qcore_mac.cpp b/src/corelib/kernel/qcore_mac.cpp
index bfb3b2ff07..b5df0db232 100644
--- a/src/corelib/kernel/qcore_mac.cpp
+++ b/src/corelib/kernel/qcore_mac.cpp
@@ -39,6 +39,9 @@
#include <private/qcore_mac_p.h>
#include <new>
+
+#include "qhash.h"
+#include "qpair.h"
#include "qvarlengtharray.h"
QT_BEGIN_NAMESPACE
@@ -57,4 +60,96 @@ QCFString::operator CFStringRef() const
return value;
}
+// --------------------------------------------------------------------------
+
+#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
+
+bool AppleUnifiedLogger::messageHandler(QtMsgType msgType, const QMessageLogContext &context,
+ const QString &message, const QString &optionalSubsystem)
+{
+ QString subsystem = optionalSubsystem;
+ if (subsystem.isNull()) {
+ static QString bundleIdentifier = []() {
+ if (CFBundleRef bundle = CFBundleGetMainBundle()) {
+ if (CFStringRef identifier = CFBundleGetIdentifier(bundle))
+ return QString::fromCFString(identifier);
+ }
+ return QString();
+ }();
+ subsystem = bundleIdentifier;
+ }
+
+ const bool isDefault = !context.category || !strcmp(context.category, "default");
+ os_log_t log = isDefault ? OS_LOG_DEFAULT :
+ cachedLog(subsystem, QString::fromLatin1(context.category));
+ os_log_type_t logType = logTypeForMessageType(msgType);
+
+ if (!os_log_type_enabled(log, logType))
+ return false;
+
+ // Logging best practices says we should not include symbolication
+ // information or source file line numbers in messages, as the system
+ // will automatically captures this information. In our case, what
+ // the system captures is the call to os_log_with_type below, which
+ // isn't really useful, but we still don't want to include the context's
+ // info, as that would clutter the logging output. See rdar://35958308.
+
+ // The format must be a string constant, so we can't pass on the
+ // message. This means we won't be able to take advantage of the
+ // unified logging's custom format specifiers such as %{BOOL}d.
+ // We use the 'public' format specifier to prevent the logging
+ // system from redacting our log message.
+ os_log_with_type(log, logType, "%{public}s", qPrintable(message));
+
+ // When running under Xcode or LLDB, one or more of these variables will
+ // be set, which triggers libsystem_trace.dyld to log messages to stderr
+ // as well, via_os_log_impl_mirror_to_stderr. Un-setting these variables
+ // is not an option, as that would silence normal NSLog or os_log calls,
+ // so instead we skip our own stderr output. See rdar://36919139.
+ static bool mirroredToStderr = qEnvironmentVariableIsSet("OS_ACTIVITY_DT_MODE")
+ || qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
+ || qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
+ return mirroredToStderr;
+}
+
+os_log_type_t AppleUnifiedLogger::logTypeForMessageType(QtMsgType msgType)
+{
+ switch (msgType) {
+ case QtDebugMsg: return OS_LOG_TYPE_DEBUG;
+ case QtInfoMsg: return OS_LOG_TYPE_INFO;
+ case QtWarningMsg: return OS_LOG_TYPE_DEFAULT;
+ case QtCriticalMsg: return OS_LOG_TYPE_ERROR;
+ case QtFatalMsg: return OS_LOG_TYPE_FAULT;
+ }
+
+ return OS_LOG_TYPE_DEFAULT;
+}
+
+os_log_t AppleUnifiedLogger::cachedLog(const QString &subsystem, const QString &category)
+{
+ static QBasicMutex mutex;
+ QMutexLocker locker(&mutex);
+
+ static QHash<QPair<QString, QString>, os_log_t> logs;
+ const auto cacheKey = qMakePair(subsystem, category);
+ os_log_t log = logs.value(cacheKey);
+
+ if (!log) {
+ log = os_log_create(subsystem.toLatin1().constData(),
+ category.toLatin1().constData());
+ logs.insert(cacheKey, log);
+
+ // Technically we should release the os_log_t resource when done
+ // with it, but since we don't know when a category is disabled
+ // we keep all cached os_log_t instances until shutdown, where
+ // the OS will clean them up for us.
+ }
+
+ return log;
+}
+
+#endif // QT_USE_APPLE_UNIFIED_LOGGING
+
+// --------------------------------------------------------------------------
+
QT_END_NAMESPACE