From 523967580af1c769b1e53875a4b3d85fe9e35918 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Fri, 31 Jul 2015 17:04:32 +0100 Subject: [PATCH] Refactor handlers out of main reporting module. This will give us a clearer separation between the core reporting code (which shouldn't change very often) and the handler code (which is likely to change more often as we add new handlers and new features to existing handlers). It is also the first (baby) step on the path of making handlers pluggable so third-parties can easily drop their own in. Change-Id: I648df057d2ff719a2a81398afc80aaef9225ff5c --- .../{reporting.py => reporting/__init__.py} | 24 +----------------- cloudinit/reporting/handlers.py | 25 +++++++++++++++++++ cloudinit/tests/test_reporting.py | 17 +++++++------ 3 files changed, 35 insertions(+), 31 deletions(-) rename cloudinit/{reporting.py => reporting/__init__.py} (83%) create mode 100644 cloudinit/reporting/handlers.py diff --git a/cloudinit/reporting.py b/cloudinit/reporting/__init__.py similarity index 83% rename from cloudinit/reporting.py rename to cloudinit/reporting/__init__.py index d2dd4fec..b0364eec 100644 --- a/cloudinit/reporting.py +++ b/cloudinit/reporting/__init__.py @@ -9,10 +9,8 @@ The reporting framework is intended to allow all parts of cloud-init to report events in a structured manner. """ -import abc -import logging - from cloudinit.registry import DictRegistry +from cloudinit.reporting.handlers import available_handlers FINISH_EVENT_TYPE = 'finish' @@ -22,9 +20,7 @@ DEFAULT_CONFIG = { 'logging': {'type': 'log'}, } - instantiated_handler_registry = DictRegistry() -available_handlers = DictRegistry() class ReportingEvent(object): @@ -56,23 +52,6 @@ class FinishReportingEvent(ReportingEvent): self.event_type, self.name, success_string, self.description) -class ReportingHandler(object): - - @abc.abstractmethod - def publish_event(self, event): - raise NotImplementedError - - -class LogHandler(ReportingHandler): - """Publishes events to the cloud-init log at the ``INFO`` log level.""" - - def publish_event(self, event): - """Publish an event to the ``INFO`` log level.""" - logger = logging.getLogger( - '.'.join([__name__, event.event_type, event.name])) - logger.info(event.as_string()) - - def add_configuration(config): for handler_name, handler_config in config.items(): handler_config = handler_config.copy() @@ -118,5 +97,4 @@ def report_start_event(event_name, event_description): return report_event(event) -available_handlers.register_item('log', LogHandler) add_configuration(DEFAULT_CONFIG) diff --git a/cloudinit/reporting/handlers.py b/cloudinit/reporting/handlers.py new file mode 100644 index 00000000..be323f53 --- /dev/null +++ b/cloudinit/reporting/handlers.py @@ -0,0 +1,25 @@ +import abc +import logging + +from cloudinit.registry import DictRegistry + + +class ReportingHandler(object): + + @abc.abstractmethod + def publish_event(self, event): + raise NotImplementedError + + +class LogHandler(ReportingHandler): + """Publishes events to the cloud-init log at the ``INFO`` log level.""" + + def publish_event(self, event): + """Publish an event to the ``INFO`` log level.""" + logger = logging.getLogger( + '.'.join(['cloudinit', 'reporting', event.event_type, event.name])) + logger.info(event.as_string()) + + +available_handlers = DictRegistry() +available_handlers.register_item('log', LogHandler) diff --git a/cloudinit/tests/test_reporting.py b/cloudinit/tests/test_reporting.py index 24e1b96b..9c5d1c0b 100644 --- a/cloudinit/tests/test_reporting.py +++ b/cloudinit/tests/test_reporting.py @@ -4,6 +4,7 @@ # vi: ts=4 expandtab from cloudinit import reporting +from cloudinit.reporting import handlers from cloudinit.tests import TestCase from cloudinit.tests.util import mock @@ -95,31 +96,31 @@ class TestReportingHandler(TestCase): def test_no_default_publish_event_implementation(self): self.assertRaises(NotImplementedError, - reporting.ReportingHandler().publish_event, None) + handlers.ReportingHandler().publish_event, None) class TestLogHandler(TestCase): - @mock.patch.object(reporting.logging, 'getLogger') + @mock.patch.object(handlers.logging, 'getLogger') def test_appropriate_logger_used(self, getLogger): event_type, event_name = 'test_type', 'test_name' event = reporting.ReportingEvent(event_type, event_name, 'description') - reporting.LogHandler().publish_event(event) + handlers.LogHandler().publish_event(event) self.assertEqual( [mock.call( 'cloudinit.reporting.{0}.{1}'.format(event_type, event_name))], getLogger.call_args_list) - @mock.patch.object(reporting.logging, 'getLogger') + @mock.patch.object(handlers.logging, 'getLogger') def test_single_log_message_at_info_published(self, getLogger): event = reporting.ReportingEvent('type', 'name', 'description') - reporting.LogHandler().publish_event(event) + handlers.LogHandler().publish_event(event) self.assertEqual(1, getLogger.return_value.info.call_count) - @mock.patch.object(reporting.logging, 'getLogger') + @mock.patch.object(handlers.logging, 'getLogger') def test_log_message_uses_event_as_string(self, getLogger): event = reporting.ReportingEvent('type', 'name', 'description') - reporting.LogHandler().publish_event(event) + handlers.LogHandler().publish_event(event) self.assertIn(event.as_string(), getLogger.return_value.info.call_args[0][0]) @@ -130,7 +131,7 @@ class TestDefaultRegisteredHandler(TestCase): registered_items = ( reporting.instantiated_handler_registry.registered_items) for _, item in registered_items.items(): - if isinstance(item, reporting.LogHandler): + if isinstance(item, handlers.LogHandler): break else: self.fail('No reporting LogHandler registered by default.')