Skip to content
This repository was archived by the owner on Sep 26, 2019. It is now read-only.

Commit af67132

Browse files
author
Daniel Watkins
committed
Make reporting handlers configurable.
And configure the LogHandler by default. Change-Id: Ic3a1cebbe8684033fb8d46bf4baebb55a43fc890
1 parent b5f5a16 commit af67132

File tree

2 files changed

+94
-16
lines changed

2 files changed

+94
-16
lines changed

cloudinit/reporting.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
FINISH_EVENT_TYPE = 'finish'
1919
START_EVENT_TYPE = 'start'
2020

21+
DEFAULT_CONFIG = {
22+
'logging': {'type': 'log'},
23+
}
24+
25+
26+
instantiated_handler_registry = DictRegistry()
27+
available_handlers = DictRegistry()
28+
2129

2230
class ReportingEvent(object):
2331
"""Encapsulation of event formatting."""
@@ -65,8 +73,12 @@ def publish_event(self, event):
6573
logger.info(event.as_string())
6674

6775

68-
handler_registry = DictRegistry()
69-
handler_registry.register_item('_logging', LogHandler())
76+
def add_configuration(config):
77+
for handler_name, handler_config in config.items():
78+
handler_config = handler_config.copy()
79+
cls = available_handlers.registered_items[handler_config.pop('type')]
80+
instance = cls(**handler_config)
81+
instantiated_handler_registry.register_item(handler_name, instance)
7082

7183

7284
def report_event(event):
@@ -79,7 +91,7 @@ def report_event(event):
7991
The type of the event; this should be a constant from the
8092
reporting module.
8193
"""
82-
for _, handler in handler_registry.registered_items.items():
94+
for _, handler in instantiated_handler_registry.registered_items.items():
8395
handler.publish_event(event)
8496

8597

@@ -104,3 +116,7 @@ def report_start_event(event_name, event_description):
104116
"""
105117
event = ReportingEvent(START_EVENT_TYPE, event_name, event_description)
106118
return report_event(event)
119+
120+
121+
available_handlers.register_item('log', LogHandler)
122+
add_configuration(DEFAULT_CONFIG)

cloudinit/tests/test_reporting.py

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ def _fake_registry():
1717

1818
class TestReportStartEvent(unittest.TestCase):
1919

20-
@mock.patch('cloudinit.reporting.handler_registry',
20+
@mock.patch('cloudinit.reporting.instantiated_handler_registry',
2121
new_callable=_fake_registry)
2222
def test_report_start_event_passes_something_with_as_string_to_handlers(
23-
self, handler_registry):
23+
self, instantiated_handler_registry):
2424
event_name, event_description = 'my_test_event', 'my description'
2525
reporting.report_start_event(event_name, event_description)
2626
expected_string_representation = ': '.join(
2727
['start', event_name, event_description])
28-
for _, handler in handler_registry.registered_items.items():
28+
for _, handler in (
29+
instantiated_handler_registry.registered_items.items()):
2930
self.assertEqual(1, handler.publish_event.call_count)
3031
event = handler.publish_event.call_args[0][0]
3132
self.assertEqual(expected_string_representation, event.as_string())
@@ -46,37 +47,40 @@ def assertHandlersPassedObjectWithAsString(
4647
event = handler.publish_event.call_args[0][0]
4748
self.assertEqual(expected_as_string, event.as_string())
4849

49-
@mock.patch('cloudinit.reporting.handler_registry',
50+
@mock.patch('cloudinit.reporting.instantiated_handler_registry',
5051
new_callable=_fake_registry)
5152
def test_report_finish_event_passes_something_with_as_string_to_handlers(
52-
self, handler_registry):
53+
self, instantiated_handler_registry):
5354
event_name, event_description = self._report_finish_event()
5455
expected_string_representation = ': '.join(
5556
['finish', event_name, event_description])
5657
self.assertHandlersPassedObjectWithAsString(
57-
handler_registry.registered_items, expected_string_representation)
58+
instantiated_handler_registry.registered_items,
59+
expected_string_representation)
5860

59-
@mock.patch('cloudinit.reporting.handler_registry',
61+
@mock.patch('cloudinit.reporting.instantiated_handler_registry',
6062
new_callable=_fake_registry)
6163
def test_reporting_successful_finish_has_sensible_string_repr(
62-
self, handler_registry):
64+
self, instantiated_handler_registry):
6365
event_name, event_description = self._report_finish_event(
6466
successful=True)
6567
expected_string_representation = ': '.join(
6668
['finish', event_name, 'success', event_description])
6769
self.assertHandlersPassedObjectWithAsString(
68-
handler_registry.registered_items, expected_string_representation)
70+
instantiated_handler_registry.registered_items,
71+
expected_string_representation)
6972

70-
@mock.patch('cloudinit.reporting.handler_registry',
73+
@mock.patch('cloudinit.reporting.instantiated_handler_registry',
7174
new_callable=_fake_registry)
7275
def test_reporting_unsuccessful_finish_has_sensible_string_repr(
73-
self, handler_registry):
76+
self, instantiated_handler_registry):
7477
event_name, event_description = self._report_finish_event(
7578
successful=False)
7679
expected_string_representation = ': '.join(
7780
['finish', event_name, 'fail', event_description])
7881
self.assertHandlersPassedObjectWithAsString(
79-
handler_registry.registered_items, expected_string_representation)
82+
instantiated_handler_registry.registered_items,
83+
expected_string_representation)
8084

8185

8286
class TestReportingEvent(unittest.TestCase):
@@ -125,8 +129,66 @@ def test_log_message_uses_event_as_string(self, getLogger):
125129
class TestDefaultRegisteredHandler(TestCase):
126130

127131
def test_log_handler_registered_by_default(self):
128-
for _, item in reporting.handler_registry.registered_items.items():
132+
registered_items = (
133+
reporting.instantiated_handler_registry.registered_items)
134+
for _, item in registered_items.items():
129135
if isinstance(item, reporting.LogHandler):
130136
break
131137
else:
132138
self.fail('No reporting LogHandler registered by default.')
139+
140+
141+
class TestReportingConfiguration(TestCase):
142+
143+
@mock.patch.object(reporting, 'instantiated_handler_registry')
144+
def test_empty_configuration_doesnt_add_handlers(
145+
self, instantiated_handler_registry):
146+
reporting.add_configuration({})
147+
self.assertEqual(
148+
0, instantiated_handler_registry.register_item.call_count)
149+
150+
@mock.patch.object(
151+
reporting, 'instantiated_handler_registry', reporting.DictRegistry())
152+
@mock.patch.object(reporting, 'available_handlers')
153+
def test_looks_up_handler_by_type_and_adds_it(self, available_handlers):
154+
handler_type_name = 'test_handler'
155+
handler_cls = mock.Mock()
156+
available_handlers.registered_items = {handler_type_name: handler_cls}
157+
handler_name = 'my_test_handler'
158+
reporting.add_configuration(
159+
{handler_name: {'type': handler_type_name}})
160+
self.assertEqual(
161+
{handler_name: handler_cls.return_value},
162+
reporting.instantiated_handler_registry.registered_items)
163+
164+
@mock.patch.object(
165+
reporting, 'instantiated_handler_registry', reporting.DictRegistry())
166+
@mock.patch.object(reporting, 'available_handlers')
167+
def test_uses_non_type_parts_of_config_dict_as_kwargs(
168+
self, available_handlers):
169+
handler_type_name = 'test_handler'
170+
handler_cls = mock.Mock()
171+
available_handlers.registered_items = {handler_type_name: handler_cls}
172+
extra_kwargs = {'foo': 'bar', 'bar': 'baz'}
173+
handler_config = extra_kwargs.copy()
174+
handler_config.update({'type': handler_type_name})
175+
handler_name = 'my_test_handler'
176+
reporting.add_configuration({handler_name: handler_config})
177+
self.assertEqual(
178+
handler_cls.return_value,
179+
reporting.instantiated_handler_registry.registered_items[
180+
handler_name])
181+
self.assertEqual([mock.call(**extra_kwargs)],
182+
handler_cls.call_args_list)
183+
184+
@mock.patch.object(
185+
reporting, 'instantiated_handler_registry', reporting.DictRegistry())
186+
@mock.patch.object(reporting, 'available_handlers')
187+
def test_handler_config_not_modified(self, available_handlers):
188+
handler_type_name = 'test_handler'
189+
handler_cls = mock.Mock()
190+
available_handlers.registered_items = {handler_type_name: handler_cls}
191+
handler_config = {'type': handler_type_name, 'foo': 'bar'}
192+
expected_handler_config = handler_config.copy()
193+
reporting.add_configuration({'my_test_handler': handler_config})
194+
self.assertEqual(expected_handler_config, handler_config)

0 commit comments

Comments
 (0)