Quickstart

Let’s see how easy it is to use Eliot.

Installing Eliot

To install Eliot and the other tools we’ll use in this example, run the following in your shell:

$ pip install eliot eliot-tree requests

You can also install it using Conda:

$ conda install -c conda-forge eliot eliot-tree requests

This will install:

  1. Eliot itself.
  2. eliot-tree, a tool that lets you visualize Eliot logs easily.
  3. requests, a HTTP client library we’ll use in the example code below. You don’t need it for real Eliot usage, though.

Our example program

We’re going to add logging code to the following script, which checks if a list of links are valid URLs:

import requests

def check_links(urls):
    for url in urls:
        try:
            response = requests.get(url)
            response.raise_for_status()
        except Exception as e:
            raise ValueError(str(e))

try:
    check_links(["http://eliot.readthedocs.io", "http://nosuchurl"])
except ValueError:
    print("Not all links were valid.")

Adding Eliot logging

To add logging to this program, we do two things:

  1. Tell Eliot to log messages to file called “linkcheck.log” by using eliot.to_file().
  2. Create two actions using eliot.start_action(). Actions succeed when the eliot.start_action() context manager finishes successfully, and fail when an exception is raised.
import requests
from eliot import start_action, to_file
to_file(open("linkcheck.log", "w"))


def check_links(urls):
    with start_action(action_type="check_links", urls=urls):
        for url in urls:
            try:
                with start_action(action_type="download", url=url):
                    response = requests.get(url)
                    response.raise_for_status()
            except Exception as e:
                raise ValueError(str(e))

try:
    check_links(["http://eliot.readthedocs.io", "http://nosuchurl"])
except ValueError:
    print("Not all links were valid.")

Running the code

Let’s run the code:

$ python linkcheck.py
Not all the links were valid.

We can see the resulting log file is composed of JSON messages, one per line:

$ cat linkcheck.log
{"action_status": "started", "task_uuid": "b1cb58cf-2c2f-45c0-92b2-838ac00b20cc", "task_level": [1], "timestamp": 1509136967.2066844, "action_type": "check_links", "urls": ["http://eliot.readthedocs.io", "http://nosuchurl"]}
...

So far these logs seem similar to the output of regular logging systems: individual isolated messages. But unlike those logging systems, Eliot produces logs that can be reconstructed into a tree, for example using the eliot-tree utility:

$ eliot-tree linkcheck.log
b1cb58cf-2c2f-45c0-92b2-838ac00b20cc
└── check_links/1 ⇒ started
    ├── timestamp: 2017-10-27 20:42:47.206684
    ├── urls:
    │   ├── 0: http://eliot.readthedocs.io
    │   └── 1: http://nosuchurl
    ├── download/2/1 ⇒ started
    │   ├── timestamp: 2017-10-27 20:42:47.206933
    │   ├── url: http://eliot.readthedocs.io
    │   └── download/2/2 ⇒ succeeded
    │       └── timestamp: 2017-10-27 20:42:47.439203
    ├── download/3/1 ⇒ started
    │   ├── timestamp: 2017-10-27 20:42:47.439412
    │   ├── url: http://nosuchurl
    │   └── download/3/2 ⇒ failed
    │       ├── errno: None
    │       ├── exception: requests.exceptions.ConnectionError
    │       ├── reason: HTTPConnectionPool(host='nosuchurl', port=80): Max retries exceeded with url: / (Caused by NewConnec…
    │       └── timestamp: 2017-10-27 20:42:47.457133
    └── check_links/4 ⇒ failed
        ├── exception: builtins.ValueError
        ├── reason: HTTPConnectionPool(host='nosuchurl', port=80): Max retries exceeded with url: / (Caused by NewConnec…
        └── timestamp: 2017-10-27 20:42:47.457332

Notice how:

  1. Eliot tells you which actions succeeded and which failed.
  2. Failed actions record their exceptions.
  3. You can see just from the logs that the check_links action caused the download action.

Next steps

You can learn more by reading the rest of the documentation, including: