mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-15 00:02:52 -04:00
Merge pull request #7814 from elemoine/ele_logging
Support QGIS Server logs to stderr
This commit is contained in:
commit
2e91c29dff
@ -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
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
|
85
python/server/auto_generated/qgsserverlogger.sip.in
Normal file
85
python/server/auto_generated/qgsserverlogger.sip.in
Normal file
@ -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 *
|
||||
************************************************************************/
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -18,7 +18,9 @@
|
||||
#include "qgslogger.h"
|
||||
#include <QDateTime>
|
||||
#include <QMetaType>
|
||||
#include <QTextStream>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
class QgsMessageLogConsole;
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 )
|
||||
{
|
||||
mLogLevel = level;
|
||||
}
|
||||
|
||||
void QgsServerLogger::setLogFile( const QString &f )
|
||||
{
|
||||
if ( ! f.isEmpty() )
|
||||
{
|
||||
if ( mLogFile.exists() )
|
||||
{
|
||||
mTextStream.flush();
|
||||
mLogFile.close();
|
||||
}
|
||||
|
||||
mLogFile.setFileName( f );
|
||||
if ( mLogFile.open( QIODevice::Append ) )
|
||||
{
|
||||
mTextStream.setDevice( &mLogFile );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsServerLogger::logMessage( const QString &message, const QString &tag, Qgis::MessageLevel level )
|
||||
{
|
||||
Q_UNUSED( tag );
|
||||
if ( !mLogFile.isOpen() || mLogLevel > level )
|
||||
if ( mLogLevel > level )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mTextStream << ( "[" + QString::number( qlonglong( QCoreApplication::applicationPid() ) ) + "]["
|
||||
+ QTime::currentTime().toString() + "] " + message + "\n" );
|
||||
mTextStream.flush();
|
||||
if ( mLogFile.isOpen() )
|
||||
{
|
||||
QString formattedMessage = formatLogMessage( message, tag, level );
|
||||
mTextStream << formattedMessage;
|
||||
mTextStream.flush();
|
||||
}
|
||||
else if ( mLogStderr )
|
||||
{
|
||||
QgsMessageLogConsole::logMessage( message, tag, level );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsServerLogger::setLogLevel( const Qgis::MessageLevel level )
|
||||
{
|
||||
mLogLevel = level;
|
||||
}
|
||||
|
||||
void QgsServerLogger::setLogFile( const QString &filename )
|
||||
{
|
||||
mTextStream.flush();
|
||||
mLogFile.close();
|
||||
mLogFile.setFileName( filename );
|
||||
|
||||
if ( ( ! filename.isEmpty() ) && mLogFile.open( QIODevice::Append ) )
|
||||
{
|
||||
mTextStream.setDevice( &mLogFile );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsServerLogger::setLogStderr()
|
||||
{
|
||||
setLogFile();
|
||||
mLogStderr = true;
|
||||
}
|
||||
|
@ -18,8 +18,6 @@
|
||||
#ifndef QGSSERVERLOGGER_H
|
||||
#define QGSSERVERLOGGER_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
|
||||
#include "qgsmessagelog.h"
|
||||
|
||||
@ -27,13 +25,14 @@
|
||||
#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:
|
||||
@ -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:
|
||||
|
||||
@ -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();
|
||||
@ -80,6 +85,7 @@ class QgsServerLogger: public QObject
|
||||
static QgsServerLogger *sInstance;
|
||||
|
||||
QFile mLogFile;
|
||||
bool mLogStderr = false;
|
||||
QTextStream mTextStream;
|
||||
Qgis::MessageLevel mLogLevel = Qgis::None;
|
||||
};
|
||||
|
@ -87,6 +87,17 @@ void QgsServerSettings::initSettings()
|
||||
};
|
||||
mSettings[ sLogFile.envVar ] = sLogFile;
|
||||
|
||||
// log to stderr
|
||||
const Setting sLogStderr = { QgsServerSettingsEnv::QGIS_SERVER_LOG_STDERR,
|
||||
QgsServerSettingsEnv::DEFAULT_VALUE,
|
||||
"Activate/Deactivate logging to stderr",
|
||||
"",
|
||||
QVariant::Bool,
|
||||
QVariant( false ),
|
||||
QVariant()
|
||||
};
|
||||
mSettings[ sLogStderr.envVar ] = sLogStderr;
|
||||
|
||||
// project file
|
||||
const Setting sProject = { QgsServerSettingsEnv::QGIS_PROJECT_FILE,
|
||||
QgsServerSettingsEnv::DEFAULT_VALUE,
|
||||
@ -281,6 +292,11 @@ QString QgsServerSettings::logFile() const
|
||||
return value( QgsServerSettingsEnv::QGIS_SERVER_LOG_FILE ).toString();
|
||||
}
|
||||
|
||||
bool QgsServerSettings::logStderr() const
|
||||
{
|
||||
return value( QgsServerSettingsEnv::QGIS_SERVER_LOG_STDERR ).toBool();
|
||||
}
|
||||
|
||||
Qgis::MessageLevel QgsServerSettings::logLevel() const
|
||||
{
|
||||
return static_cast<Qgis::MessageLevel>( value( QgsServerSettingsEnv::QGIS_SERVER_LOG_LEVEL ).toInt() );
|
||||
|
@ -56,6 +56,7 @@ class SERVER_EXPORT QgsServerSettingsEnv : public QObject
|
||||
QGIS_SERVER_MAX_THREADS,
|
||||
QGIS_SERVER_LOG_LEVEL,
|
||||
QGIS_SERVER_LOG_FILE,
|
||||
QGIS_SERVER_LOG_STDERR,
|
||||
QGIS_PROJECT_FILE,
|
||||
MAX_CACHE_LAYERS,
|
||||
QGIS_SERVER_CACHE_DIRECTORY,
|
||||
@ -148,6 +149,13 @@ class SERVER_EXPORT QgsServerSettings
|
||||
*/
|
||||
QString logFile() const;
|
||||
|
||||
/**
|
||||
* Returns whether logging to stderr is activated.
|
||||
* \returns true if logging to stderr is activated, false otherwise.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
bool logStderr() const;
|
||||
|
||||
/**
|
||||
* Returns the cache size.
|
||||
* \returns the cache size.
|
||||
|
@ -257,6 +257,7 @@ ENDIF (ENABLE_ORACLETEST)
|
||||
|
||||
IF (WITH_SERVER)
|
||||
ADD_PYTHON_TEST(PyQgsServer test_qgsserver.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerLogger test_qgsserverlogger.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerPlugins test_qgsserver_plugins.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerWMS test_qgsserver_wms.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerWMSGetMap test_qgsserver_wms_getmap.py)
|
||||
|
57
tests/src/python/test_qgsserverlogger.py
Normal file
57
tests/src/python/test_qgsserverlogger.py
Normal file
@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsServerLogger.
|
||||
"""
|
||||
__author__ = 'Eric Lemoine'
|
||||
__date__ = '11/09/2018'
|
||||
__copyright__ = 'Copyright 2018, The QGIS Project'
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
from qgis.testing import unittest
|
||||
from qgis.server import QgsServerLogger
|
||||
|
||||
from utilities import unitTestDataPath
|
||||
|
||||
|
||||
class TestQgsServerLogger(unittest.TestCase):
|
||||
|
||||
log_file = os.path.join(unitTestDataPath('qgis_server'), 'qgis_server_test.log')
|
||||
|
||||
@staticmethod
|
||||
def remove_file(filename):
|
||||
try:
|
||||
os.remove(filename)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def setUp(self):
|
||||
self.logger = QgsServerLogger.instance()
|
||||
self.logger.setLogLevel(0)
|
||||
self.logger.setLogFile(self.log_file)
|
||||
exists = os.access(self.log_file, os.R_OK)
|
||||
self.assertTrue(exists)
|
||||
self.remove_file(self.log_file)
|
||||
|
||||
def tearDown(self):
|
||||
self.remove_file(self.log_file)
|
||||
|
||||
def test_logging_no_log_file(self):
|
||||
self.logger.setLogFile('')
|
||||
exists = os.access(self.log_file, os.R_OK)
|
||||
self.assertFalse(exists)
|
||||
|
||||
def test_logging_log_file(self):
|
||||
self.logger.setLogFile(self.log_file)
|
||||
exists = os.access(self.log_file, os.R_OK)
|
||||
self.assertTrue(exists)
|
||||
|
||||
def test_logging_log_file_stderr(self):
|
||||
self.logger.setLogFile('stderr')
|
||||
exists = os.access(self.log_file, os.R_OK)
|
||||
self.assertFalse(exists)
|
||||
|
||||
def test_logging_stderr(self):
|
||||
self.logger.setLogStderr()
|
||||
exists = os.access(self.log_file, os.R_OK)
|
||||
self.assertFalse(exists)
|
Loading…
x
Reference in New Issue
Block a user