mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 03:18:07 +00:00
Fix threading to run just after minimal initialization (like logger instanciation).
Rewrite Logger : out logs are run on core, and file logs on model. Fix crash on removing logger listener.
This commit is contained in:
parent
ca40833b43
commit
bc2c51badd
8 changed files with 184 additions and 119 deletions
|
|
@ -31,8 +31,6 @@ App::App(int &argc, char *argv[])
|
|||
: SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
|
||||
mLinphoneThread = new Thread(this);
|
||||
init();
|
||||
qDebug() << "[App] Starting Thread";
|
||||
mLinphoneThread->start();
|
||||
}
|
||||
|
||||
App *App::getInstance() {
|
||||
|
|
@ -58,6 +56,11 @@ void App::init() {
|
|||
if (mParser->isSet("verbose")) QtLogger::enableVerbose(true);
|
||||
if (mParser->isSet("qt-logs-only")) QtLogger::enableQtOnly(true);
|
||||
|
||||
if (!mLinphoneThread->isRunning()) {
|
||||
qDebug() << "[App] Starting Thread";
|
||||
mLinphoneThread->start();
|
||||
}
|
||||
|
||||
// QML
|
||||
mEngine = new QQmlApplicationEngine(this);
|
||||
mEngine->addImportPath(":/");
|
||||
|
|
@ -68,7 +71,10 @@ void App::init() {
|
|||
QObject::connect(
|
||||
mEngine, &QQmlApplicationEngine::objectCreated, this,
|
||||
[url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl) QCoreApplication::exit(-1);
|
||||
if (!obj && url == objUrl) {
|
||||
qCritical() << "[App] Main.qml couldn't be load. The app will exit";
|
||||
exit(-1);
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
mEngine->load(url);
|
||||
|
|
@ -83,6 +89,9 @@ void App::initCppInterfaces() {
|
|||
//------------------------------------------------------------
|
||||
|
||||
void App::clean() {
|
||||
// Wait 500ms to let time for log te be stored.
|
||||
mLinphoneThread->wait(250);
|
||||
qApp->processEvents(QEventLoop::AllEvents, 250);
|
||||
mLinphoneThread->exit();
|
||||
mLinphoneThread->wait();
|
||||
delete mLinphoneThread;
|
||||
|
|
|
|||
|
|
@ -19,21 +19,59 @@
|
|||
*/
|
||||
|
||||
#include "QtLogger.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QMetaMethod>
|
||||
#include <iostream>
|
||||
#include <linphone++/linphone.hh>
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static QtLogger gLogger;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#define BLUE "\x1B[1;34m"
|
||||
#define YELLOW "\x1B[1;33m"
|
||||
#define GREEN "\x1B[1;32m"
|
||||
#define PURPLE "\x1B[1;35m"
|
||||
#define RED "\x1B[1;31m"
|
||||
#define RESET "\x1B[0m"
|
||||
#else
|
||||
#define BLUE ""
|
||||
#define YELLOW ""
|
||||
#define GREEN ""
|
||||
#define PURPLE ""
|
||||
#define RED ""
|
||||
#define RESET ""
|
||||
#endif // if defined(__linux__) || defined(__APPLE__)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static inline QByteArray getFormattedCurrentTime() {
|
||||
return QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz").toLocal8Bit();
|
||||
}
|
||||
|
||||
QtLogger::QtLogger(QObject *parent) : QObject(parent) {
|
||||
qInstallMessageHandler(QtLogger::onQtLog);
|
||||
}
|
||||
|
||||
QtLogger::~QtLogger() {
|
||||
qInstallMessageHandler(0);
|
||||
}
|
||||
|
||||
QtLogger *QtLogger::getInstance() {
|
||||
return &gLogger;
|
||||
}
|
||||
|
||||
void QtLogger::onQtLog(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
|
||||
emit gLogger.logReceived(type, context.file, context.line, msg);
|
||||
if (type == QtFatalMsg) {
|
||||
QString out; // Qt force call abort() that kill the application. So it cannot be used to retrieve
|
||||
// in other thread. Print the error in the hope that it can be catch somewhere.
|
||||
gLogger.printLog(&out, Constants::AppDomain, linphone::LogLevel::Fatal, Utils::appStringToCoreString(msg));
|
||||
}
|
||||
emit gLogger.qtLogReceived(type, context.file, context.line, msg);
|
||||
}
|
||||
|
||||
void QtLogger::enableVerbose(bool verbose) {
|
||||
|
|
@ -43,3 +81,65 @@ void QtLogger::enableVerbose(bool verbose) {
|
|||
void QtLogger::enableQtOnly(bool qtOnly) {
|
||||
emit gLogger.requestQtOnlyEnabled(qtOnly);
|
||||
}
|
||||
|
||||
void QtLogger::onLinphoneLog(const std::string &domain, linphone::LogLevel level, const std::string &message) {
|
||||
QString qMessage;
|
||||
printLog(&qMessage, domain, level, message);
|
||||
|
||||
if (level == linphone::LogLevel::Fatal) {
|
||||
QMetaObject::invokeMethod(qApp, [qMessage]() {
|
||||
QMessageBox::critical(nullptr, EXECUTABLE_NAME " will crash", qMessage);
|
||||
std::terminate();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void QtLogger::printLog(QString *qMessage,
|
||||
const std::string &domain,
|
||||
linphone::LogLevel level,
|
||||
const std::string &message) {
|
||||
bool isAppLog = domain == Constants::AppDomain;
|
||||
FILE *out = stdout;
|
||||
// TypeColor Date SourceColor [Domain] TypeColor Type Reset Message
|
||||
QString format = "%1 %2 %3[%4]%1 %5" RESET " %6\n";
|
||||
QString colorType;
|
||||
QString type;
|
||||
*qMessage = Utils::coreStringToAppString(message);
|
||||
switch (level) {
|
||||
case linphone::LogLevel::Debug:
|
||||
colorType = GREEN;
|
||||
type = "DEBUG";
|
||||
break;
|
||||
case linphone::LogLevel::Trace:
|
||||
colorType = BLUE;
|
||||
type = "TRACE";
|
||||
break;
|
||||
case linphone::LogLevel::Message:
|
||||
colorType = BLUE;
|
||||
type = "MESSAGE";
|
||||
break;
|
||||
case linphone::LogLevel::Warning:
|
||||
colorType = RED;
|
||||
type = "WARNING";
|
||||
out = stderr;
|
||||
break;
|
||||
case linphone::LogLevel::Error:
|
||||
colorType = RED;
|
||||
type = "ERROR";
|
||||
out = stderr;
|
||||
break;
|
||||
case linphone::LogLevel::Fatal:
|
||||
colorType = RED;
|
||||
type = "FATAL";
|
||||
out = stderr;
|
||||
break;
|
||||
}
|
||||
QString messageToDisplay = format.arg(colorType)
|
||||
.arg(getFormattedCurrentTime())
|
||||
.arg(isAppLog ? PURPLE : YELLOW)
|
||||
.arg(Utils::coreStringToAppString(domain))
|
||||
.arg(type)
|
||||
.arg(*qMessage);
|
||||
fprintf(out, "%s", qPrintable(messageToDisplay));
|
||||
fflush(out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,22 +24,38 @@
|
|||
#include <QMetaMethod>
|
||||
#include <QObject>
|
||||
|
||||
// =============================================================================
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// Qt SDK
|
||||
//fatal | |
|
||||
// -- *----------> |
|
||||
// | |
|
||||
// | | <--------- *
|
||||
// | | |
|
||||
// -> | |
|
||||
// V V
|
||||
// OUT FILE
|
||||
//
|
||||
// Only one instance. Use getInstance() and logReceived() to bind logs coming from Qt.
|
||||
class QtLogger : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QtLogger(QObject *parent = nullptr);
|
||||
|
||||
~QtLogger();
|
||||
static QtLogger *getInstance();
|
||||
static void onQtLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
static void enableVerbose(bool verbose);
|
||||
static void enableQtOnly(bool qtOnly);
|
||||
|
||||
void printLog(QString * qMessage, const std::string &domain, linphone::LogLevel level, const std::string &message);
|
||||
|
||||
// Log Sources
|
||||
static void onQtLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
void onLinphoneLog(const std::string &domain, linphone::LogLevel level, const std::string &message);
|
||||
|
||||
signals:
|
||||
void logReceived(QtMsgType type, QString contextFile, int contextLine, QString msg);
|
||||
void qtLogReceived(QtMsgType type, QString contextFile, int contextLine, QString msg);
|
||||
void requestVerboseEnabled(bool verbose);
|
||||
void requestQtOnlyEnabled(bool qtOnly);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
int result = app.exec();
|
||||
int result = 0;
|
||||
while (result >= 0) {
|
||||
result = app.exec();
|
||||
}
|
||||
app.clean();
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,96 +20,14 @@
|
|||
|
||||
#include "LoggerListener.hpp"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
|
||||
#include "tool/Constants.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#define BLUE "\x1B[1;34m"
|
||||
#define YELLOW "\x1B[1;33m"
|
||||
#define GREEN "\x1B[1;32m"
|
||||
#define PURPLE "\x1B[1;35m"
|
||||
#define RED "\x1B[1;31m"
|
||||
#define RESET "\x1B[0m"
|
||||
#else
|
||||
#define BLUE ""
|
||||
#define YELLOW ""
|
||||
#define GREEN ""
|
||||
#define PURPLE ""
|
||||
#define RED ""
|
||||
#define RESET ""
|
||||
#endif // if defined(__linux__) || defined(__APPLE__)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static inline QByteArray getFormattedCurrentTime() {
|
||||
return QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz").toLocal8Bit();
|
||||
LoggerListener::LoggerListener() : QObject(nullptr) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
LoggerListener::LoggerListener() {
|
||||
}
|
||||
|
||||
void LoggerListener::onLogMessageWritten(const std::shared_ptr<linphone::LoggingService> &,
|
||||
void LoggerListener::onLogMessageWritten(const std::shared_ptr<linphone::LoggingService> &logService,
|
||||
const std::string &domain,
|
||||
linphone::LogLevel level,
|
||||
const std::string &message) {
|
||||
bool isAppLog = domain == Constants::AppDomain;
|
||||
if (!mVerboseEnabled || (!isAppLog && mQtOnlyEnabled)) return;
|
||||
FILE *out = stdout;
|
||||
// TypeColor Date SourceColor [Domain] TypeColor Type Reset Message
|
||||
QString format = "%1 %2 %3[%4]%1 %5" RESET " %6\n";
|
||||
QString colorType;
|
||||
QString type;
|
||||
QString qMessage = Utils::coreStringToAppString(message);
|
||||
switch (level) {
|
||||
case linphone::LogLevel::Debug:
|
||||
colorType = GREEN;
|
||||
type = "DEBUG";
|
||||
break;
|
||||
case linphone::LogLevel::Trace:
|
||||
colorType = BLUE;
|
||||
type = "TRACE";
|
||||
break;
|
||||
case linphone::LogLevel::Message:
|
||||
colorType = BLUE;
|
||||
type = "MESSAGE";
|
||||
break;
|
||||
case linphone::LogLevel::Warning:
|
||||
colorType = RED;
|
||||
type = "WARNING";
|
||||
out = stderr;
|
||||
break;
|
||||
case linphone::LogLevel::Error:
|
||||
colorType = RED;
|
||||
type = "ERROR";
|
||||
out = stderr;
|
||||
break;
|
||||
case linphone::LogLevel::Fatal:
|
||||
colorType = RED;
|
||||
type = "FATAL";
|
||||
out = stderr;
|
||||
break;
|
||||
}
|
||||
QString messageToDisplay = format.arg(colorType)
|
||||
.arg(getFormattedCurrentTime())
|
||||
.arg(isAppLog ? PURPLE : YELLOW)
|
||||
.arg(Utils::coreStringToAppString(domain))
|
||||
.arg(type)
|
||||
.arg(qMessage);
|
||||
fprintf(out, "%s", qPrintable(messageToDisplay));
|
||||
fflush(out);
|
||||
if (level == linphone::LogLevel::Fatal) {
|
||||
QMetaObject::invokeMethod(qApp, [qMessage]() {
|
||||
QMessageBox::critical(nullptr, EXECUTABLE_NAME " will crash", qMessage);
|
||||
std::terminate();
|
||||
});
|
||||
}
|
||||
emit logReceived(logService, domain, level, message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,19 +21,23 @@
|
|||
#ifndef LOGGER_LISTENER_H_
|
||||
#define LOGGER_LISTENER_H_
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
class LoggerListener : public linphone::LoggingServiceListener {
|
||||
class LoggerListener : public QObject, public linphone::LoggingServiceListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LoggerListener();
|
||||
|
||||
bool mVerboseEnabled = false;
|
||||
bool mQtOnlyEnabled = false;
|
||||
|
||||
static QString printLog(bool isAppLog, const std::string &domain, linphone::LogLevel level, const std::string &message);
|
||||
signals:
|
||||
void logReceived(const std::shared_ptr<linphone::LoggingService> &logService,
|
||||
const std::string &domain,
|
||||
linphone::LogLevel level,
|
||||
const std::string &message);
|
||||
private:
|
||||
virtual void onLogMessageWritten(const std::shared_ptr<linphone::LoggingService> &logService,
|
||||
const std::string &domain,
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@
|
|||
*/
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
#include "config.h"
|
||||
|
|
@ -35,23 +35,26 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
LoggerModel::LoggerModel(QObject *parent) : QObject(parent) {
|
||||
connect(QtLogger::getInstance(), &QtLogger::logReceived, this, &LoggerModel::onLog, Qt::QueuedConnection);
|
||||
connect(QtLogger::getInstance(), &QtLogger::qtLogReceived, this, &LoggerModel::onQtLog, Qt::QueuedConnection);
|
||||
connect(QtLogger::getInstance(), &QtLogger::requestVerboseEnabled, this, &LoggerModel::enableVerbose,
|
||||
Qt::QueuedConnection);
|
||||
connect(QtLogger::getInstance(), &QtLogger::requestQtOnlyEnabled, this, &LoggerModel::enableQtOnly,
|
||||
Qt::QueuedConnection);
|
||||
connect(this, &LoggerModel::linphoneLogReceived, QtLogger::getInstance(), &QtLogger::onLinphoneLog,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
LoggerModel::~LoggerModel() {
|
||||
linphone::LoggingService::get()->removeListener(mListener);
|
||||
}
|
||||
|
||||
bool LoggerModel::isVerbose() const {
|
||||
return mListener ? mListener->mVerboseEnabled : false;
|
||||
return mVerboseEnabled;
|
||||
}
|
||||
|
||||
void LoggerModel::enableVerbose(bool verbose) {
|
||||
if (mListener && mListener->mVerboseEnabled != verbose) {
|
||||
mListener->mVerboseEnabled = verbose;
|
||||
if (mVerboseEnabled != verbose) {
|
||||
mVerboseEnabled = verbose;
|
||||
emit verboseEnabledChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -62,24 +65,21 @@ void LoggerModel::enableFullLogs(const bool &full) {
|
|||
}
|
||||
|
||||
bool LoggerModel::qtOnlyEnabled() const {
|
||||
return mListener ? mListener->mQtOnlyEnabled : false;
|
||||
return mQtOnlyEnabled;
|
||||
}
|
||||
|
||||
void LoggerModel::enableQtOnly(const bool &enable) {
|
||||
if (mListener) {
|
||||
if (mListener->mQtOnlyEnabled != enable) {
|
||||
mListener->mQtOnlyEnabled = enable;
|
||||
if (mQtOnlyEnabled != enable) {
|
||||
mQtOnlyEnabled = enable;
|
||||
auto service = linphone::LoggingService::get();
|
||||
if (service) service->setDomain(enable ? Constants::AppDomain : "");
|
||||
emit qtOnlyEnabledChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Called from Qt
|
||||
void LoggerModel::onLog(QtMsgType type, QString contextFile, int contextLine, QString msg) {
|
||||
connect(this, &LoggerModel::logReceived, this, &LoggerModel::onLog, Qt::QueuedConnection);
|
||||
void LoggerModel::onQtLog(QtMsgType type, QString contextFile, int contextLine, QString msg) {
|
||||
auto service = linphone::LoggingService::get();
|
||||
QString contextStr = "";
|
||||
#ifdef QT_MESSAGELOGCONTEXT
|
||||
|
|
@ -116,6 +116,16 @@ void LoggerModel::onLog(QtMsgType type, QString contextFile, int contextLine, QS
|
|||
}
|
||||
}
|
||||
|
||||
// Call from Linphone
|
||||
void LoggerModel::onLinphoneLog(const std::shared_ptr<linphone::LoggingService> &,
|
||||
const std::string &domain,
|
||||
linphone::LogLevel level,
|
||||
const std::string &message) {
|
||||
bool isAppLog = domain == Constants::AppDomain;
|
||||
if (!mVerboseEnabled || (!isAppLog && mQtOnlyEnabled)) return;
|
||||
emit linphoneLogReceived(domain, level, message);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void LoggerModel::enable(bool status) {
|
||||
|
|
@ -134,7 +144,7 @@ void LoggerModel::init(const std::shared_ptr<linphone::Config> &config) {
|
|||
void LoggerModel::init() {
|
||||
QLoggingCategory::setFilterRules("qt.qml.connections.warning=false");
|
||||
mListener = std::make_shared<LoggerListener>();
|
||||
|
||||
connect(mListener.get(), &LoggerListener::logReceived, this, &LoggerModel::onLinphoneLog);
|
||||
{
|
||||
std::shared_ptr<linphone::LoggingService> loggingService = linphone::LoggingService::get();
|
||||
loggingService->setDomain(Constants::AppDomain);
|
||||
|
|
|
|||
|
|
@ -45,17 +45,22 @@ public:
|
|||
void init();
|
||||
void init(const std::shared_ptr<linphone::Config> &config);
|
||||
|
||||
static void onQtLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
public slots:
|
||||
void onLog(QtMsgType type, QString file, int contextLine, QString msg);
|
||||
|
||||
void onQtLog(QtMsgType type, QString file, int contextLine, QString msg);// Received from Qt
|
||||
void onLinphoneLog(const std::shared_ptr<linphone::LoggingService> &,
|
||||
const std::string &domain,
|
||||
linphone::LogLevel level,
|
||||
const std::string &message);// Received from SDK
|
||||
|
||||
signals:
|
||||
void logReceived(QtMsgType type, QString contextFile, int contextLine, QString msg);
|
||||
void linphoneLogReceived(const std::string &domain, linphone::LogLevel level, const std::string &message); // Send to Qt
|
||||
void verboseEnabledChanged();
|
||||
void qtOnlyEnabledChanged();
|
||||
|
||||
private:
|
||||
static void log(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
bool mVerboseEnabled = false;
|
||||
bool mQtOnlyEnabled = false;
|
||||
std::shared_ptr<LoggerListener> mListener;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue