Commit be9dcf43 authored by Nick Draper's avatar Nick Draper
Browse files

Allow individual log level control for each channel

re #12703
parent 07f27f12
......@@ -20,6 +20,7 @@
//----------------------------------------------------------------------
/// @cond Exclude from doxygen documentation
namespace Poco {
class Channel;
namespace Util {
class PropertyFileConfiguration;
class SystemConfiguration;
......@@ -223,6 +224,14 @@ public:
/// Set the default facility
void setFacility(const std::string &facilityName);
///Sets the log level priority for the File log channel
void setFileLogLevel(int logLevel);
///Sets the log level priority for the Console log channel
void setConsoleLogLevel(int logLevel);
///Sets the log level priority for the selected Filter log channel
void setFilterChannelLogLevel(const std::string& filterChannelName, int logLevel);
/// Look for an instrument
const InstrumentInfo &
getInstrument(const std::string &instrumentName = "") const;
......@@ -262,7 +271,7 @@ private:
void loadConfig(const std::string &filename, const bool append = false);
/// Read a file and place its contents into the given string
bool readFile(const std::string &filename, std::string &contents) const;
/// Provies a string of a default configuration
/// Provides a string of a default configuration
std::string defaultConfig() const;
/// Writes out a fresh user properties file
void createUserPropertiesFile() const;
......
......@@ -59,8 +59,10 @@ public:
/// Returns the channel pointer.
Channel *getChannel() { return _channel; }
/// Attaches a channel, which may not be null.
/// set the priority cutoff by integer.
const FilterChannel &setPriority(const int &priority);
/// Set the priority cutoff by string.
const FilterChannel &setPriority(const std::string &priority);
/// Returns the integer representation of the priority
......
......@@ -9,6 +9,7 @@
#include <boost/lexical_cast.hpp>
#endif
#include <vector>
#include <set>
#include <map>
namespace Mantid {
......
......@@ -9,7 +9,7 @@
#include <Poco/Message.h>
#include <iosfwd>
#include <set>
#include <string>
//----------------------------------------------------------------------
......@@ -71,6 +71,8 @@ public:
// Our logger's priority types are the same as POCO's Message's types.
typedef Poco::Message::Priority Priority;
static const std::string* PriorityNames;
/// Constructor giving the logger name
Logger(const std::string &name);
/// Destructor
......@@ -104,6 +106,12 @@ public:
/// Logs at debug level
std::ostream &debug();
/// Log a message at a given priority
void log(const std::string &message, Logger::Priority priority);
/// gets the correct log stream for a priority
std::ostream &getLogStream(Logger::Priority priority);
/// Logs the given message at debug level, followed by the data in buffer.
void dump(const std::string &msg, const void *buffer, std::size_t length);
......@@ -146,10 +154,6 @@ private:
/// Disable assignment
Logger &operator=(const Logger &);
/// Log a message at a given priority
void log(const std::string &message, Logger::Priority priority);
/// gets the correct log stream for a priority
std::ostream &getLogStream(Logger::Priority priority);
/// Return a log stream set with the given priority
Priority applyLevelOffset(Priority proposedLevel);
......
......@@ -4,7 +4,6 @@
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/MantidVersion.h"
#include "MantidKernel/ParaViewVersion.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/Logger.h"
#include "MantidKernel/FilterChannel.h"
......@@ -29,6 +28,10 @@
#ifdef _WIN32
#pragma warning(disable : 4250)
#endif
#include <Poco/Logger.h>
#include <Poco/Channel.h>
#include <Poco/SplitterChannel.h>
#include <Poco/LoggingRegistry.h>
#include <Poco/PipeStream.h>
#include <Poco/StreamCopier.h>
......@@ -995,7 +998,7 @@ void ConfigServiceImpl::getKeysRecursive(const std::string &root,
}
}
/**
/**
* Recursively gets a list of all config options.
*
* This function is needed as Boost Python does not like calling function with
......@@ -1947,6 +1950,59 @@ Kernel::ProxyInfo &ConfigServiceImpl::getProxy(const std::string &url) {
return m_proxyInfo;
}
/** Sets the log level priority for the File log channel
* @logLevel the integer value of the log level to set, 1=Critical, 7=Debug
*/
void ConfigServiceImpl::setFileLogLevel(int logLevel)
{
setFilterChannelLogLevel("fileFilterChannel",logLevel);
}
/** Sets the log level priority for the Console log channel
* @logLevel the integer value of the log level to set, 1=Critical, 7=Debug
*/
void ConfigServiceImpl::setConsoleLogLevel(int logLevel)
{
setFilterChannelLogLevel("consoleFilterChannel",logLevel);
}
/** Sets the Log level for a filter channel
* @filterChannelName the channel name of the filter channel to change
* @logLevel the integer value of the log level to set, 1=Critical, 7=Debug
* @throws std::invalid_argument if the channel name is incorrect or it is not a filterChannel
*/
void ConfigServiceImpl::setFilterChannelLogLevel(const std::string& filterChannelName, int logLevel)
{
Poco::Channel* channel = NULL;
try
{
channel = Poco::LoggingRegistry::defaultRegistry().channelForName(filterChannelName);
}
catch(Poco::NotFoundException&)
{
throw std::invalid_argument(filterChannelName + " not found in the Logging Registry");
}
auto *filterChannel = dynamic_cast<Poco::FilterChannel*>(channel);
if (filterChannel)
{
filterChannel->setPriority(logLevel);
//set root level if required
int rootLevel = Poco::Logger::root().getLevel();
if (rootLevel < logLevel)
{
Mantid::Kernel::Logger::setLevelForAll(logLevel);
}
g_log.log(filterChannelName + " log channel set to " + Logger::PriorityNames[logLevel] + " priority",static_cast<Logger::Priority>(logLevel));
}
else
{
throw std::invalid_argument(filterChannelName + " was not a filter channel");
}
}
/// \cond TEMPLATE
template DLLExport int ConfigServiceImpl::getValue(const std::string &,
double &);
......
......@@ -50,6 +50,12 @@ void FilterChannel::close() {
}
}
const FilterChannel &FilterChannel::setPriority(const int &priority) {
_priority = priority;
return *this;
}
const FilterChannel &FilterChannel::setPriority(const std::string &priority) {
// take a local copy of the input
std::string workPriority = priority;
......
......@@ -24,6 +24,19 @@ namespace {
Poco::NullOutputStream NULL_STREAM;
}
static const std::string PriorityNames_data[] = {
"PRIO_FATAL",
"PRIO_CRITICAL",
"PRIO_ERROR",
"PRIO_WARNING",
"PRIO_NOTICE",
"PRIO_INFORMATION",
"PRIO_DEBUG",
"PRIO_TRACE"
};
const std::string* Logger::PriorityNames = PriorityNames_data;
/** Constructor
* @param name :: The class name invoking this logger
*/
......
......@@ -102,6 +102,16 @@ public:
TS_ASSERT_THROWS_NOTHING(log1.debug("a debug string with offset 999 should be trace"));
}
void testLogLevelFiltering()
{
TS_ASSERT_THROWS_NOTHING(ConfigService::Instance().setConsoleLogLevel(4));
TS_ASSERT_THROWS_NOTHING(ConfigService::Instance().setFileLogLevel(4));
TSM_ASSERT_THROWS("A false channel name for setFilterChannelLogLevel did not throw",
ConfigService::Instance().setFilterChannelLogLevel("AnIncorrectChannelName",4),std::invalid_argument);
TSM_ASSERT_THROWS("A correct channel name, but not a filterChannel for setFilterChannelLogLevel did not throw",
ConfigService::Instance().setFilterChannelLogLevel("consoleChannel",4),std::invalid_argument);
}
void testDefaultFacility()
{
TS_ASSERT_THROWS_NOTHING(ConfigService::Instance().getFacility() );
......
......@@ -145,19 +145,28 @@ graph1d.autodistribution = On
#AlgorithmChaining.SwitchedOn = 1
# logging configuration
# root level message filter (drop to debug for more messages)
# root level message filter (This sets a minimal level possible for any channel)
logging.loggers.root.level = notice
# splitting the messages to many logging channels
logging.loggers.root.channel.class = SplitterChannel
logging.loggers.root.channel.channel1 = consoleChannel
logging.loggers.root.channel.channel1 = consoleFilterChannel
logging.loggers.root.channel.channel2 = fileFilterChannel
# output to the console - primarily for console based apps
logging.channels.consoleChannel.class = ConsoleChannel
logging.channels.consoleChannel.formatter = f1
# specific filter for the console channel raising the level to notice (drop to debug for debugging)
logging.channels.consoleFilterChannel.class= FilterChannel
logging.channels.consoleFilterChannel.channel= consoleChannel
logging.channels.consoleFilterChannel.level= notice
# specific filter for the file channel raising the level to notice (drop to debug for debugging)
logging.channels.fileFilterChannel.class= FilterChannel
logging.channels.fileFilterChannel.channel= fileChannel
logging.channels.fileFilterChannel.level= notice
# output to the console - primarily for console based apps
logging.channels.consoleChannel.class = ConsoleChannel
logging.channels.consoleChannel.formatter = f1
# output to a file (For error capturing and debugging)
logging.channels.fileChannel.class = @FILECHANNEL@
logging.channels.fileChannel.path =
......@@ -165,10 +174,10 @@ logging.channels.fileChannel.rotation = 1 M
logging.channels.fileChannel.purgeCount = 9
logging.channels.fileChannel.formatter.class = PatternFormatter
logging.channels.fileChannel.formatter.pattern = %Y-%m-%d %H:%M:%S,%i [%I] %p %s - %t
logging.channels.fileChannel.formatter.times = local
logging.formatters.f1.class = PatternFormatter
logging.formatters.f1.pattern = @CONSOLEPATTERN@
logging.formatters.f1.times = local
logging.channels.fileChannel.formatter.times = local
workspace.sendto.SansView.arguments=[file]
workspace.sendto.SansView.saveusing=SaveCanSAS1D
......
......@@ -123,6 +123,12 @@ void export_ConfigService() {
"Saves the keys that have changed from their default to the given "
"filename")
.def("setFileLogLevel", &ConfigServiceImpl::setFileLogLevel,
"Sets the log level priority for the File log channel, logLevel 1 = Critical, 7 = Debug")
.def("setConsoleLogLevel", &ConfigServiceImpl::setConsoleLogLevel,
"Sets the log level priority for the Console log channel, logLevel 1 = Critical, 7 = Debug")
.def("keys", &ConfigServiceImpl::keys)
// Treat this as a dictionary
......
import unittest
import os
import testhelpers
from mantid.kernel import (ConfigService, ConfigServiceImpl, config,
std_vector_str, FacilityInfo, InstrumentInfo)
......@@ -89,8 +90,11 @@ class ConfigServiceTest(unittest.TestCase):
self.assertTrue('tmp' in paths[0])
self.assertTrue('tmp_2' in paths[1])
self._clean_up_test_areas()
def test_setting_log_channel_levels(self):
testhelpers.assertRaisesNothing(self, config.setFileLogLevel, 4)
testhelpers.assertRaisesNothing(self, config.setConsoleLogLevel, 4)
def _setup_test_areas(self):
"""Create a new data search path string
"""
......
......@@ -5,6 +5,7 @@
// Includes
//----------------------------------
#include "WidgetDllOption.h"
#include "MantidKernel/FilterChannel.h"
#include "MantidQtAPI/Message.h"
#include "MantidQtAPI/QtSignalChannel.h"
......@@ -120,6 +121,8 @@ namespace MantidQt
LogLevelControl m_logLevelControl;
/// A reference to the log channel
API::QtSignalChannel *m_logChannel;
/// A reference to the log channel
Poco::FilterChannel *m_filterChannel;
/// The actual widget holding the text
QPlainTextEdit * m_textDisplay;
/// Map priority to text formatting
......
......@@ -12,6 +12,7 @@
#include <QPlainTextEdit>
#include <QPoint>
#include <QScrollBar>
#include <QSettings>
#include <QSignalMapper>
#include <Poco/Logger.h>
......@@ -33,7 +34,7 @@ namespace MantidQt
* @param parent An optional parent widget
*/
MessageDisplay::MessageDisplay(QWidget *parent)
: QWidget(parent), m_logLevelControl(DisableLogLevelControl), m_logChannel(new API::QtSignalChannel),
: QWidget(parent), m_logLevelControl(DisableLogLevelControl), m_logChannel(new API::QtSignalChannel),m_filterChannel(new Poco::FilterChannel),
m_textDisplay(new QPlainTextEdit(this)), m_formats(), m_loglevels(new QActionGroup(this)), m_logLevelMapping(new QSignalMapper(this)),
m_error(new QAction(tr("&Error"), this)), m_warning(new QAction(tr("&Warning"), this)),
m_notice(new QAction(tr("&Notice"), this)), m_information(new QAction(tr("&Information"), this)),
......@@ -50,7 +51,7 @@ namespace MantidQt
* @param parent An optional parent widget
*/
MessageDisplay::MessageDisplay(LogLevelControl logLevelControl, QWidget *parent)
: QWidget(parent), m_logLevelControl(logLevelControl), m_logChannel(new API::QtSignalChannel),
: QWidget(parent), m_logLevelControl(logLevelControl), m_logChannel(new API::QtSignalChannel),m_filterChannel(new Poco::FilterChannel),
m_textDisplay(new QPlainTextEdit(this)), m_loglevels(new QActionGroup(this)), m_logLevelMapping(new QSignalMapper(this)),
m_error(new QAction(tr("&Error"), this)), m_warning(new QAction(tr("&Warning"), this)),
m_notice(new QAction(tr("&Notice"), this)), m_information(new QAction(tr("&Information"), this)),
......@@ -65,8 +66,11 @@ namespace MantidQt
*/
MessageDisplay::~MessageDisplay()
{
QSettings settings;
settings.writeEntry("MessageDisplayPriority", static_cast <int>(m_filterChannel->getPriority()));
// The Channel class is ref counted and will
// delete itself when required
m_filterChannel->release();
m_logChannel->release();
delete m_textDisplay;
}
......@@ -83,12 +87,17 @@ namespace MantidQt
// The root channel might be a SplitterChannel
if(auto *splitChannel = dynamic_cast<Poco::SplitterChannel*>(rootChannel))
{
splitChannel->addChannel(m_logChannel);
splitChannel->addChannel(m_filterChannel);
}
else
{
Poco::Logger::setChannel(rootLogger.name(), m_logChannel);
Poco::Logger::setChannel(rootLogger.name(), m_filterChannel);
}
m_filterChannel->addChannel(m_logChannel);
QSettings settings;
int priority = settings.readNumEntry("MessageDisplayPriority", Message::Priority::PRIO_NOTICE);
m_filterChannel->setPriority(priority);
connect(m_logChannel, SIGNAL(messageReceived(const Message&)),
this, SLOT(append(const Message &)));
......@@ -254,7 +263,13 @@ namespace MantidQt
logLevelMenu->addAction(m_debug);
//check the right level
int level = Mantid::Kernel::Logger("").getLevel(); //get the root logger logging level
int level = m_filterChannel->getPriority();
//get the root logger logging level
int rootLevel = Poco::Logger::root().getLevel();
if (rootLevel < level) {
level = rootLevel;
}
if (level == Poco::Message::PRIO_ERROR)
m_error->setChecked(true);
if (level == Poco::Message::PRIO_WARNING)
......@@ -263,7 +278,7 @@ namespace MantidQt
m_notice->setChecked(true);
if (level == Poco::Message::PRIO_INFORMATION)
m_information->setChecked(true);
if (level == Poco::Message::PRIO_DEBUG)
if (level >= Poco::Message::PRIO_DEBUG)
m_debug->setChecked(true);
}
......@@ -277,7 +292,14 @@ namespace MantidQt
*/
void MessageDisplay::setGlobalLogLevel(int priority)
{
Mantid::Kernel::Logger::setLevelForAll(priority);
//set Local filter level
m_filterChannel->setPriority(priority);
//if this is higher than the global level then that will have to be lowered to work
int rootLevel = Poco::Logger::root().getLevel();
if (rootLevel < priority)
{
Mantid::Kernel::Logger::setLevelForAll(priority);
}
}
//-----------------------------------------------------------------------------
......@@ -311,7 +333,7 @@ namespace MantidQt
connect(m_information, SIGNAL(activated()), m_logLevelMapping, SLOT (map()));
connect(m_debug, SIGNAL(activated()), m_logLevelMapping, SLOT (map()));
connect(m_logLevelMapping, SIGNAL(mapped(int)), m_logChannel, SLOT(setGlobalLogLevel(int)));
connect(m_logLevelMapping, SIGNAL(mapped(int)), this, SLOT(setGlobalLogLevel(int)));
}
/**
......
......@@ -96,15 +96,21 @@ Directory Properties
Logging Properties
******************
The details of configuring the logging functionality within Mantid will not be explained here. For those who want more details look into the POCO logging classes and the Log4J logging module that it closely emulates. There are several comments in the properties file itself that explain the configuration we provide by default.However there are some obvious areas that you may want to alter and those properties are detailed below.
The details of configuring the logging functionality within Mantid will not be explained here.
For those who want more details look into the POCO logging classes and the Log4J logging module
that it closely emulates. There are several comments in the properties file itself that explain
the configuration we provide by default. However there are some obvious areas that you may want
to alter and those properties are detailed below.
+----------------------------------------+---------------------------------------------------+-----------------------+
|Property |Description |Example value |
+========================================+===================================================+=======================+
|logging.loggers.root.level |Defines the lowest level of messages to be output |debug, informtion, |
| |by the system. The default is information, but this|notice, warning, |
| |can be lowered to debug for more detailed feedback.|error, critical |
| | |or fatal |
| |by the system, and will override lower settings in |notice, warning, |
| |filterChannels. The default is information, but |error, critical |
| |this can be lowered to debug for more detailed |or fatal |
| |feedback. | |
| | | |
+----------------------------------------+---------------------------------------------------+-----------------------+
|logging.channels.fileFilterChannel.level|The lowest level messages to output to the log |debug, informtion, |
| |file. The default is warning, but this can be |notice, warning, |
......@@ -114,6 +120,18 @@ The details of configuring the logging functionality within Mantid will not be e
+----------------------------------------+---------------------------------------------------+-----------------------+
|logging.channels.fileChannel.path | The Path to the log file. |../logs/mantid.log |
+----------------------------------------+---------------------------------------------------+-----------------------+
The logging priority levels for the file logging and console logging can also be adjusted in python using the commands:
.. testcode:: LoggingConfigExample
#Set the console to log at debug level on above (7=debug)
ConfigService.setConsoleLogLevel(7)
#Set the file to only log at critical level (1=critical)
ConfigService.setConsoleLogLevel(7)
.. testoutput:: AddSampleLogExample
MantidPlot Properties
*********************
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment