Revision: 004b5ff3ac8e
Author: Pekka Klärck
Date: Tue May 17 14:28:11 2011
Log: Support for Pytho's standard `logging` module
Update issue 455
Status: Started
Owner: pekka.klarck
I implemented the support for the logging module by propogating messages
received by the root logger to new robot.api.logger (issue 339).
Chris, could you take a look at the implementation and, if possible,
checkout
the latest version and test this?
http://code.google.com/p/robotframework/source/detail?r=004b5ff3ac8e
Added:
/atest/robot/test_libraries/logging_with_logging.txt
/atest/testdata/test_libraries/LibUsingPyLogging.py
/atest/testdata/test_libraries/logging_with_logging.txt
/src/robot/output/pyloggingconf.py
Modified:
/src/robot/__init__.py
=======================================
--- /dev/null
+++ /atest/robot/test_libraries/logging_with_logging.txt Tue May 17
14:28:11 2011
@@ -0,0 +1,42 @@
+*** Settings ***
+Documentation Tests for logging using Python's `logging` module.
+Suite Setup Run Tests ${EMPTY}
test_libraries/logging_with_logging.txt
+Force Tags regression pybot jybot
+Resource atest_resource.txt
+
+*** Test Cases ***
+
+Log with default levels
+ ${tc} = Check test case ${TEST NAME}
+ Check log message ${tc.kws[0].msgs[0]} debug message DEBUG
+ Check log message ${tc.kws[0].msgs[1]} info message INFO
+ Check log message ${tc.kws[0].msgs[2]} warning message WARN
+ Check log message ${tc.kws[0].msgs[3]} error message WARN
+ Check log message ${tc.kws[0].msgs[4]} critical message WARN
+ Check log message ${ERRORS.msgs[0]} warning message WARN
+ Check log message ${ERRORS.msgs[1]} error message WARN
+ Check log message ${ERRORS.msgs[2]} critical message WARN
+
+Log with custom levels
+ ${tc} = Check test case ${TEST NAME}
+ Check log message ${tc.kws[0].msgs[0]} below debug
DEBUG
+ Check log message ${tc.kws[0].msgs[1]} between debug and info INFO
+ Check log message ${tc.kws[0].msgs[2]} between info and warning INFO
+ Check log message ${tc.kws[0].msgs[3]} above warning WARN
+
+Log using custom logger
+ ${tc} = Check test case ${TEST NAME}
+ Check log message ${tc.kws[0].msgs[0]} custom logger
+ Check stdout contains Custom Logger
+
+Log using non-propagating logger
+ ${tc} = Check test case ${TEST NAME}
+ Should be empty ${tc.kws[0].msgs}
+ Check stdout contains Nonprop Logger
+
+Timestamps are accurate
+ ${tc} = Check test case ${TEST NAME}
+ ${msg1} ${msg2} = Set variable ${tc.kws[0].msgs}
+ Check log message ${msg1} First message
+ Check log message ${msg2} Second message 0.1 sec later
+ Should be true '${msg1.timestamp}' < '${msg2.timestamp}'
=======================================
--- /dev/null
+++ /atest/testdata/test_libraries/LibUsingPyLogging.py Tue May 17 14:28:11
2011
@@ -0,0 +1,42 @@
+import logging
+import time
+import sys
+
+
+class CustomHandler(logging.Handler):
+
+ def emit(self, record):
+ sys.__stdout__.write(record.getMessage().title() + '\n')
+
+
+custom = logging.getLogger('custom')
+custom.addHandler(CustomHandler())
+nonprop = logging.getLogger('nonprop')
+nonprop.propagate = False
+nonprop.addHandler(CustomHandler())
+
+
+def log_with_default_levels():
+ logging.debug('debug message')
+ logging.info('%s %s', 'info', 'message')
+ logging.warning('warning message')
+ # error and critical are considered warnings
+ logging.error('error message')
+ logging.critical('critical message')
+
+def log_with_custom_levels():
+ logging.log(logging.DEBUG-1, 'below debug')
+ logging.log(logging.INFO-1, 'between debug and info')
+ logging.log(logging.INFO+1, 'between info and warning')
+ logging.log(logging.WARNING*100, 'above warning')
+
+def log_using_custom_logger():
+ logging.getLogger('custom').info('custom logger')
+
+def log_using_non_propagating_logger():
+ logging.getLogger('nonprop').info('nonprop logger')
+
+def log_messages_different_time():
+ logging.info('First message')
+ time.sleep(0.1)
+ logging.info('Second message 0.1 sec later')
=======================================
--- /dev/null
+++ /atest/testdata/test_libraries/logging_with_logging.txt Tue May 17
14:28:11 2011
@@ -0,0 +1,22 @@
+*** Settings ***
+Documentation Tests for logging using Python's `logging` module.
+Library LibUsingPyLogging.py
+Suite Setup Set log level DEBUG
+Suite Teardown Set log level INFO
+
+*** Test Cases ***
+
+Log with default levels
+ Log with default levels
+
+Log with custom levels
+ Log with custom levels
+
+Log using custom logger
+ Log using custom logger
+
+Log using non-propagating logger
+ Log using non propagating logger
+
+Timestamps are accurate
+ Log messages different time
=======================================
--- /dev/null
+++ /src/robot/output/pyloggingconf.py Tue May 17 14:28:11 2011
@@ -0,0 +1,52 @@
+# Copyright 2008-2011 Nokia Siemens Networks Oyj
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module to configure Python's standard `logging` module.
+
+After this module is imported, messages logged with `logging` module
+are, by defaul, propagated to Robot's log file.
+"""
+
+import logging
+
+from robot.api import logger
+
+
+class RobotHandler(logging.Handler):
+
+ def emit(self, record):
+ self._get_logger_method(record.levelno)(record.getMessage())
+
+ def _get_logger_method(self, level):
+ if level >= logging.WARNING:
+ return logger.warn
+ if level <= logging.DEBUG:
+ return logger.debug
+ return logger.info
+
+
+class NullStream(object):
+
+ def write(self, message):
+ pass
+
+ def close(self):
+ pass
+
+ def flush(self):
+ pass
+
+
+logging.basicConfig(level=logging.NOTSET, stream=NullStream())
+logging.getLogger().addHandler(RobotHandler())
=======================================
--- /src/robot/__init__.py Mon Apr 18 21:30:37 2011
+++ /src/robot/__init__.py Tue May 17 14:28:11 2011
@@ -41,7 +41,7 @@
if 'pythonpathsetter' not in sys.modules:
import pythonpathsetter
-from output import Output, LOGGER
+from output import Output, LOGGER, pyloggingconf
from conf import RobotSettings, RebotSettings
from running import TestSuite, STOP_SIGNAL_MONITOR
from serializing import RobotTestOutput, RebotTestOutput,
SplitIndexTestOutput