From 9c30903eb67e6339da4038c145e2b860838b99cc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 12:05:56 -0700 Subject: [PATCH 01/10] add the VerboseLoggingHelper class for repeated messages --- libraries/shared/src/VerboseLoggingHelper.cpp | 34 ++++++++++++++++++ libraries/shared/src/VerboseLoggingHelper.h | 36 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 libraries/shared/src/VerboseLoggingHelper.cpp create mode 100644 libraries/shared/src/VerboseLoggingHelper.h diff --git a/libraries/shared/src/VerboseLoggingHelper.cpp b/libraries/shared/src/VerboseLoggingHelper.cpp new file mode 100644 index 0000000000..6fa3f8a5a5 --- /dev/null +++ b/libraries/shared/src/VerboseLoggingHelper.cpp @@ -0,0 +1,34 @@ +// +// VerboseLoggingHelper.cpp +// libraries/shared/src +// +// Created by Stephen Birarda on 2014-10-28. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "VerboseLoggingHelper.h" + +VerboseLoggingHelper& VerboseLoggingHelper::getInstance() { + static VerboseLoggingHelper sharedInstance; + return sharedInstance; +} + +VerboseLoggingHelper::VerboseLoggingHelper() { + // setup our timer to flush the verbose logs every 5 seconds + _timer = new QTimer(this); + connect(_timer, &QTimer::timeout, this, &VerboseLoggingHelper::flushMessages); + _timer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); +} + +void VerboseLoggingHelper::flushMessages() { + QHash::iterator message = _messageCountHash.begin(); + while (message != _messageCountHash.end()) { + qDebug() << message.key().arg(message.value()); + message = _messageCountHash.erase(message); + } +} \ No newline at end of file diff --git a/libraries/shared/src/VerboseLoggingHelper.h b/libraries/shared/src/VerboseLoggingHelper.h new file mode 100644 index 0000000000..368dfa51e6 --- /dev/null +++ b/libraries/shared/src/VerboseLoggingHelper.h @@ -0,0 +1,36 @@ +// +// VerboseLoggingHelper.h +// libraries/shared/src +// +// Created by Stephen Birarda on 2014-10-28. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_VerboseLoggingHelper_h +#define hifi_VerboseLoggingHelper_h + +#include +#include +#include + +const int VERBOSE_LOG_INTERVAL_SECONDS = 5; + +class VerboseLoggingHelper : public QObject { + Q_OBJECT +public: + static VerboseLoggingHelper& getInstance(); + + void addMessage(const QString& message) { _messageCountHash[message] += 1; } +private: + VerboseLoggingHelper(); + + void flushMessages(); + + QTimer* _timer; + QHash _messageCountHash; +}; + +#endif // hifi_VerboseLoggingHelper_h \ No newline at end of file From 8a4c716452ae0c1dd95468ffe0eafff1ee4d83a1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 12:15:52 -0700 Subject: [PATCH 02/10] leverage the VerboseLoggingHelper for packets from unknown nodes --- libraries/networking/src/LimitedNodeList.cpp | 8 ++++++-- libraries/shared/src/VerboseLoggingHelper.cpp | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 919dc75c23..93f50b2824 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -19,6 +19,8 @@ #include #include +#include + #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" @@ -211,8 +213,10 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { << uuidFromPacketHeader(packet); } } else { - qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" - << uuidFromPacketHeader(packet); + QString unknownPacketString = "%1 packets of type " + QString::number(checkType) + + " received from unknown node with UUID " + + uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); + VerboseLoggingHelper::getInstance().addMessage(unknownPacketString); } } else { return true; diff --git a/libraries/shared/src/VerboseLoggingHelper.cpp b/libraries/shared/src/VerboseLoggingHelper.cpp index 6fa3f8a5a5..ae014f425d 100644 --- a/libraries/shared/src/VerboseLoggingHelper.cpp +++ b/libraries/shared/src/VerboseLoggingHelper.cpp @@ -28,7 +28,8 @@ VerboseLoggingHelper::VerboseLoggingHelper() { void VerboseLoggingHelper::flushMessages() { QHash::iterator message = _messageCountHash.begin(); while (message != _messageCountHash.end()) { - qDebug() << message.key().arg(message.value()); + qDebug() << qPrintable(message.key().arg(message.value())) + << "in last" << VERBOSE_LOG_INTERVAL_SECONDS << "seconds."; message = _messageCountHash.erase(message); } } \ No newline at end of file From 2711ff2b5f9e895888ce1a65779f82846be29f53 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 13:48:53 -0700 Subject: [PATCH 03/10] move functionality from VerboseLoggingHelper into the Logging class --- interface/src/Application.cpp | 4 -- libraries/networking/src/LimitedNodeList.cpp | 8 +-- libraries/networking/src/Logging.cpp | 69 +++++-------------- libraries/networking/src/Logging.h | 41 +++++------ libraries/shared/src/VerboseLoggingHelper.cpp | 35 ---------- libraries/shared/src/VerboseLoggingHelper.h | 36 ---------- 6 files changed, 38 insertions(+), 155 deletions(-) delete mode 100644 libraries/shared/src/VerboseLoggingHelper.cpp delete mode 100644 libraries/shared/src/VerboseLoggingHelper.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 140e51ee3e..f0bd2fb66c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -581,10 +581,6 @@ void Application::initializeGL() { float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0; _justStarted = false; qDebug("Startup time: %4.2f seconds.", startupTime); - const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; - - // ask the Logstash class to record the startup time - Logging::stashValue(STAT_TYPE_TIMER, LOGSTASH_INTERFACE_START_TIME_KEY, startupTime); } // update before the first render diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 93f50b2824..46ab4f4b0b 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -19,8 +19,6 @@ #include #include -#include - #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" @@ -213,10 +211,8 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { << uuidFromPacketHeader(packet); } } else { - QString unknownPacketString = "%1 packets of type " + QString::number(checkType) - + " received from unknown node with UUID " - + uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); - VerboseLoggingHelper::getInstance().addMessage(unknownPacketString); + qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" + << uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); } } else { return true; diff --git a/libraries/networking/src/Logging.cpp b/libraries/networking/src/Logging.cpp index f42f1bda58..bb704729af 100644 --- a/libraries/networking/src/Logging.cpp +++ b/libraries/networking/src/Logging.cpp @@ -9,12 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include -//#include // not available on windows, apparently not needed on mac - #ifdef _WIN32 #include #define getpid _getpid @@ -22,55 +16,22 @@ #define pid_t int // hack to build #endif -#include - -#include "HifiSockAddr.h" -#include "SharedUtil.h" -#include "NodeList.h" +#include #include "Logging.h" -HifiSockAddr Logging::_logstashSocket = HifiSockAddr(); QString Logging::_targetName = QString(); -const HifiSockAddr& Logging::socket() { - - if (_logstashSocket.getAddress().isNull()) { - // we need to construct the socket object - // use the constant port - _logstashSocket.setPort(htons(LOGSTASH_UDP_PORT)); - - // lookup the IP address for the constant hostname - QHostInfo hostInfo = QHostInfo::fromName(LOGSTASH_HOSTNAME); - if (!hostInfo.addresses().isEmpty()) { - // use the first IP address - _logstashSocket.setAddress(hostInfo.addresses().first()); - } else { - qDebug("Failed to lookup logstash IP - will try again on next log attempt."); - } - } - - return _logstashSocket; +Logging& Logging::getInstance() { + static Logging staticInstance; + return staticInstance; } -bool Logging::shouldSendStats() { - static bool shouldSendStats = isInEnvironment("production"); - return shouldSendStats; -} - -void Logging::stashValue(char statType, const char* key, float value) { - static char logstashPacket[MAX_PACKET_SIZE]; - - // load up the logstash packet with the key and the passed float value - // send it to 4 decimal places - int numPacketBytes = sprintf(logstashPacket, "%c %s %.4f", statType, key, value); - - NodeList *nodeList = NodeList::getInstance(); - - if (nodeList) { - nodeList->getNodeSocket().writeDatagram(logstashPacket, numPacketBytes, - _logstashSocket.getAddress(), _logstashSocket.getPort()); - } +Logging::Logging() { + // setup our timer to flush the verbose logs every 5 seconds + QTimer* logFlushTimer = new QTimer(this); + connect(logFlushTimer, &QTimer::timeout, this, &Logging::flushRepeatedMessages); + logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); } const char* stringForLogType(QtMsgType msgType) { @@ -95,6 +56,7 @@ void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& co if (message.isEmpty()) { return; } + // log prefix is in the following format // [DEBUG] [TIMESTAMP] [PID:PARENT_PID] [TARGET] logged string @@ -118,9 +80,16 @@ void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& co prefixString.append("]"); } - if (!_targetName.isEmpty()) { - prefixString.append(QString(" [%1]").arg(_targetName)); + if (!getInstance()._targetName.isEmpty()) { + prefixString.append(QString(" [%1]").arg(getInstance()._targetName)); } fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData()); } + +void Logging::flushRepeatedMessages() { + QHash::iterator message = _repeatMessageCountHash.begin(); + while (message != _repeatMessageCountHash.end()) { + message = _repeatMessageCountHash.erase(message); + } +} diff --git a/libraries/networking/src/Logging.h b/libraries/networking/src/Logging.h index c52812bd33..458cbf90e8 100644 --- a/libraries/networking/src/Logging.h +++ b/libraries/networking/src/Logging.h @@ -12,33 +12,18 @@ #ifndef hifi_Logging_h #define hifi_Logging_h -#include +#include +#include +#include +#include +#include -const int LOGSTASH_UDP_PORT = 9500; -const char LOGSTASH_HOSTNAME[] = "graphite.highfidelity.io"; - -const char STAT_TYPE_TIMER = 't'; -const char STAT_TYPE_COUNTER = 'c'; -const char STAT_TYPE_GAUGE = 'g'; - -class HifiSockAddr; +const int VERBOSE_LOG_INTERVAL_SECONDS = 5; /// Handles custom message handling and sending of stats/logs to Logstash instance -class Logging { +class Logging : public QObject { + Q_OBJECT public: - /// \return the socket used to send stats to logstash - static const HifiSockAddr& socket(); - - /// checks if this target should send stats to logstash, given its current environment - /// \return true if the caller should send stats to logstash - static bool shouldSendStats(); - - /// stashes a float value to Logstash instance - /// \param statType a stat type from the constants in this file - /// \param key the key at which to store the stat - /// \param value the value to store - static void stashValue(char statType, const char* key, float value); - /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs static void setTargetName(const QString& targetName) { _targetName = targetName; } @@ -46,9 +31,17 @@ public: /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); + + static void addRepeatedMessageRegex(const QRegExp& regex) { getInstance()._repeatedMessageRegexes.append(regex); } private: - static HifiSockAddr _logstashSocket; + static Logging& getInstance(); + Logging(); + + void flushRepeatedMessages(); + static QString _targetName; + QList _repeatedMessageRegexes; + QHash _repeatMessageCountHash; }; #endif // hifi_Logging_h diff --git a/libraries/shared/src/VerboseLoggingHelper.cpp b/libraries/shared/src/VerboseLoggingHelper.cpp deleted file mode 100644 index ae014f425d..0000000000 --- a/libraries/shared/src/VerboseLoggingHelper.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// VerboseLoggingHelper.cpp -// libraries/shared/src -// -// Created by Stephen Birarda on 2014-10-28. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include "VerboseLoggingHelper.h" - -VerboseLoggingHelper& VerboseLoggingHelper::getInstance() { - static VerboseLoggingHelper sharedInstance; - return sharedInstance; -} - -VerboseLoggingHelper::VerboseLoggingHelper() { - // setup our timer to flush the verbose logs every 5 seconds - _timer = new QTimer(this); - connect(_timer, &QTimer::timeout, this, &VerboseLoggingHelper::flushMessages); - _timer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); -} - -void VerboseLoggingHelper::flushMessages() { - QHash::iterator message = _messageCountHash.begin(); - while (message != _messageCountHash.end()) { - qDebug() << qPrintable(message.key().arg(message.value())) - << "in last" << VERBOSE_LOG_INTERVAL_SECONDS << "seconds."; - message = _messageCountHash.erase(message); - } -} \ No newline at end of file diff --git a/libraries/shared/src/VerboseLoggingHelper.h b/libraries/shared/src/VerboseLoggingHelper.h deleted file mode 100644 index 368dfa51e6..0000000000 --- a/libraries/shared/src/VerboseLoggingHelper.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// VerboseLoggingHelper.h -// libraries/shared/src -// -// Created by Stephen Birarda on 2014-10-28. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_VerboseLoggingHelper_h -#define hifi_VerboseLoggingHelper_h - -#include -#include -#include - -const int VERBOSE_LOG_INTERVAL_SECONDS = 5; - -class VerboseLoggingHelper : public QObject { - Q_OBJECT -public: - static VerboseLoggingHelper& getInstance(); - - void addMessage(const QString& message) { _messageCountHash[message] += 1; } -private: - VerboseLoggingHelper(); - - void flushMessages(); - - QTimer* _timer; - QHash _messageCountHash; -}; - -#endif // hifi_VerboseLoggingHelper_h \ No newline at end of file From d3bbd251db27cc517002d41fbd6fe4c5debfd243 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 13:59:23 -0700 Subject: [PATCH 04/10] move Logging to LogHandler --- assignment-client/src/AssignmentClient.cpp | 6 +-- .../src/AssignmentClientMonitor.cpp | 4 +- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- assignment-client/src/main.cpp | 4 +- assignment-client/src/octree/OctreeServer.cpp | 4 +- domain-server/src/main.cpp | 4 +- ice-server/src/main.cpp | 4 +- interface/src/Application.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 3 +- libraries/networking/src/NodeList.cpp | 3 +- .../networking/src/ThreadedAssignment.cpp | 5 ++- .../Logging.cpp => shared/src/LogHandler.cpp} | 41 ++++++++++--------- .../src/Logging.h => shared/src/LogHandler.h} | 30 +++++++------- 14 files changed, 60 insertions(+), 54 deletions(-) rename libraries/{networking/src/Logging.cpp => shared/src/LogHandler.cpp} (78%) rename libraries/{networking/src/Logging.h => shared/src/LogHandler.h} (63%) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index b30cd355d1..e7ac7577b9 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -51,7 +51,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit())); // set the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); + LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); @@ -218,7 +218,7 @@ void AssignmentClient::handleAuthenticationRequest() { void AssignmentClient::assignmentCompleted() { // reset the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); + LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); qDebug("Assignment finished or never started - waiting for new assignment."); diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index af09ff1535..02a4ff04f0 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include "AssignmentClientMonitor.h" @@ -21,7 +21,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int num QCoreApplication(argc, argv) { // start the Logging class with the parent's target name - Logging::setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); + LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); _childArguments = arguments(); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8d87638434..cc834798d7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include #include diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 93f38e3608..3ec7c5cfbf 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 5e103cf767..3bf6990a74 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include #include "Assignment.h" @@ -22,7 +22,7 @@ int main(int argc, char* argv[]) { #endif // use the verbose message handler in Logging - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index d0a17287cb..121cac0273 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include "../AssignmentClient.h" @@ -923,7 +923,7 @@ void OctreeServer::run() { beforeRun(); // after payload has been processed - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); const char* STATUS_PORT = "--statusPort"; const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT); diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 82e4bf7cab..ba80e6fce0 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -17,7 +17,7 @@ #include -#include +#include #include #include "DomainServer.h" @@ -27,7 +27,7 @@ int main(int argc, char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); #endif - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); int currentExitCode = 0; diff --git a/ice-server/src/main.cpp b/ice-server/src/main.cpp index 21c8b563b1..2326984668 100644 --- a/ice-server/src/main.cpp +++ b/ice-server/src/main.cpp @@ -11,7 +11,7 @@ #include -#include +#include #include "IceServer.h" @@ -20,7 +20,7 @@ int main(int argc, char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); #endif - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); IceServer iceServer(argc, argv); return iceServer.exec(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0bd2fb66c..e1088136c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 46ab4f4b0b..48a94e5444 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -19,10 +19,11 @@ #include #include +#include + #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" -#include "Logging.h" #include "LimitedNodeList.h" #include "PacketHeaders.h" #include "SharedUtil.h" diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index feeb13500a..ff3b86880d 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -15,10 +15,11 @@ #include #include +#include + #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" -#include "Logging.h" #include "NodeList.h" #include "PacketHeaders.h" #include "SharedUtil.h" diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 6d2e366499..52644a9a4e 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -14,7 +14,8 @@ #include #include -#include "Logging.h" +#include + #include "ThreadedAssignment.h" ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : @@ -54,7 +55,7 @@ void ThreadedAssignment::setFinished(bool isFinished) { void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running - Logging::setTargetName(targetName); + LogHandler::getInstance().setTargetName(targetName); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(nodeType); diff --git a/libraries/networking/src/Logging.cpp b/libraries/shared/src/LogHandler.cpp similarity index 78% rename from libraries/networking/src/Logging.cpp rename to libraries/shared/src/LogHandler.cpp index bb704729af..123b418562 100644 --- a/libraries/networking/src/Logging.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -1,9 +1,10 @@ // -// Logging.cpp -// libraries/networking/src +// LogHandler.cpp +// libraries/shared/src // -// Created by Stephen Birarda on 6/11/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Stephen Birarda on 2014-10-28. +// Migrated from Logging.cpp created on 6/11/13 +// Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -18,19 +19,17 @@ #include -#include "Logging.h" +#include "LogHandler.h" -QString Logging::_targetName = QString(); - -Logging& Logging::getInstance() { - static Logging staticInstance; +LogHandler& LogHandler::getInstance() { + static LogHandler staticInstance; return staticInstance; } -Logging::Logging() { +LogHandler::LogHandler() { // setup our timer to flush the verbose logs every 5 seconds QTimer* logFlushTimer = new QTimer(this); - connect(logFlushTimer, &QTimer::timeout, this, &Logging::flushRepeatedMessages); + connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages); logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); } @@ -52,34 +51,34 @@ const char* stringForLogType(QtMsgType msgType) { // the following will produce 2000-10-02 13:55:36 -0700 const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; -void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { +void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (message.isEmpty()) { return; } // log prefix is in the following format // [DEBUG] [TIMESTAMP] [PID:PARENT_PID] [TARGET] logged string - + QString prefixString = QString("[%1]").arg(stringForLogType(type)); - + time_t rawTime; time(&rawTime); struct tm* localTime = localtime(&rawTime); - + char dateString[100]; strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime); - + prefixString.append(QString(" [%1]").arg(dateString)); - + prefixString.append(QString(" [%1").arg(getpid())); - + pid_t parentProcessID = getppid(); if (parentProcessID != 0) { prefixString.append(QString(":%1]").arg(parentProcessID)); } else { prefixString.append("]"); } - + if (!getInstance()._targetName.isEmpty()) { prefixString.append(QString(" [%1]").arg(getInstance()._targetName)); } @@ -87,9 +86,11 @@ void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& co fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData()); } -void Logging::flushRepeatedMessages() { +void LogHandler::flushRepeatedMessages() { QHash::iterator message = _repeatMessageCountHash.begin(); while (message != _repeatMessageCountHash.end()) { message = _repeatMessageCountHash.erase(message); } } + + diff --git a/libraries/networking/src/Logging.h b/libraries/shared/src/LogHandler.h similarity index 63% rename from libraries/networking/src/Logging.h rename to libraries/shared/src/LogHandler.h index 458cbf90e8..e89a739c6a 100644 --- a/libraries/networking/src/Logging.h +++ b/libraries/shared/src/LogHandler.h @@ -1,16 +1,17 @@ // -// Logging.h -// libraries/networking/src +// LogHandler.cpp +// libraries/shared/src // -// Created by Stephen Birarda on 6/11/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Stephen Birarda on 2014-10-28. +// Migrated from Logging.cpp created on 6/11/13 +// Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_Logging_h -#define hifi_Logging_h +#ifndef hifi_LogHandler_h +#define hifi_LogHandler_h #include #include @@ -21,27 +22,28 @@ const int VERBOSE_LOG_INTERVAL_SECONDS = 5; /// Handles custom message handling and sending of stats/logs to Logstash instance -class Logging : public QObject { +class LogHandler : public QObject { Q_OBJECT public: + static LogHandler& getInstance(); + /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs - static void setTargetName(const QString& targetName) { _targetName = targetName; } - + void setTargetName(const QString& targetName) { _targetName = targetName; } + /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); - static void addRepeatedMessageRegex(const QRegExp& regex) { getInstance()._repeatedMessageRegexes.append(regex); } + void addRepeatedMessageRegex(const QRegExp& regex) { _repeatedMessageRegexes.append(regex); } private: - static Logging& getInstance(); - Logging(); + LogHandler(); void flushRepeatedMessages(); - static QString _targetName; + QString _targetName; QList _repeatedMessageRegexes; QHash _repeatMessageCountHash; }; -#endif // hifi_Logging_h +#endif // hifi_LogHandler_h \ No newline at end of file From 8e3102266a587897c5f35f3bafc19d938c2e00a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 14:23:34 -0700 Subject: [PATCH 05/10] use the LogHandler in Interface --- interface/src/Application.cpp | 10 ++- libraries/networking/src/LimitedNodeList.cpp | 3 + libraries/shared/src/LogHandler.cpp | 66 ++++++++++++++------ libraries/shared/src/LogHandler.h | 10 ++- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e1088136c4..16d8062303 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -116,12 +116,10 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js"; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - if (message.size() > 0) { - QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate); - QString formattedMessage = QString("[%1] %2\n").arg(dateString).arg(message); - - fprintf(stdout, "%s", qPrintable(formattedMessage)); - Application::getInstance()->getLogger()->addMessage(qPrintable(formattedMessage)); + QString logMessage = LogHandler::getInstance().printMessage(type, context, message); + + if (!logMessage.isEmpty()) { + Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage)); } } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 48a94e5444..600427a733 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -212,6 +212,9 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { << uuidFromPacketHeader(packet); } } else { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID"); + qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); } diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 123b418562..078cdf5ab6 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -17,6 +17,7 @@ #define pid_t int // hack to build #endif +#include #include #include "LogHandler.h" @@ -26,7 +27,9 @@ LogHandler& LogHandler::getInstance() { return staticInstance; } -LogHandler::LogHandler() { +LogHandler::LogHandler() : + _shouldOutputPID(false) +{ // setup our timer to flush the verbose logs every 5 seconds QTimer* logFlushTimer = new QTimer(this); connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages); @@ -51,9 +54,33 @@ const char* stringForLogType(QtMsgType msgType) { // the following will produce 2000-10-02 13:55:36 -0700 const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; -void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { +void LogHandler::flushRepeatedMessages() { + QHash::iterator message = _repeatMessageCountHash.begin(); + while (message != _repeatMessageCountHash.end()) { + message = _repeatMessageCountHash.erase(message); + } +} + +QString LogHandler::printMessage(QtMsgType type, const QMessageLogContext& context, const QString& message) { + if (message.isEmpty()) { - return; + return QString(); + } + + if (type == QtDebugMsg) { + // for debug messages, check if this matches any of our regexes for repeated log messages + foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) { + QRegExp repeatRegex(regexString); + if (repeatRegex.indexIn(message) != -1) { + + // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message + _repeatMessageCountHash[regexString] += 1; + _lastRepeatedMessage[regexString] = message; + + // return out, we're not printing this one + return QString(); + } + } } // log prefix is in the following format @@ -70,27 +97,26 @@ void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& prefixString.append(QString(" [%1]").arg(dateString)); - prefixString.append(QString(" [%1").arg(getpid())); - - pid_t parentProcessID = getppid(); - if (parentProcessID != 0) { - prefixString.append(QString(":%1]").arg(parentProcessID)); - } else { - prefixString.append("]"); + if (_shouldOutputPID) { + prefixString.append(QString(" [%1").arg(getpid())); + + pid_t parentProcessID = getppid(); + if (parentProcessID != 0) { + prefixString.append(QString(":%1]").arg(parentProcessID)); + } else { + prefixString.append("]"); + } } - if (!getInstance()._targetName.isEmpty()) { - prefixString.append(QString(" [%1]").arg(getInstance()._targetName)); + if (!_targetName.isEmpty()) { + prefixString.append(QString(" [%1]").arg(_targetName)); } - fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData()); + QString logMessage = QString("%1 %2").arg(prefixString, message); + fprintf(stdout, "%s\n", qPrintable(logMessage)); + return logMessage; } -void LogHandler::flushRepeatedMessages() { - QHash::iterator message = _repeatMessageCountHash.begin(); - while (message != _repeatMessageCountHash.end()) { - message = _repeatMessageCountHash.erase(message); - } +void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + getInstance().printMessage(type, context, message); } - - diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index e89a739c6a..abc39b7040 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -31,19 +31,25 @@ public: /// \param targetName the desired target name to output in logs void setTargetName(const QString& targetName) { _targetName = targetName; } + void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; } + + QString printMessage(QtMsgType type, const QMessageLogContext& context, const QString &message); + /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); - void addRepeatedMessageRegex(const QRegExp& regex) { _repeatedMessageRegexes.append(regex); } + const QString& addRepeatedMessageRegex(const QString& regexString) { return *_repeatedMessageRegexes.insert(regexString); } private: LogHandler(); void flushRepeatedMessages(); QString _targetName; - QList _repeatedMessageRegexes; + bool _shouldOutputPID; + QSet _repeatedMessageRegexes; QHash _repeatMessageCountHash; + QHash _lastRepeatedMessage; }; #endif // hifi_LogHandler_h \ No newline at end of file From 424793b90515a759cd9fd9b5223bd194867e1db4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 14:49:14 -0700 Subject: [PATCH 06/10] complete output of suppressed repeated messages to log --- interface/src/Application.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/shared/src/LogHandler.cpp | 17 +++++++++++++---- libraries/shared/src/LogHandler.h | 10 +++++++++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 16d8062303..141ba20416 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -116,7 +116,7 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js"; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage(type, context, message); + QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); if (!logMessage.isEmpty()) { Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage)); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 600427a733..5c4dc6cea2 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -216,7 +216,7 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID"); qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" - << uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); + << qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet))); } } else { return true; diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 078cdf5ab6..aa377b5683 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -36,7 +36,7 @@ LogHandler::LogHandler() : logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); } -const char* stringForLogType(QtMsgType msgType) { +const char* stringForLogType(LogMsgType msgType) { switch (msgType) { case QtDebugMsg: return "DEBUG"; @@ -46,6 +46,8 @@ const char* stringForLogType(QtMsgType msgType) { return "FATAL"; case QtWarningMsg: return "WARNING"; + case LogSuppressed: + return "SUPPRESS"; default: return "UNKNOWN"; } @@ -57,17 +59,24 @@ const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; void LogHandler::flushRepeatedMessages() { QHash::iterator message = _repeatMessageCountHash.begin(); while (message != _repeatMessageCountHash.end()) { + QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") + .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key())); + + QMessageLogContext emptyContext; + printMessage(LogSuppressed, emptyContext, repeatMessage); + + _lastRepeatedMessage.remove(message.key()); message = _repeatMessageCountHash.erase(message); } } -QString LogHandler::printMessage(QtMsgType type, const QMessageLogContext& context, const QString& message) { +QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) { if (message.isEmpty()) { return QString(); } - if (type == QtDebugMsg) { + if (type == LogDebug) { // for debug messages, check if this matches any of our regexes for repeated log messages foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) { QRegExp repeatRegex(regexString); @@ -118,5 +127,5 @@ QString LogHandler::printMessage(QtMsgType type, const QMessageLogContext& conte } void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - getInstance().printMessage(type, context, message); + getInstance().printMessage((LogMsgType) type, context, message); } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index abc39b7040..f8f06b0033 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -21,6 +21,14 @@ const int VERBOSE_LOG_INTERVAL_SECONDS = 5; +enum LogMsgType { + LogDebug, + LogWarning, + LogCritical, + LogFatal, + LogSuppressed +}; + /// Handles custom message handling and sending of stats/logs to Logstash instance class LogHandler : public QObject { Q_OBJECT @@ -33,7 +41,7 @@ public: void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; } - QString printMessage(QtMsgType type, const QMessageLogContext& context, const QString &message); + QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message); /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information From c4538836c16918ab05d3d558e7d3a30105bc74bb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 14:51:47 -0700 Subject: [PATCH 07/10] always output the first matching repeated log message --- libraries/shared/src/LogHandler.cpp | 31 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index aa377b5683..9a081e429d 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -59,11 +59,14 @@ const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; void LogHandler::flushRepeatedMessages() { QHash::iterator message = _repeatMessageCountHash.begin(); while (message != _repeatMessageCountHash.end()) { - QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") - .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key())); - QMessageLogContext emptyContext; - printMessage(LogSuppressed, emptyContext, repeatMessage); + if (message.value() > 0) { + QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") + .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key())); + + QMessageLogContext emptyContext; + printMessage(LogSuppressed, emptyContext, repeatMessage); + } _lastRepeatedMessage.remove(message.key()); message = _repeatMessageCountHash.erase(message); @@ -82,12 +85,20 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont QRegExp repeatRegex(regexString); if (repeatRegex.indexIn(message) != -1) { - // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message - _repeatMessageCountHash[regexString] += 1; - _lastRepeatedMessage[regexString] = message; - - // return out, we're not printing this one - return QString(); + if (!_repeatMessageCountHash.contains(regexString)) { + // we have a match but didn't have this yet - output the first one + _repeatMessageCountHash[regexString] = 0; + + // break the foreach so we output the first match + break; + } else { + // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message + _repeatMessageCountHash[regexString] += 1; + _lastRepeatedMessage[regexString] = message; + + // return out, we're not printing this one + return QString(); + } } } } From 01de6305e943828588fd6d74b7b135122634b3fa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:42:03 -0700 Subject: [PATCH 08/10] add time header for date in log entry --- libraries/shared/src/LogHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 9a081e429d..7b06b77ae8 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -10,6 +10,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #ifdef _WIN32 #include #define getpid _getpid From 992396ba63da824065072ecc2877d0578aadf186 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:48:06 -0700 Subject: [PATCH 09/10] add ctime for strftime call --- libraries/shared/src/LogHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 7b06b77ae8..88afba8c07 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -11,6 +11,7 @@ // #include +#include #ifdef _WIN32 #include From 9af097967ddd8e4fee8fcb59b21bd455eb1abd9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:56:30 -0700 Subject: [PATCH 10/10] remove ctime since windows build did not fail without it --- libraries/shared/src/LogHandler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 88afba8c07..7b06b77ae8 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -11,7 +11,6 @@ // #include -#include #ifdef _WIN32 #include