Skip to content

Commit

Permalink
Merge pull request #7814 from elemoine/ele_logging
Browse files Browse the repository at this point in the history
Support QGIS Server logs to stderr
  • Loading branch information
pblottiere committed Sep 14, 2018
2 parents a78a7e7 + 9eaee8f commit 2e91c29
Show file tree
Hide file tree
Showing 13 changed files with 299 additions and 48 deletions.
31 changes: 28 additions & 3 deletions python/core/auto_generated/qgsmessagelog.sip.in
Expand Up @@ -107,18 +107,43 @@ class QgsMessageLogConsole : QObject
%Docstring
Default implementation of message logging interface

This class outputs log messages to the standard output. Therefore it might
be the right choice for apps without GUI.
This class outputs log messages to the standard error. Therefore it might
be the right choice for applications without GUI.
%End

%TypeHeaderCode
#include "qgsmessagelog.h"
%End
public:

QgsMessageLogConsole();
%Docstring
Constructor for QgsMessageLogConsole.
%End

protected:

QString formatLogMessage( const QString &message, const QString &tag, Qgis::MessageLevel level = Qgis::Info ) const;
%Docstring
Formats a log message. Used by child classes.

:param message: the message to format
:param tag: the tag of the message
:param level: the log level of the message

.. versionadded:: 3.4
%End

public slots:
void logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level );

virtual void logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level );
%Docstring
Logs a message to stderr.

:param message: the message to format
:param tag: the tag of the message
:param level: the log level of the message
%End
};

/************************************************************************
Expand Down
85 changes: 85 additions & 0 deletions python/server/auto_generated/qgsserverlogger.sip.in
@@ -0,0 +1,85 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/server/qgsserverlogger.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/






class QgsServerLogger : QgsMessageLogConsole
{
%Docstring
Writes message log into server logfile

.. versionadded:: 2.8
%End

%TypeHeaderCode
#include "qgsserverlogger.h"
%End
public:

static QgsServerLogger *instance();
%Docstring
Gets the singleton instance
%End

Qgis::MessageLevel logLevel() const;
%Docstring
Gets the current log level

:return: the log level

.. versionadded:: 3.0
%End

void setLogLevel( Qgis::MessageLevel level );
%Docstring
Set the current log level

:param level: the log level

.. versionadded:: 3.0
%End

void setLogFile( const QString &filename = QString() );
%Docstring
Set the current log file
%End

void setLogStderr();
%Docstring
Activates logging to stderr.

.. versionadded:: 3.4.
%End

public slots:

virtual void logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level );

%Docstring
Log a message from the server context

:param message: the message
:param tag: tag of the message
:param level: log level of the message
%End

protected:
QgsServerLogger();

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/server/qgsserverlogger.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
9 changes: 9 additions & 0 deletions python/server/auto_generated/qgsserversettings.sip.in
Expand Up @@ -94,6 +94,15 @@ Returns the QGS project file to use.
Returns the log file.

:return: the path of the log file or an empty string if none is defined.
%End

bool logStderr() const;
%Docstring
Returns whether logging to stderr is activated.

:return: true if logging to stderr is activated, false otherwise.

.. versionadded:: 3.4
%End

qint64 cacheSize() const;
Expand Down
1 change: 1 addition & 0 deletions python/server/server_auto.sip
Expand Up @@ -3,6 +3,7 @@
%Include auto_generated/qgsmapserviceexception.sip
%Include auto_generated/qgscapabilitiescache.sip
%Include auto_generated/qgsconfigcache.sip
%Include auto_generated/qgsserverlogger.sip
%Include auto_generated/qgsserversettings.sip
%Include auto_generated/qgsserverparameters.sip
%Include auto_generated/qgsbufferserverrequest.sip
Expand Down
21 changes: 15 additions & 6 deletions src/core/qgsmessagelog.cpp
Expand Up @@ -18,7 +18,9 @@
#include "qgslogger.h"
#include <QDateTime>
#include <QMetaType>
#include <QTextStream>
#include <iostream>
#include <stdio.h>

class QgsMessageLogConsole;

Expand Down Expand Up @@ -47,12 +49,19 @@ QgsMessageLogConsole::QgsMessageLogConsole()

void QgsMessageLogConsole::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level )
{
std::cerr
<< tag.toLocal8Bit().data() << "[" <<
( level == Qgis::Info ? "INFO"
: level == Qgis::Warning ? "WARNING"
: "CRITICAL" )
<< "]: " << message.toLocal8Bit().data() << std::endl;
QString formattedMessage = formatLogMessage( message, tag, level );
QTextStream cerr( stderr );
cerr << formattedMessage;
}

QString QgsMessageLogConsole::formatLogMessage( const QString &message, const QString &tag, Qgis::MessageLevel level ) const
{
const QString time = QTime::currentTime().toString();
const QString levelStr = level == Qgis::Info ? QStringLiteral( "INFO" ) :
level == Qgis::Warning ? QStringLiteral( "WARNING" ) :
QStringLiteral( "CRITICAL" );
const QString pid = QString::number( QCoreApplication::applicationPid() );
return QStringLiteral( "%1 %2 %3[%4]: %5\n" ).arg( time, levelStr, tag, pid, message );
}

//
Expand Down
36 changes: 30 additions & 6 deletions src/core/qgsmessagelog.h
Expand Up @@ -128,20 +128,44 @@ class CORE_EXPORT QgsMessageLogNotifyBlocker

/**
* \ingroup core
\brief Default implementation of message logging interface
This class outputs log messages to the standard output. Therefore it might
be the right choice for apps without GUI.
*/
* \brief Default implementation of message logging interface
*
* This class outputs log messages to the standard error. Therefore it might
* be the right choice for applications without GUI.
*/
class CORE_EXPORT QgsMessageLogConsole : public QObject
{
Q_OBJECT

public:

/**
* Constructor for QgsMessageLogConsole.
*/
QgsMessageLogConsole();

protected:

/**
* Formats a log message. Used by child classes.
*
* \param message the message to format
* \param tag the tag of the message
* \param level the log level of the message
* \since QGIS 3.4
*/
QString formatLogMessage( const QString &message, const QString &tag, Qgis::MessageLevel level = Qgis::Info ) const;

public slots:
void logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level );

/**
* Logs a message to stderr.
*
* \param message the message to format
* \param tag the tag of the message
* \param level the log level of the message
*/
virtual void logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level );
};

#endif
9 changes: 8 additions & 1 deletion src/server/qgsserver.cpp
Expand Up @@ -186,7 +186,14 @@ bool QgsServer::init()
// init and configure logger
QgsServerLogger::instance();
QgsServerLogger::instance()->setLogLevel( sSettings.logLevel() );
QgsServerLogger::instance()->setLogFile( sSettings.logFile() );
if ( ! sSettings.logFile().isEmpty() )
{
QgsServerLogger::instance()->setLogFile( sSettings.logFile() );
}
else if ( sSettings.logStderr() )
{
QgsServerLogger::instance()->setLogStderr();
}

// log settings currently used
sSettings.logSummary();
Expand Down
57 changes: 30 additions & 27 deletions src/server/qgsserverlogger.cpp
Expand Up @@ -36,44 +36,47 @@ QgsServerLogger *QgsServerLogger::instance()
}

QgsServerLogger::QgsServerLogger()
: mLogFile( nullptr )
: QgsMessageLogConsole()
{
connect( QgsApplication::messageLog(), static_cast<void ( QgsMessageLog::* )( const QString &, const QString &, Qgis::MessageLevel )>( &QgsMessageLog::messageReceived ), this,
&QgsServerLogger::logMessage );
}

void QgsServerLogger::setLogLevel( Qgis::MessageLevel level )
void QgsServerLogger::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level )
{
mLogLevel = level;
if ( mLogLevel > level )
{
return;
}
if ( mLogFile.isOpen() )
{
QString formattedMessage = formatLogMessage( message, tag, level );
mTextStream << formattedMessage;
mTextStream.flush();
}
else if ( mLogStderr )
{
QgsMessageLogConsole::logMessage( message, tag, level );
}
}

void QgsServerLogger::setLogFile( const QString &f )
void QgsServerLogger::setLogLevel( const Qgis::MessageLevel level )
{
if ( ! f.isEmpty() )
{
if ( mLogFile.exists() )
{
mTextStream.flush();
mLogFile.close();
}

mLogFile.setFileName( f );
if ( mLogFile.open( QIODevice::Append ) )
{
mTextStream.setDevice( &mLogFile );
}
}
mLogLevel = level;
}

void QgsServerLogger::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level )
void QgsServerLogger::setLogFile( const QString &filename )
{
Q_UNUSED( tag );
if ( !mLogFile.isOpen() || mLogLevel > level )
mTextStream.flush();
mLogFile.close();
mLogFile.setFileName( filename );

if ( ( ! filename.isEmpty() ) && mLogFile.open( QIODevice::Append ) )
{
return;
mTextStream.setDevice( &mLogFile );
}
}

mTextStream << ( "[" + QString::number( qlonglong( QCoreApplication::applicationPid() ) ) + "]["
+ QTime::currentTime().toString() + "] " + message + "\n" );
mTextStream.flush();
void QgsServerLogger::setLogStderr()
{
setLogFile();
mLogStderr = true;
}
16 changes: 11 additions & 5 deletions src/server/qgsserverlogger.h
Expand Up @@ -18,22 +18,21 @@
#ifndef QGSSERVERLOGGER_H
#define QGSSERVERLOGGER_H

#define SIP_NO_FILE


#include "qgsmessagelog.h"

#include <QFile>
#include <QObject>
#include <QString>
#include <QTextStream>
#include "qgis_server.h"

/**
* \ingroup server
* \brief Writes message log into server logfile
* \since QGIS 2.8
*/
class QgsServerLogger: public QObject
class SERVER_EXPORT QgsServerLogger : public QgsMessageLogConsole
{
Q_OBJECT
public:
Expand All @@ -60,7 +59,13 @@ class QgsServerLogger: public QObject
/**
* Set the current log file
*/
void setLogFile( const QString &f );
void setLogFile( const QString &filename = QString() );

/**
* Activates logging to stderr.
* \since QGIS 3.4.
*/
void setLogStderr();

public slots:

Expand All @@ -71,7 +76,7 @@ class QgsServerLogger: public QObject
* \param tag tag of the message
* \param level log level of the message
*/
void logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level );
void logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level ) override;

protected:
QgsServerLogger();
Expand All @@ -80,6 +85,7 @@ class QgsServerLogger: public QObject
static QgsServerLogger *sInstance;

QFile mLogFile;
bool mLogStderr = false;
QTextStream mTextStream;
Qgis::MessageLevel mLogLevel = Qgis::None;
};
Expand Down

0 comments on commit 2e91c29

Please sign in to comment.