diff --git a/README.md b/README.md index 98fb2ed..a6806eb 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ The package will deliver a default configuration file with following content (`/ name=nymea-remoteproxy writeLogs=false logFile=/var/log/nymea-remoteproxy.log + logEngineEnabled=false monitorSocket=/tmp/nymea-remoteproxy-monitor.sock jsonRpcTimeout=10000 authenticationTimeout=8000 diff --git a/libnymea-remoteproxy/engine.cpp b/libnymea-remoteproxy/engine.cpp index a5cec58..065f848 100644 --- a/libnymea-remoteproxy/engine.cpp +++ b/libnymea-remoteproxy/engine.cpp @@ -83,6 +83,9 @@ void Engine::start(ProxyConfiguration *configuration) m_monitorServer = new MonitorServer(configuration->monitorSocketFileName(), this); m_monitorServer->startServer(); + if (configuration->logEngineEnabled()) + m_logEngine->enable(); + // Set running true in the next event loop QMetaObject::invokeMethod(this, QString("setRunning").toLatin1().data(), Qt::QueuedConnection, Q_ARG(bool, true)); } @@ -154,6 +157,11 @@ MonitorServer *Engine::monitorServer() const return m_monitorServer; } +LogEngine *Engine::logEngine() const +{ + return m_logEngine; +} + Engine::Engine(QObject *parent) : QObject(parent) { @@ -164,6 +172,8 @@ Engine::Engine(QObject *parent) : m_timer->setInterval(50); connect(m_timer, &QTimer::timeout, this, &Engine::onTimerTick); + + m_logEngine = new LogEngine(this); } Engine::~Engine() @@ -191,7 +201,13 @@ void Engine::onTimerTick() if (m_currentTimeCounter >= 1000) { // One second passed, do second tick m_proxyServer->tick(); - m_monitorServer->updateClients(createServerStatistic()); + + QVariantMap serverStatistics = createServerStatistic(); + m_monitorServer->updateClients(serverStatistics); + m_logEngine->logStatistics(serverStatistics.value("proxyStatistic").toMap().value("tunnelCount").toInt(), + serverStatistics.value("proxyStatistic").toMap().value("clientCount").toInt(), + serverStatistics.value("proxyStatistic").toMap().value("troughput").toInt()); + m_currentTimeCounter = 0; } } diff --git a/libnymea-remoteproxy/engine.h b/libnymea-remoteproxy/engine.h index d6d19fe..fc9632c 100644 --- a/libnymea-remoteproxy/engine.h +++ b/libnymea-remoteproxy/engine.h @@ -29,6 +29,7 @@ #include #include +#include "logengine.h" #include "proxyserver.h" #include "monitorserver.h" #include "websocketserver.h" @@ -62,6 +63,8 @@ public: ProxyServer *proxyServer() const; WebSocketServer *webSocketServer() const; MonitorServer *monitorServer() const; + LogEngine *logEngine() const; + private: explicit Engine(QObject *parent = nullptr); @@ -81,6 +84,7 @@ private: ProxyServer *m_proxyServer = nullptr; WebSocketServer *m_webSocketServer = nullptr; MonitorServer *m_monitorServer = nullptr; + LogEngine *m_logEngine = nullptr; QVariantMap createServerStatistic(); diff --git a/libnymea-remoteproxy/libnymea-remoteproxy.pro b/libnymea-remoteproxy/libnymea-remoteproxy.pro index ccb3913..c560aff 100644 --- a/libnymea-remoteproxy/libnymea-remoteproxy.pro +++ b/libnymea-remoteproxy/libnymea-remoteproxy.pro @@ -25,7 +25,8 @@ HEADERS += \ authentication/aws/userinformation.h \ authentication/aws/authenticationprocess.h \ authentication/aws/sigv4utils.h \ - authentication/aws/awscredentialprovider.h + authentication/aws/awscredentialprovider.h \ + logengine.h SOURCES += \ engine.cpp \ @@ -49,7 +50,8 @@ SOURCES += \ authentication/aws/userinformation.cpp \ authentication/aws/authenticationprocess.cpp \ authentication/aws/sigv4utils.cpp \ - authentication/aws/awscredentialprovider.cpp + authentication/aws/awscredentialprovider.cpp \ + logengine.cpp # install header file with relative subdirectory diff --git a/libnymea-remoteproxy/logengine.cpp b/libnymea-remoteproxy/logengine.cpp new file mode 100644 index 0000000..8a3dfdd --- /dev/null +++ b/libnymea-remoteproxy/logengine.cpp @@ -0,0 +1,148 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2018 Simon Stürz * + * * + * This file is part of nymea-remoteproxy. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "logengine.h" +#include "loggingcategories.h" + +#include + +namespace remoteproxy { + +LogEngine::LogEngine(QObject *parent) : QObject(parent) +{ + m_currentDay = QDateTime::currentDateTime().date().day(); + m_tunnelsFileName = "/var/log/nymea-remoteproxy-tunnels"; + m_statisticsFileName = "/var/log/nymea-remoteproxy-statistics"; +} + +LogEngine::~LogEngine() +{ + disable(); +} + +void LogEngine::logTunnel(const TunnelConnection &tunnel) +{ + if (!m_tunnelsFile.isOpen()) + return; + + // + + QStringList logString; + logString << createTimestamp(); + logString << QString::number(tunnel.creationTime()); + logString << tunnel.clientOne()->userName(); + logString << tunnel.clientOne()->peerAddress().toString(); + logString << tunnel.clientTwo()->peerAddress().toString(); + logString << QString::number(tunnel.clientOne()->rxDataCount() + tunnel.clientOne()->txDataCount()); + + QTextStream textStream(&m_tunnelsFile); + textStream << logString.join(" ") << endl; +} + +void LogEngine::logStatistics(int tunnelCount, int connectionCount, int troughput) +{ + if (!m_statisticsFile.isOpen()) + return; + + // + QStringList logString; + logString << createTimestamp(); + logString << QString::number(tunnelCount); + logString << QString::number(connectionCount); + logString << QString::number(troughput); + + QTextStream textStream(&m_statisticsFile); + textStream << logString.join(" ") << endl; + + // Check if we have to rotate the logfile + if (m_currentDay != QDateTime::currentDateTime().date().day()) { + // Day changed + m_currentDay = QDateTime::currentDateTime().date().day(); + rotateLogs(); + } +} + +void LogEngine::rotateLogs() +{ + qCDebug(dcApplication()) << "Rotate log files."; + + // Close the log files + if (m_tunnelsFile.isOpen()) + m_tunnelsFile.close(); + + if (m_statisticsFile.isOpen()) + m_statisticsFile.close(); + + // Rename the current files + QString postfix = "-" + QDateTime::currentDateTime().toString("yyyyMMddhhmmss") + ".log"; + + m_tunnelsFile.rename(m_tunnelsFileName + postfix); + qCDebug(dcApplication()) << "Rotate logfile" << m_tunnelsFile.fileName(); + + m_statisticsFile.rename(m_statisticsFileName + postfix); + qCDebug(dcApplication()) << "Rotate logfile" << m_statisticsFile.fileName(); + + // Reopen the file with the default log file name + m_statisticsFile.setFileName(m_statisticsFileName + ".log"); + if (!m_statisticsFile.open(QIODevice::WriteOnly | QIODevice::Append)) { + qCDebug(dcApplication()) << "Could not open logfile" << m_statisticsFile.fileName(); + } + + m_tunnelsFile.setFileName(m_tunnelsFileName + ".log"); + if (!m_tunnelsFile.open(QIODevice::WriteOnly | QIODevice::Append)) { + qCDebug(dcApplication()) << "Could not open logfile" << m_tunnelsFile.fileName(); + } +} + +QString LogEngine::createTimestamp() +{ + return QString::number(QDateTime::currentDateTime().toTime_t()); +} + +void LogEngine::enable() +{ + qCDebug(dcApplication()) << "Enable log engine"; + m_enabled = true; + + m_statisticsFile.setFileName(m_statisticsFileName + ".log"); + if (!m_statisticsFile.open(QIODevice::WriteOnly | QIODevice::Append)) { + qCDebug(dcApplication()) << "Could not open logfile" << m_statisticsFile.fileName(); + } + + m_tunnelsFile.setFileName(m_tunnelsFileName + ".log"); + if (!m_tunnelsFile.open(QIODevice::WriteOnly | QIODevice::Append)) { + qCDebug(dcApplication()) << "Could not open logfile" << m_tunnelsFile.fileName(); + } +} + +void LogEngine::disable() +{ + qCDebug(dcApplication()) << "Disable log engine"; + m_enabled = false; + + if (m_tunnelsFile.isOpen()) + m_tunnelsFile.close(); + + if (m_statisticsFile.isOpen()) + m_statisticsFile.close(); +} + +} diff --git a/libnymea-remoteproxy/logengine.h b/libnymea-remoteproxy/logengine.h new file mode 100644 index 0000000..3ee367f --- /dev/null +++ b/libnymea-remoteproxy/logengine.h @@ -0,0 +1,63 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2018 Simon Stürz * + * * + * This file is part of nymea-remoteproxy. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef LOGENGINE_H +#define LOGENGINE_H + +#include +#include + +#include "tunnelconnection.h" + +namespace remoteproxy { + +class LogEngine : public QObject +{ + Q_OBJECT +public: + explicit LogEngine(QObject *parent = nullptr); + ~LogEngine(); + + void logTunnel(const TunnelConnection &tunnel); + void logStatistics(int tunnelCount, int connectionCount, int troughput); + +private: + QFile m_tunnelsFile; + QFile m_statisticsFile; + + QString m_tunnelsFileName; + QString m_statisticsFileName; + + bool m_enabled = false; + int m_currentDay; + + void rotateLogs(); + QString createTimestamp(); + +public slots: + void enable(); + void disable(); + +}; + +} + +#endif // LOGENGINE_H diff --git a/libnymea-remoteproxy/proxyconfiguration.cpp b/libnymea-remoteproxy/proxyconfiguration.cpp index 375eb38..11f22a6 100644 --- a/libnymea-remoteproxy/proxyconfiguration.cpp +++ b/libnymea-remoteproxy/proxyconfiguration.cpp @@ -50,6 +50,7 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName) setServerName(settings.value("name", "nymea-remoteproxy").toString()); setWriteLogFile(settings.value("writeLogs", false).toBool()); setLogFileName(settings.value("logFile", "/var/log/nymea-remoteproxy.log").toString()); + setLogEngineEnabled(settings.value("logEngineEnabled", false).toBool()); setMonitorSocketFileName(settings.value("monitorSocket", "/tmp/nymea-remoteproxy.monitor").toString()); setJsonRpcTimeout(settings.value("jsonRpcTimeout", 10000).toInt()); setAuthenticationTimeout(settings.value("authenticationTimeout", 8000).toInt()); @@ -159,6 +160,16 @@ void ProxyConfiguration::setLogFileName(const QString &logFileName) m_logFileName = logFileName; } +bool ProxyConfiguration::logEngineEnabled() const +{ + return m_logEngineEnabled; +} + +void ProxyConfiguration::setLogEngineEnabled(bool enabled) +{ + m_logEngineEnabled = enabled; +} + QString ProxyConfiguration::monitorSocketFileName() const { return m_monitorSocketFileName; @@ -322,6 +333,7 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration) debug.nospace() << " - Server name:" << configuration->serverName() << endl; debug.nospace() << " - Write logfile:" << configuration->writeLogFile() << endl; debug.nospace() << " - Logfile:" << configuration->logFileName() << endl; + debug.nospace() << " - Log engine enabled:" << configuration->logEngineEnabled() << endl; debug.nospace() << " - JSON RPC timeout:" << configuration->jsonRpcTimeout() << " [ms]" << endl; debug.nospace() << " - Authentication timeout:" << configuration->authenticationTimeout() << " [ms]" << endl; debug.nospace() << " - Inactive timeout:" << configuration->inactiveTimeout() << " [ms]" << endl; diff --git a/libnymea-remoteproxy/proxyconfiguration.h b/libnymea-remoteproxy/proxyconfiguration.h index cfebf6a..5a4b003 100644 --- a/libnymea-remoteproxy/proxyconfiguration.h +++ b/libnymea-remoteproxy/proxyconfiguration.h @@ -50,6 +50,9 @@ public: QString logFileName() const; void setLogFileName(const QString &logFileName); + bool logEngineEnabled() const; + void setLogEngineEnabled(bool enabled); + QString monitorSocketFileName() const; void setMonitorSocketFileName(const QString &fileName); @@ -107,6 +110,7 @@ private: QString m_serverName; bool m_writeLogFile = false; QString m_logFileName = "/var/log/nymea-remoteproxy.log"; + bool m_logEngineEnabled = false; QString m_monitorSocketFileName; int m_jsonRpcTimeout = 10000; diff --git a/libnymea-remoteproxy/proxyserver.cpp b/libnymea-remoteproxy/proxyserver.cpp index 5730383..fb1af26 100644 --- a/libnymea-remoteproxy/proxyserver.cpp +++ b/libnymea-remoteproxy/proxyserver.cpp @@ -19,6 +19,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include "engine.h" #include "proxyserver.h" #include "loggingcategories.h" @@ -179,7 +180,6 @@ void ProxyServer::establishTunnel(ProxyClient *firstClient, ProxyClient *secondC qCDebug(dcProxyServer()) << tunnel; - m_totalTunnelCount += 1; saveStatistics(); @@ -190,7 +190,6 @@ void ProxyServer::establishTunnel(ProxyClient *firstClient, ProxyClient *secondC Q_ARG(QVariantMap, notificationParamsFirst), Q_ARG(ProxyClient *, tunnel.clientOne())); - QMetaObject::invokeMethod(m_jsonRpcServer, QString("sendNotification").toLatin1().data(), Qt::QueuedConnection, Q_ARG(QString, m_jsonRpcServer->name()), Q_ARG(QString, "TunnelEstablished"), @@ -198,7 +197,6 @@ void ProxyServer::establishTunnel(ProxyClient *firstClient, ProxyClient *secondC Q_ARG(ProxyClient *, tunnel.clientTwo())); } - void ProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address) { TransportInterface *interface = static_cast(sender()); @@ -241,7 +239,8 @@ void ProxyServer::onClientDisconnected(const QUuid &clientId) // There is a tunnel connection for this client, remove the tunnel and disconnect also the other client ProxyClient *remoteClient = getRemoteClient(proxyClient); - m_tunnels.remove(proxyClient->token()); + TunnelConnection tunnelConnection = m_tunnels.take(proxyClient->token()); + Engine::instance()->logEngine()->logTunnel(tunnelConnection); if (remoteClient) { remoteClient->killConnection("Tunnel client disconnected"); } diff --git a/nymea-remoteproxy.conf b/nymea-remoteproxy.conf index 7690741..9266c60 100644 --- a/nymea-remoteproxy.conf +++ b/nymea-remoteproxy.conf @@ -2,6 +2,7 @@ name=nymea-remoteproxy writeLogs=false logFile=/var/log/nymea-remoteproxy.log +logEngineEnabled=false monitorSocket=/tmp/nymea-remoteproxy-monitor.sock jsonRpcTimeout=10000 authenticationTimeout=8000 diff --git a/nymea-remoteproxy.pri b/nymea-remoteproxy.pri index a8f4397..3bd922e 100644 --- a/nymea-remoteproxy.pri +++ b/nymea-remoteproxy.pri @@ -5,7 +5,7 @@ QT -= gui SERVER_NAME=nymea-remoteproxy API_VERSION_MAJOR=0 API_VERSION_MINOR=3 -SERVER_VERSION=0.1.6 +SERVER_VERSION=0.1.7 DEFINES += SERVER_NAME_STRING=\\\"$${SERVER_NAME}\\\" \ SERVER_VERSION_STRING=\\\"$${SERVER_VERSION}\\\" \