1
0

GODT-1893: bridge-gui sends bridge's log to stdout, stderr.

WIP: bridge-gui now parses and self-apply log level from command-line.
WIP: downgraded the log level of gRPC calls to debug.
This commit is contained in:
Xavier Michelon
2022-09-26 10:03:00 +02:00
parent 7a3354f654
commit 653727fd12
13 changed files with 343 additions and 195 deletions

View File

@ -110,6 +110,7 @@ endif(UNIX)
add_executable(bridge-gui
Resources.qrc
AppController.cpp AppController.h
CommandLine.cpp CommandLine.h
EventStreamWorker.cpp EventStreamWorker.h
main.cpp
Pch.h

View File

@ -0,0 +1,129 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.
//
// Proton Mail Bridge 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.
//
// Proton Mail Bridge 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "CommandLine.h"
using namespace bridgepp;
namespace
{
QString const launcherFlag = "--launcher"; ///< launcher flag parameter used for bridge.
//****************************************************************************************************************************************************
/// \brief parse a command-line string argument as expected by go's CLI package.
/// \param[in] argc The number of arguments passed to the application.
/// \param[in] argv The list of arguments passed to the application.
/// \param[in] paramNames the list of names for the parameter
//****************************************************************************************************************************************************
QString parseGoCLIStringArgument(int argc, char *argv[], QStringList paramNames)
{
// go cli package is pretty permissive when it comes to parsing arguments. For each name 'param', all the following seems to be accepted:
// -param value
// --param value
// -param=value
// --param=value
for (QString const &paramName: paramNames)
for (qsizetype i = 1; i < argc; ++i)
{
QString const arg(QString::fromLocal8Bit(argv[i]));
if ((i < argc - 1) && ((arg == "-" + paramName) || (arg == "--" + paramName)))
return QString(argv[i + 1]);
QRegularExpressionMatch match = QRegularExpression(QString("^-{1,2}%1=(.+)$").arg(paramName)).match(arg);
if (match.hasMatch())
return match.captured(1);
}
return QString();
}
//****************************************************************************************************************************************************
/// \brief Parse the log level from the command-line arguments.
///
/// \param[in] argc The number of arguments passed to the application.
/// \param[in] argv The list of arguments passed to the application.
/// \return The log level. if not specified on the command-line, the default log level is returned.
//****************************************************************************************************************************************************
Log::Level parseLogLevel(int argc, char *argv[])
{
QString levelStr = parseGoCLIStringArgument(argc, argv, { "l", "log-level" });
if (levelStr.isEmpty())
return Log::defaultLevel;
Log::Level level = Log::defaultLevel;
Log::stringToLevel(levelStr, level);
return level;
}
} // anonymous namespace
//****************************************************************************************************************************************************
/// \param[in] argc number of arguments passed to the application.
/// \param[in] argv list of arguments passed to the application.
/// \param[out] args list of arguments passed to the application as a QStringList.
/// \param[out] launcher launcher used in argument, forced to self application if not specify.
/// \param[out] outAttach The value for the 'attach' command-line parameter.
/// \param[out] outLogLevel The parsed log level. If not found, the default log level is returned.
//****************************************************************************************************************************************************
void parseCommandLineArguments(int argc, char *argv[], QStringList& args, QString& launcher, bool &outAttach, Log::Level& outLogLevel) {
bool flagFound = false;
launcher = QString::fromLocal8Bit(argv[0]);
// for unknown reasons, on Windows QCoreApplication::arguments() frequently returns an empty list, which is incorrect, so we rebuild the argument
// list from the original argc and argv values.
for (int i = 1; i < argc; i++) {
QString const &arg = QString::fromLocal8Bit(argv[i]);
// we can't use QCommandLineParser here since it will fail on unknown options.
// Arguments may contain some bridge flags.
if (arg == launcherFlag)
{
args.append(arg);
launcher = QString::fromLocal8Bit(argv[++i]);
args.append(launcher);
flagFound = true;
}
#ifdef QT_DEBUG
else if (arg == "--attach" || arg == "-a")
{
// we don't keep the attach mode within the args since we don't need it for Bridge.
outAttach = true;
}
#endif
else
{
args.append(arg);
}
}
if (!flagFound)
{
// add bridge-gui as launcher
args.append(launcherFlag);
args.append(launcher);
}
outLogLevel = parseLogLevel(argc, argv);
}

View File

@ -0,0 +1,29 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.
//
// Proton Mail Bridge 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.
//
// Proton Mail Bridge 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_COMMAND_LINE_H
#define BRIDGE_GUI_COMMAND_LINE_H
#include <bridgepp/Log/Log.h>
void parseCommandLineArguments(int argc, char *argv[], QStringList& args, QString& launcher, bool &outAttach, bridgepp::Log::Level& outLogLevel); ///< Parse the command-line arguments
#endif //BRIDGE_GUI_COMMAND_LINE_H

View File

@ -161,12 +161,9 @@ bridgepp::SPUser UserList::getUserWithID(QString const &userID) const
User *UserList::get(int row) const
{
if ((row < 0) || (row >= users_.count()))
{
app().log().error(QString("Requesting invalid user at row %1 (user userCount = %2)").arg(row).arg(users_.count()));
return nullptr;
}
app().log().debug(QString("Retrieving user at row %1 (user userCount = %2)").arg(row).arg(users_.count()));
app().log().trace(QString("Retrieving user at row %1 (user userCount = %2)").arg(row).arg(users_.count()));
return users_[row].get();
}
@ -185,7 +182,7 @@ void UserList::onUserChanged(QString const &userID)
{
if (index >= 0) // user exists here but not in the go backend. we delete it.
{
app().log().debug(QString("Removing user from user list: %1").arg(userID));
app().log().trace(QString("Removing user from user list: %1").arg(userID));
this->removeUserAt(index);
}
return;
@ -193,12 +190,12 @@ void UserList::onUserChanged(QString const &userID)
if (index < 0)
{
app().log().debug(QString("Adding user in user list: %1").arg(userID));
app().log().trace(QString("Adding user in user list: %1").arg(userID));
this->appendUser(user);
return;
}
app().log().debug(QString("Updating user in user list: %1").arg(userID));
app().log().trace(QString("Updating user in user list: %1").arg(userID));
this->updateUserAtRow(index, *user);
}

View File

@ -16,6 +16,8 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "CommandLine.h"
#include "QMLBackend.h"
#include "Version.h"
#include <bridgepp/Log/Log.h>
@ -23,10 +25,6 @@
#include <bridgepp/Exception/Exception.h>
#include <bridgepp/ProcessMonitor.h>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QJsonDocument>
#include <QJsonObject>
using namespace bridgepp;
@ -41,7 +39,6 @@ namespace
QString const exeSuffix;
#endif
QString const launcherFlag = "--launcher"; ///< launcher flag parameter used for bridge.
QString const bridgeLock = "bridge-gui.lock"; ///< file name used for the lock file.
QString const exeName = "bridge" + exeSuffix; ///< The bridge executable file name.*
}
@ -81,8 +78,6 @@ void initQtApplication()
Log &initLog()
{
Log &log = app().log();
log.setEchoInConsole(true);
log.setLevel(Log::Level::Debug);
log.registerAsQtMessageHandler();
return log;
}
@ -141,7 +136,7 @@ bool checkSingleInstance(QLockFile &lock)
//****************************************************************************************************************************************************
/// \return QUrl to reqch the bridge API.
/// \return QUrl to reach the bridge API.
//****************************************************************************************************************************************************
QUrl getApiUrl()
{
@ -189,50 +184,6 @@ void focusOtherInstance()
}
//****************************************************************************************************************************************************
/// \param [in] argc number of arguments passed to the application.
/// \param [in] argv list of arguments passed to the application.
/// \param [out] args list of arguments passed to the application as a QStringList.
/// \param [out] launcher launcher used in argument, forced to self application if not specify.
/// \param[out] outAttach The value for the 'attach' command-line parameter.
//****************************************************************************************************************************************************
void parseArguments(int argc, char *argv[], QStringList& args, QString& launcher, bool &outAttach) {
bool flagFound = false;
launcher = QString::fromLocal8Bit(argv[0]);
// for unknown reasons, on Windows QCoreApplication::arguments() frequently returns an empty list, which is incorrect, so we rebuild the argument
// list from the original argc and argv values.
for (int i = 1; i < argc; i++) {
QString const &arg = QString::fromLocal8Bit(argv[i]);
// we can't use QCommandLineParser here since it will fail on unknown options.
// Arguments may contain some bridge flags.
if (arg == launcherFlag)
{
args.append(arg);
launcher = QString::fromLocal8Bit(argv[++i]);
args.append(launcher);
flagFound = true;
}
#ifdef QT_DEBUG
else if (arg == "--attach" || arg == "-a")
{
// we don't keep the attach mode within the args since we don't need it for Bridge.
outAttach = true;
}
#endif
else
{
args.append(arg);
}
}
if (!flagFound)
{
// add bridge-gui as launcher
args.append(launcherFlag);
args.append(launcher);
}
}
//****************************************************************************************************************************************************
/// \param [in] args list of arguments to pass to bridge.
//****************************************************************************************************************************************************
@ -300,7 +251,14 @@ int main(int argc, char *argv[])
QStringList args;
QString launcher;
bool attach = false;
parseArguments(argc, argv, args, launcher, attach);
Log::Level logLevel = Log::defaultLevel;
parseCommandLineArguments(argc, argv, args, launcher, attach, logLevel);
// In attached mode, we do not intercept stderr and stdout of bridge, as we did not launch it ourselves, so we output the log to the console.
// When not in attached mode, log entries are forwarded to bridge, which output it on stdout/stderr. bridge-gui's process monitor intercept
// these outputs and output them on the command-line.
log.setEchoInConsole(attach);
log.setLevel(logLevel);
if (!attach)
launchBridge(args);
@ -344,7 +302,7 @@ int main(int argc, char *argv[])
int result = 0;
if (!startError)
{
// we succeed to run the bridge so we can be set as mainExecutable.
// we succeeded in launching bridge, so we can be set as mainExecutable.
app().grpc().setMainExecutable(QString::fromLocal8Bit(argv[0]));
result = QGuiApplication::exec();
}