Quick start guide
Installation
You can install the latest version of Seagrass by running
pip install seagrass
Creating a new Auditor
You typically audit code with Seagrass in three steps:
Create a new
Auditorinstance.Define new Seagrass events using
Auditor.audit.Create a new auditing context using
auditor.start_auditing(), and then start calling the code under audit.
Let’s look at an example. Before we start, we’ll configure the logger used by
Seagrass. Auditors default to using the "seagrass" logger, so we’ll
configure the logger to print all logs to stdout:
import logging
fh = logging.StreamHandler()
fh.setLevel(logging.INFO)
formatter = logging.Formatter("(%(levelname)s) %(name)s: %(message)s")
fh.setFormatter(formatter)
logger = logging.getLogger("seagrass")
logger.setLevel(logging.INFO)
logger.addHandler(fh)
Now let’s use Seagrass! In the code below, we audit the add and sub
functions to see how many times each of them are called. We create a new event
for the add function called event.add, and an event for the sub
function called event.sub.
from seagrass import Auditor
from seagrass.hooks import CounterHook
# Create a new Auditor instance
auditor = Auditor()
# Create a hook that will count each time an event occurs
hook = CounterHook()
# Now define some new events by hooking some example functions
@auditor.audit("event.add", hooks=[hook])
def add(x: int, y: int) -> int:
return x + y
@auditor.audit("event.sub", hooks=[hook])
def sub(x: int, y: int) -> int:
return x - y
# Now start auditing!
with auditor.start_auditing():
add(1, 2)
add(3, 4)
sub(5, 2)
# Display the results of auditing.
auditor.log_results()
{"message": "CounterHook results", "seagrass": {"event": null, "hook": "CounterHook", "hook_ctx": {"event": "event.add", "count": 2}}, "level": "INFO"}
{"message": "CounterHook results", "seagrass": {"event": null, "hook": "CounterHook", "hook_ctx": {"event": "event.sub", "count": 1}}, "level": "INFO"}
From here we can start doing more complicated tasks. For instance, here’s an
example where we override Python’s time.sleep and measure the amount of time
spent in that function (as well as the number of times it gets called).
>>> import time
>>> from seagrass.hooks import CounterHook, TimerHook
>>> ch = CounterHook()
>>> th = TimerHook()
>>> ausleep = auditor.audit("time.sleep", time.sleep, hooks=[ch,th])
>>> time.sleep = ausleep
>>> with auditor.start_auditing():
... for _ in range(10):
... time.sleep(0.1)
>>> auditor.log_results()
(INFO) seagrass: Calls to events recorded by CounterHook:
(INFO) seagrass: time.sleep: 10
(INFO) seagrass: TimerHook results:
(INFO) seagrass: Time spent in time.sleep: 1.006210
Raising audit events without wrapping functions
Up until this point, we’ve been creating audit events by calling
seagrass.Auditor.audit() function that we want to audit. Sometimes,
though, it doesn’t make sense to audit an entire function; perhaps we just want
to raise a signal at a single point in time, and have Seagrass capture
information about that signal.
We can achieve this functionality by using
create_event() and
raise_event(). In the code snippet below, we create a
new event my_sum.cumsum and call it at every iteration of the function
my_sum to get the cumulative sum that’s being calculated internally.
>>> from seagrass.hooks import LoggingHook
>>> prehook_msg = lambda event_name, args, kwargs: f"cumsum={args[0]}"
>>> hook = LoggingHook(prehook_msg=prehook_msg)
>>> event_wrapper = auditor.create_event("my_sum.cumsum", hooks=[hook])
>>> def my_sum(iterable):
... total = 0.
... for val in iterable:
... auditor.raise_event("my_sum.cumsum", total)
... total += val
... return total
>>> with auditor.start_auditing():
... my_sum([1, 2, 3, 4])
{"message": "cumsum=0.0", "seagrass": {"event": "my_sum.cumsum"}, "level": "DEBUG"}
{"message": "cumsum=1.0", "seagrass": {"event": "my_sum.cumsum"}, "level": "DEBUG"}
{"message": "cumsum=3.0", "seagrass": {"event": "my_sum.cumsum"}, "level": "DEBUG"}
{"message": "cumsum=6.0", "seagrass": {"event": "my_sum.cumsum"}, "level": "DEBUG"}
10.0