Files

341 lines
8.7 KiB
C++
Raw Permalink Normal View History

2022-12-28 13:41:45 +03:00
#include "logger.h"
2022-02-22 02:08:57 +03:00
#include <QDateTime>
2020-12-16 06:02:22 +03:00
#include <QDebug>
#include <QDesktopServices>
2020-11-23 16:20:25 +03:00
#include <QDir>
#include <QJsonDocument>
#include <QMetaEnum>
2020-11-23 16:20:25 +03:00
#include <QStandardPaths>
2020-12-16 06:02:22 +03:00
#include <QUrl>
2020-11-23 16:20:25 +03:00
#include "utilities.h"
#include "version.h"
2020-11-23 16:20:25 +03:00
2022-02-22 02:08:57 +03:00
#ifdef AMNEZIA_DESKTOP
#include <core/ipcclient.h>
2022-02-22 02:08:57 +03:00
#endif
#ifdef Q_OS_IOS
#include <DefaultVPN-Swift.h>
#endif
2022-12-28 13:41:45 +03:00
QFile Logger::m_file;
QTextStream Logger::m_textStream;
QString Logger::m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
QString Logger::m_serviceLogFileName = QString("%1.log").arg(SERVICE_NAME);
2020-11-23 16:20:25 +03:00
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
2020-11-23 16:20:25 +03:00
{
2020-12-16 06:02:22 +03:00
if (msg.simplified().isEmpty()) {
return;
}
2020-12-26 23:17:20 +03:00
// Skip annoying messages from Qt
if (msg.contains("OpenType support missing for")) {
return;
}
if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap")
|| msg.startsWith("Populating font") || msg.startsWith("stale focus object")) {
2020-12-16 06:02:22 +03:00
return;
}
2020-11-23 16:20:25 +03:00
switch (type) {
case QtDebugMsg: Logger::Instance().debug() << msg; break;
case QtInfoMsg: Logger::Instance().info() << msg; break;
case QtWarningMsg: Logger::Instance().warning() << msg; break;
case QtCriticalMsg: Logger::Instance().error() << msg; break;
case QtFatalMsg: {
Logger::Instance().error() << msg;
} // Brackets are needed to ensure the destructor of LogStreamer is called before abort()
abort();
}
2020-11-23 16:20:25 +03:00
}
2022-12-28 13:41:45 +03:00
Logger &Logger::Instance()
2022-02-04 17:49:48 +03:00
{
2022-12-28 13:41:45 +03:00
static Logger s;
2022-02-04 17:49:48 +03:00
return s;
}
bool Logger::init(bool isServiceLogger)
2020-11-23 16:20:25 +03:00
{
QString path = isServiceLogger ? systemLogDir() : userLogsDir();
QString logFileName = isServiceLogger ? m_serviceLogFileName : m_logFileName;
2020-11-23 16:20:25 +03:00
QDir appDir(path);
2020-12-16 06:02:22 +03:00
if (!appDir.mkpath(path)) {
2020-11-23 16:20:25 +03:00
return false;
}
m_file.setFileName(appDir.filePath(logFileName));
2022-01-30 17:35:57 +03:00
if (!m_file.open(QIODevice::Append)) {
qWarning() << "Cannot open log file:" << logFileName;
2020-11-23 16:20:25 +03:00
return false;
}
2020-12-16 06:02:22 +03:00
m_file.setTextModeEnabled(true);
m_textStream.setDevice(&m_file);
2021-10-17 07:00:00 -07:00
qInstallMessageHandler(messageHandler);
2020-11-23 16:20:25 +03:00
return true;
}
2022-12-28 13:41:45 +03:00
void Logger::deInit()
{
m_textStream.setDevice(nullptr);
m_file.close();
}
bool Logger::setServiceLogsEnabled(bool enabled)
{
#ifdef AMNEZIA_DESKTOP
return IpcClient::withInterface([enabled](QSharedPointer<IpcInterfaceReplica> iface) {
iface->setLogsEnabled(enabled);
qDebug() << "Logger::setServiceLogsEnabled(): Logs transitioned to be " << (enabled ? "enabled" : "disabled");
return true;
},[](){
qWarning() << "Logger::setServiceLogsEnabled(): Service is not running";
return false;
});
#endif
return true;
}
2022-12-28 13:41:45 +03:00
QString Logger::userLogsDir()
2020-11-23 16:20:25 +03:00
{
2020-12-26 23:17:20 +03:00
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log";
2020-11-23 16:20:25 +03:00
}
QString Logger::systemLogDir()
{
#ifdef Q_OS_WIN
QStringList locationList = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
QString primaryLocation = "ProgramData";
foreach (const QString &location, locationList) {
if (location.contains(primaryLocation)) {
return QString("%1/%2/log").arg(location).arg(APPLICATION_NAME);
}
}
return QString();
#else
return QString("/var/log/%1").arg(APPLICATION_NAME);
#endif
}
2022-12-28 13:41:45 +03:00
QString Logger::userLogsFilePath()
2022-02-01 19:48:59 +03:00
{
return userLogsDir() + QDir::separator() + m_logFileName;
}
QString Logger::serviceLogsFilePath()
{
return systemLogDir() + QDir::separator() + m_serviceLogFileName;
}
2022-12-28 13:41:45 +03:00
QString Logger::getLogFile()
2022-02-01 19:48:59 +03:00
{
m_file.flush();
QFile file(userLogsFilePath());
file.open(QIODevice::ReadOnly);
QString qtLog = file.readAll();
#ifdef Q_OS_IOS
return QString().fromStdString(DefaultVPN::swiftUpdateLogData(qtLog.toStdString()));
#else
return qtLog;
#endif
}
QString Logger::getServiceLogFile()
{
m_file.flush();
QFile file(serviceLogsFilePath());
file.open(QIODevice::ReadOnly);
QString qtLog = file.readAll();
#ifdef Q_OS_IOS
return QString().fromStdString(DefaultVPN::swiftUpdateLogData(qtLog.toStdString()));
#else
return qtLog;
#endif
2022-02-01 19:48:59 +03:00
}
bool Logger::openLogsFolder(bool isServiceLogger)
2020-11-23 16:20:25 +03:00
{
QString path = isServiceLogger ? systemLogDir() : userLogsDir();
2020-12-16 06:02:22 +03:00
#ifdef Q_OS_WIN
path = "file:///" + path;
#endif
if (!QDesktopServices::openUrl(QUrl::fromLocalFile(path))) {
qWarning() << "Can't open url:" << path;
return false;
2020-11-23 16:20:25 +03:00
}
2020-12-16 06:02:22 +03:00
return true;
2020-11-23 16:20:25 +03:00
}
2020-12-26 15:03:51 +03:00
void Logger::clearLogs(bool isServiceLogger)
2022-01-30 17:35:57 +03:00
{
bool isLogActive = m_file.isOpen();
m_file.close();
QFile file(isServiceLogger ? serviceLogsFilePath() : userLogsFilePath());
2022-01-30 17:35:57 +03:00
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
file.resize(0);
file.close();
#ifdef Q_OS_IOS
DefaultVPN::swiftDeleteLog();
#endif
2022-01-30 17:35:57 +03:00
if (isLogActive) {
init(isServiceLogger);
2022-01-30 17:35:57 +03:00
}
}
2022-12-28 13:41:45 +03:00
void Logger::clearServiceLogs()
2022-01-30 17:35:57 +03:00
{
2022-02-22 02:08:57 +03:00
#ifdef AMNEZIA_DESKTOP
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
iface->clearLogs();
qDebug() << "Logger::clearServiceLogs(): Logs cleared";
}, []() {
qWarning() << "Logger::clearServiceLogs(): Service is not running";
});
2022-02-22 02:08:57 +03:00
#endif
2022-01-30 17:35:57 +03:00
}
2022-12-28 13:41:45 +03:00
void Logger::cleanUp()
2022-01-30 17:35:57 +03:00
{
clearLogs(false);
2022-01-30 17:35:57 +03:00
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
dir.removeRecursively();
clearLogs(true);
2022-01-30 17:35:57 +03:00
}
Logger::LogStreamer::LogStreamer(Logger *logger, LogLevel logLevel)
: m_logger(logger), m_logLevel(logLevel), m_data(new Data())
{
}
Logger::LogStreamer::~LogStreamer()
{
QString logLevelString;
switch (m_logLevel) {
case LogLevel::Trace: logLevelString = "[TRACE]"; break;
case LogLevel::Debug: logLevelString = "[DEBUG]"; break;
case LogLevel::Info: logLevelString = "[INFO]"; break;
case LogLevel::Warning: logLevelString = "[WARNING]"; break;
case LogLevel::Error: logLevelString = "[ERROR]"; break;
}
const QString message = QString("%1 %2 Amnezia %3 : %4")
.arg(QDateTime::currentDateTimeUtc().toString("[yyyy-MM-dd hh:mm:ss.zzzZ]"),
logLevelString, m_logger->className(), m_data->m_buffer.trimmed());
if (m_file.isOpen()) {
QTextStream logToFile(&m_file);
logToFile << message << Qt::endl << Qt::flush;
}
QTextStream logToOutput((m_logLevel == LogLevel::Error) ? stderr : stdout);
logToOutput << message << Qt::endl << Qt::flush;
delete m_data;
}
Logger::LogStreamer Logger::error()
{
return { this, LogLevel::Error };
}
Logger::LogStreamer Logger::warning()
{
return { this, LogLevel::Warning };
}
Logger::LogStreamer Logger::info()
{
return { this, LogLevel::Info };
}
Logger::LogStreamer Logger::debug()
{
return { this, LogLevel::Debug };
}
QString Logger::sensitive(const QString &input)
{
#ifdef Q_DEBUG
return input;
#else
Q_UNUSED(input);
return { 8, 'X' };
#endif
}
#define CREATE_LOGSTREAMER_OP_REF(x) \
Logger::LogStreamer &Logger::LogStreamer::operator<<(x t) \
{ \
m_data->m_ts << t << ' '; \
return *this; \
}
CREATE_LOGSTREAMER_OP_REF(uint64_t);
CREATE_LOGSTREAMER_OP_REF(const char *);
CREATE_LOGSTREAMER_OP_REF(const QString &);
CREATE_LOGSTREAMER_OP_REF(const QByteArray &);
CREATE_LOGSTREAMER_OP_REF(const void *);
#undef CREATE_LOGSTREAMER_OP_REF
Logger::LogStreamer &Logger::LogStreamer::operator<<(const QStringList &t)
{
m_data->m_ts << '[' << t.join(",") << ']' << ' ';
return *this;
}
Logger::LogStreamer &Logger::LogStreamer::operator<<(const QJsonObject &t)
{
m_data->m_ts << QJsonDocument(t).toJson(QJsonDocument::Indented) << ' ';
return *this;
}
Logger::LogStreamer &Logger::LogStreamer::operator<<(QTextStreamFunction t)
{
m_data->m_ts << t;
return *this;
}
void Logger::LogStreamer::addMetaEnum(quint64 value, const QMetaObject *meta, const char *name)
{
QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
QString out;
QTextStream ts(&out);
if (const char *scope = me.scope()) {
ts << scope << "::";
}
const char *key = me.valueToKey(static_cast<int>(value));
const bool scoped = me.isScoped();
if (scoped || !key) {
ts << me.enumName() << (!key ? "(" : "::");
}
if (key) {
ts << key;
} else {
ts << value << ")";
}
m_data->m_ts << out;
}