def test_task_action(self): """ The root message is the only child of a `Task`. """ node = next(tasks_from_iterable([action_task])) self.assertThat(get_children(set(), node), Equals([node.root()])) node = next(tasks_from_iterable([message_task])) self.assertThat(get_children(set(), node), Equals([node.root()]))
def test_written_action_no_children(self): """ The children of a `WrittenAction` does not contain any child actions/messages if there aren't any. """ node = next(tasks_from_iterable([action_task])).root() self.assertThat(list(get_children({u'foo'}, node)), HasLength(2))
def test_written_action_no_end(self): """ If the `WrittenAction` has no end message, it is excluded. """ node = next(tasks_from_iterable([action_task, nested_action_task])).root() self.assertThat(list(get_children({u'foo'}, node))[4:], Equals([]))
def test_task(self): """ `Task`'s UUID is rendered. """ node = next(tasks_from_iterable([action_task])) self.assertThat(self.format_node(node), ExactlyEquals(node.root().task_uuid))
def test_action_status(self): """ Action types include their status. """ message = next(tasks_from_iterable([action_task])).root().start_message self.assertThat(message_name(colors, no_formatting, message), Contains(u'started'))
def test_action_task_level(self): """ Action types include their task level. """ message = next(tasks_from_iterable([action_task])).root().start_message self.assertThat(message_name(colors, no_formatting, message), Contains(message.task_level.to_string()))
def test_action_type(self): """ Action types include their type name. """ message = next(tasks_from_iterable([action_task])).root().start_message self.assertThat( message_name(colors, no_formatting, message), StartsWith(colors.parent(message.contents.action_type)))
def render_tasks(self, iterable, **kw): fd = StringIO() err = StringIO(u'') tasks = tasks_from_iterable(iterable) render_tasks(write=fd.write, write_err=err.write, tasks=tasks, **kw) if err.tell(): return fd.getvalue(), err.getvalue() return fd.getvalue()
def render_stdout(message): """Ref: http://stackoverflow.com/questions/42936027/how-to-generate-eliot-tasks-for-eliottree-render-tasks """ eliottree.render_tasks(codecs.getwriter('utf-8')(sys.stdout).write, eliottree.tasks_from_iterable([message]), colorize=True, human_readable=True)
def test_written_action_end(self): """ The last child of a `WrittenAction` is the end message. """ node = next( tasks_from_iterable( [action_task, nested_action_task, action_task_end])).root() self.assertThat( list(get_children({u'foo'}, node))[3:], Equals([node.end_message]))
def test_written_action_children(self): """ The children of a `WrittenAction` contain child actions/messages. """ node = next( tasks_from_iterable( [action_task, nested_action_task, action_task_end])).root() self.assertThat( list(get_children({u'foo'}, node))[2], Equals(node.children[0]))
def test_action_status_success(self): """ Successful actions color their status. """ message = next(tasks_from_iterable([ action_task, action_task_end, ])).root().end_message self.assertThat(message_name(colors, no_formatting, message), Contains(colors.status_success(u'succeeded')))
def test_action_status_failed(self): """ Failed actions color their status. """ message = next(tasks_from_iterable([ action_task, action_task_end_failed, ])).root().end_message self.assertThat( message_name(colors, no_formatting, message), Contains(colors.failure(u'failed')))
def test_written_action_ignored_fields(self): """ Action fields can be ignored. """ task = dict(action_task) task.update({u'c': u'3'}) node = next(tasks_from_iterable([task])).root() start_message = node.start_message self.assertThat( list(get_children({u'c'}, node)), Equals([(u'action_status', start_message.contents.action_status), (u'action_type', start_message.contents.action_type)]))
def test_written_action_start(self): """ The children of a `WrittenAction` begin with the fields of the start message. """ node = next( tasks_from_iterable( [action_task, nested_action_task, action_task_end])).root() start_message = node.start_message self.assertThat( list(get_children({u'foo'}, node))[:2], Equals([(u'action_status', start_message.contents.action_status), (u'action_type', start_message.contents.action_type)]))
def test_written_action(self): """ `WrittenAction`'s start message is rendered. """ tasks = tasks_from_iterable([action_task, action_task_end]) node = next(tasks).root() self.assertThat( self.format_node(node), ExactlyEquals(u'{}{} {} {} {} \u29d6 {}'.format( node.start_message.contents.action_type, node.start_message.task_level.to_string(), RIGHT_DOUBLE_ARROW, node.start_message.contents.action_status, node.start_message.timestamp, node.end_message.timestamp - node.start_message.timestamp)))
def test_multiline_field(self): """ When no field limit is specified for task values, multiple lines are output for multiline tasks. """ fd = StringIO() tasks = tasks_from_iterable([multiline_action_task]) render_tasks(write=fd.write, tasks=tasks) self.assertThat( fd.getvalue(), ExactlyEquals(u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action/1 \u21d2 started ' u'1425356800\n' u' \u2514\u2500\u2500 message: this is a\u23ce\n' u' many line message\n\n'))
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 unicode: The rendered string. """ tasks = tasks_from_iterable(logs) out = StringIO() render_tasks( write=out.write, tasks=tasks, field_limit=0, ) return out.getvalue()
def parse_messages(files=None, select=None, task_uuid=None, start=None, end=None): """ Parse message dictionaries from inputs into Eliot tasks, filtering by any provided criteria. """ def filter_funcs(): if task_uuid is not None: yield filter_by_uuid(task_uuid) 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) def _parse(files, inventory): for file in files: file_name = getattr(file, 'name', '<unknown>') for line_number, line in enumerate(file, 1): try: task = json.loads(line) inventory[id(task)] = file_name, line_number yield task except Exception: raise JSONParseError(file_name, line_number, line.rstrip(u'\n'), sys.exc_info()) if not files: files = [text_reader(sys.stdin)] inventory = {} return inventory, tasks_from_iterable( filter(combine_filters_and(*filter_funcs()), _parse(files, inventory)))
import requests from eliot import start_action, add_destinations, log_call from eliottree import render_tasks, tasks_from_iterable messages = [] def collect_messages(message): messages.append(message) add_destinations(collect_messages) @log_call def get_some_data(url): requests.get(url) try: with start_action(action_type='SomeOuterAction', x=123) as action: action.log(message_type='my_dummy_message', text='something is about to happen') url = 'http://4ut23y74283ty872y3t47823t.com/' with start_action(action_type='SomeInnerAction', url=url): get_some_data(url) except: render_tasks(sys.stdout.write, tasks_from_iterable(messages), colorize=True)