Example #1
0
def build_task_nodes(files=None, select=None, task_uuid=None,
                     human_readable=True):
    """
    Build the task nodes given some input data, query criteria and formatting
    options.
    """
    def task_transformers():
        if human_readable:
            yield _convert_timestamp
        yield json.loads

    def filter_funcs():
        if select is not None:
            for query in select:
                yield filter_by_jmespath(query)

        if task_uuid is not None:
            yield filter_by_uuid(task_uuid)

    if files is None:
        files = [sys.stdin]

    tree = Tree()
    tasks = imap(compose(*task_transformers()),
                 chain.from_iterable(files))
    return tree.nodes(tree.merge_tasks(tasks, filter_funcs())),
Example #2
0
def build_task_nodes(files=None, select=None, task_uuid=None, start=None,
                     end=None):
    """
    Build the task nodes given some input data, query criteria and formatting
    options.
    """
    def filter_funcs():
        if start:
            yield filter_by_start_date(start)
        if end:
            yield filter_by_end_date(end)

        if select is not None:
            for query in select:
                yield filter_by_jmespath(query)

        if task_uuid is not None:
            yield filter_by_uuid(task_uuid)

    if not files:
        if PY3:
            files = [sys.stdin]
        else:
            files = [codecs.getreader('utf-8')(sys.stdin)]

    tree = Tree()
    tasks = map(json.loads, chain.from_iterable(files))
    return tree.nodes(tree.merge_tasks(tasks, filter_funcs()))
Example #3
0
 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')))
Example #4
0
def display_task_tree(args):
    """
    Read the input files, apply any command-line-specified behaviour and
    display the task tree.
    """

    def task_transformers():
        if args.human_readable:
            yield _convert_timestamp
        yield json.loads

    def filter_funcs():
        if args.select:
            for query in args.select:
                yield filter_by_jmespath(query)

        if args.task_uuid:
            yield filter_by_uuid(args.task_uuid)

    if not args.files:
        args.files.append(sys.stdin)

    tree = Tree()
    tasks = imap(compose(*task_transformers()), chain.from_iterable(args.files))
    render_task_nodes(
        write=sys.stdout.write,
        nodes=tree.nodes(tree.merge_tasks(tasks, filter_funcs())),
        ignored_task_keys=set(args.ignored_task_keys) or None,
        field_limit=args.field_limit,
    )
Example #5
0
 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))
Example #6
0
 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)))
Example #7
0
 def test_nested(self):
     """
     Render nested tasks in a way that visually represents that nesting.
     """
     fd = StringIO()
     tree = Tree()
     tree.merge_tasks([action_task, nested_action_task])
     render_task_nodes(fd.write, tree.nodes(), 0)
     self.assertThat(
         fd.getvalue(),
         Equals(
             'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
             '+-- app:action@1/started\n'
             '    `-- timestamp: 1425356800\n'
             '    +-- app:action:nested@1,1/started\n'
             '        `-- timestamp: 1425356900\n\n'))
Example #8
0
 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')))
Example #9
0
 def test_field_limit(self):
     """
     Truncate task values that are longer than the field_limit if specified.
     """
     fd = StringIO()
     tree = Tree()
     tree.merge_tasks([message_task])
     render_task_nodes(
         write=fd.write,
         nodes=tree.nodes(),
         field_limit=5)
     self.assertThat(
         fd.getvalue(),
         Equals(
             'cdeb220d-7605-4d5f-8341-1a170222e308\n'
             '+-- twisted:log@1\n'
             '    |-- error: False\n'
             '    |-- message: Main  [...]\n'
             '    `-- timestamp: 14253 [...]\n\n'))
Example #10
0
 def test_multiline_field_limit(self):
     """
     When a field limit is specified for task values, only the first of
     multiple lines is output.
     """
     fd = StringIO()
     tree = Tree()
     tree.merge_tasks([multiline_action_task])
     render_task_nodes(
         write=fd.write,
         nodes=tree.nodes(),
         field_limit=1000)
     self.assertThat(
         fd.getvalue(),
         Equals(
             'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
             '+-- app:action@1/started\n'
             '    |-- message: this is a [...]\n'
             '    `-- timestamp: 1425356800\n\n'))
Example #11
0
 def test_dict_data(self):
     """
     Task values that are ``dict``s are rendered as tree elements.
     """
     fd = StringIO()
     tree = Tree()
     tree.merge_tasks([dict_action_task])
     render_task_nodes(
         write=fd.write,
         nodes=tree.nodes(),
         field_limit=0)
     self.assertThat(
         fd.getvalue(),
         Equals(
             'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
             '+-- app:action@1/started\n'
             '    |-- some_data:\n'
             '        `-- a: 42\n'
             '    `-- timestamp: 1425356800\n\n'))
Example #12
0
 def test_task_data(self):
     """
     Task data is rendered as tree elements.
     """
     fd = StringIO()
     tree = Tree()
     tree.merge_tasks([message_task])
     render_task_nodes(
         write=fd.write,
         nodes=tree.nodes(),
         field_limit=0)
     self.assertThat(
         fd.getvalue(),
         Equals(
             'cdeb220d-7605-4d5f-8341-1a170222e308\n'
             '+-- twisted:log@1\n'
             '    |-- error: False\n'
             '    |-- message: Main loop terminated.\n'
             '    `-- timestamp: 1425356700\n\n'))
Example #13
0
 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')))
Example #14
0
 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')))
Example #15
0
 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')))
Example #16
0
 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')))
Example #17
0
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()
Example #18
0
 def test_tasks(self):
     """
     Render two tasks of sequential levels, by default most standard Eliot
     task keys are ignored.
     """
     fd = StringIO()
     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(),
         Equals(
             'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
             '+-- app:action@1/started\n'
             '    `-- timestamp: 1425356800\n'
             '    +-- app:action@2/succeeded\n'
             '        `-- timestamp: 1425356800\n\n'))
Example #19
0
 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')))
Example #20
0
 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 = StringIO()
     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(),
         Equals(
             'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
             '+-- app:action@1/started\n'
             '    `-- timestamp: 2015-03-03 04:26:40\n'
             '    +-- app:action@2/succeeded\n'
             '        `-- timestamp: 2015-03-03 04:26:40\n\n'))
Example #21
0
 def test_ignored_keys(self):
     """
     Task keys can be ignored.
     """
     fd = StringIO()
     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(),
         Equals(
             'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
             '+-- app:action@1/started\n'
             '    |-- action_status: started\n'
             '    |-- action_type: app:action\n'
             '    |-- task_uuid: f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
             '    `-- timestamp: 1425356800\n\n'))
Example #22
0
 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')))
Example #23
0
 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')))
Example #24
0
 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')))
Example #25
0
 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')))