def test_colorize(self): """ Passing ``colorize=True`` will colorize the output. """ fd = BytesIO() tree = Tree() tree.merge_tasks([action_task, action_task_end]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0, colorize=True) C = COLORS(colored) self.assertThat( fd.getvalue(), ExactlyEquals( u'\n'.join([ C.root(u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4'), u'\u2514\u2500\u2500 {}'.format( C.success(u'app:action@1/started')), u' \u251c\u2500\u2500 {}: {}'.format( C.prop(u'timestamp'), u'1425356800'), u' \u2514\u2500\u2500 {}'.format( C.success(u'app:action@2/succeeded')), u' \u2514\u2500\u2500 {}: {}'.format( C.prop('timestamp'), u'1425356802'), u'\n', ]).encode('utf-8')))
def test_node(self): """ Task nodes use their own name. """ tree = Tree() tree.merge_tasks([action_task]) node = tree.nodes()[0][1] C = COLORS(colored) get_name = get_name_factory(C) self.assertThat( get_name(node), ExactlyEquals(node.name))
def test_node_failure(self): """ Task nodes indicating failure are colored. """ tree = Tree() tree.merge_tasks([action_task]) node = tree.nodes()[0][1].copy() node.success = False C = COLORS(colored) get_name = get_name_factory(C) self.assertThat( get_name(node), ExactlyEquals(C.failure(node.name)))
def test_nested(self): """ Render nested tasks in a way that visually represents that nesting. """ fd = BytesIO() tree = Tree() tree.merge_tasks([action_task, nested_action_task]) render_task_nodes(fd.write, tree.nodes(), 0) self.assertThat( fd.getvalue(), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action@1/started\n' u' \u251c\u2500\u2500 timestamp: 1425356800\n' u' \u2514\u2500\u2500 app:action:nest@1,1/started\n' u' \u2514\u2500\u2500 timestamp: 1425356900\n\n' .encode('utf-8')))
def _eliottree(logs): """ Render some Eliot log events into a tree-like string. :param list[dict] logs: The Eliot log events to render. These should be dicts like those passed to an Eliot destination. :return bytes: The rendered string. """ tree = Tree() tree.merge_tasks(logs) nodes = tree.nodes() out = BytesIO() render_task_nodes( write=out.write, nodes=nodes, field_limit=0, ) return out.getvalue()
def test_task_data(self): """ Task data is rendered as tree elements. """ fd = BytesIO() tree = Tree() tree.merge_tasks([message_task]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0) self.assertThat( fd.getvalue(), ExactlyEquals( u'cdeb220d-7605-4d5f-8341-1a170222e308\n' u'\u2514\u2500\u2500 twisted:log@1\n' u' \u251c\u2500\u2500 error: False\n' u' \u251c\u2500\u2500 message: Main loop terminated.\n' u' \u2514\u2500\u2500 timestamp: 1425356700\n\n' .encode('utf-8')))
def test_dict_data(self): """ Task values that are ``dict``s are rendered as tree elements. """ fd = BytesIO() tree = Tree() tree.merge_tasks([dict_action_task]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0) self.assertThat( fd.getvalue(), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action@1/started\n' u' \u251c\u2500\u2500 some_data\n' u' \u2502 \u2514\u2500\u2500 a: 42\n' u' \u2514\u2500\u2500 timestamp: 1425356800\n\n' .encode('utf-8')))
def test_field_limit(self): """ Truncate task values that are longer than the field_limit if specified. """ fd = BytesIO() tree = Tree() tree.merge_tasks([message_task]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=5) self.assertThat( fd.getvalue(), ExactlyEquals( u'cdeb220d-7605-4d5f-8341-1a170222e308\n' u'\u2514\u2500\u2500 twisted:log@1\n' u' \u251c\u2500\u2500 error: False\n' u' \u251c\u2500\u2500 message: Main \u2026\n' u' \u2514\u2500\u2500 timestamp: 14253\u2026\n\n' .encode('utf-8')))
def test_multiline_field_limit(self): """ When a field limit is specified for task values, only the first of multiple lines is output. """ fd = BytesIO() tree = Tree() tree.merge_tasks([multiline_action_task]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=1000) self.assertThat( fd.getvalue(), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action@1/started\n' u' \u251c\u2500\u2500 message: this is a\u2026\n' u' \u2514\u2500\u2500 timestamp: 1425356800\n\n' .encode('utf-8')))
def test_tasks(self): """ Render two tasks of sequential levels, by default most standard Eliot task keys are ignored. """ fd = BytesIO() tree = Tree() tree.merge_tasks([action_task, action_task_end]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0) self.assertThat( fd.getvalue(), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action@1/started\n' u' \u251c\u2500\u2500 timestamp: 1425356800\n' u' \u2514\u2500\u2500 app:action@2/succeeded\n' u' \u2514\u2500\u2500 timestamp: 1425356802\n\n' .encode('utf-8')))
def test_janky_action(self): """ Task names, UUIDs, keys and values in actions all have control characters escaped. """ fd = BytesIO() tree = Tree() tree.merge_tasks([janky_action_task]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0) self.assertThat( fd.getvalue(), ExactlyEquals( u'f3a32bb3-ea6b-457c-\u241b(0aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 A\u241b(0@1/started\n' u' \u251c\u2500\u2500 \u241b(0\n' u' \u2502 \u2514\u2500\u2500 \u241b(0: nope\n' u' \u251c\u2500\u2500 mes\u240asage: hello\u241b(0world\n' u' \u2514\u2500\u2500 timestamp: 1425356800\u241b(0\n\n' .encode('utf-8')))
def test_janky_message(self): """ Task names, UUIDs, keys and values in messages all have control characters escaped. """ fd = BytesIO() tree = Tree() tree.merge_tasks([janky_message_task]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0) self.assertThat( fd.getvalue(), ExactlyEquals( u'cdeb220d-7605-4d5f-\u241b(08341-1a170222e308\n' u'\u2514\u2500\u2500 M\u241b(0@1\n' u' \u251c\u2500\u2500 er\u241bror: False\n' u' \u251c\u2500\u2500 mes\u240asage: ' u'Main loop\u241b(0terminated.\n' u' \u2514\u2500\u2500 timestamp: 1425356700\n\n' .encode('utf-8')))
def test_ignored_keys(self): """ Task keys can be ignored. """ fd = BytesIO() tree = Tree() tree.merge_tasks([action_task]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0, ignored_task_keys=set(['task_level'])) self.assertThat( fd.getvalue(), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action@1/started\n' u' \u251c\u2500\u2500 action_status: started\n' u' \u251c\u2500\u2500 action_type: app:action\n' u' \u251c\u2500\u2500 task_uuid: ' u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u' \u2514\u2500\u2500 timestamp: 1425356800\n\n' .encode('utf-8')))
def test_tasks_human_readable(self): """ Render two tasks of sequential levels, by default most standard Eliot task keys are ignored, values are formatted to be human readable. """ fd = BytesIO() tree = Tree() tree.merge_tasks([action_task, action_task_end]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0, human_readable=True) self.assertThat( fd.getvalue(), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action@1/started\n' u' \u251c\u2500\u2500 timestamp: 2015-03-03 04:26:40\n' u' \u2514\u2500\u2500 app:action@2/succeeded\n' u' \u2514\u2500\u2500 timestamp: 2015-03-03 04:26:42\n' u'\n' .encode('utf-8')))