Using Timers

Timers are an incredibly powerful tool for tracking application performance. Statsd provides a number of ways to use them to instrument your code.

There are four ways to use timers.

Calling timing manually

The simplest way to use a timer is to record the time yourself and send it manually, using the StatsClient.timing() method:

import time
from datetime import datetime
from statsd import StatsClient

statsd = StatsClient()

# Pass milliseconds directly

start = time.time()
time.sleep(3)
# You must convert to milliseconds:
dt = int((time.time() - start) * 1000)
statsd.timing('slept', dt)

# Or pass a timedelta

start = datetime.utcnow()
time.sleep(3)
dt = datetime.utcnow() - start
statsd.timing('slept', dt)

Using a context manager

The StatsClient.timer() method will return a Timer object that can be used as both a context manager and a thread-safe decorator.

When used as a context manager, it will automatically report the time taken for the inner block:

from statsd import StatsClient

statsd = StatsClient()

with statsd.timer('foo'):
    # This block will be timed.
    for i in xrange(0, 100000):
        i ** 2
# The timing is sent immediately when the managed block exits.

Using a decorator

Timer objects can be used to decorate a method in a thread-safe manner. Every time the decorated function is called, the time it took to execute will be sent to the statsd server.

from statsd import StatsClient

statsd = StatsClient()

@statsd.timer('myfunc')
def myfunc(a, b):
    """Calculate the most complicated thing a and b can do."""

# Timing information will be sent every time the function is called.
myfunc(1, 2)
myfunc(3, 7)

Using a Timer object directly

New in version 2.1.

Timer objects function as context managers and as decorators, but they can also be used directly. (Flat is, after all, better than nested.)

from statsd import StatsClient

statsd = StatsClient()

foo_timer = statsd.timer('foo')
foo_timer.start()
# Do something fun.
foo_timer.stop()

When Timer.stop() is called, a timing stat will automatically be sent to StatsD. You can over ride this behavior with the send=False keyword argument to stop():

foo_timer.stop(send=False)
foo_timer.send()

Use Timer.send() to send the stat when you’re ready.

Note

This use of timers is compatible with Pipelines but the send() method may not behave exactly as expected. Timing data must be sent, either by calling stop() without send=False or calling send() explicitly, in order for it to be included in the pipeline. However, it will not be sent immediately.

with statsd.pipeline() as pipe:
    foo_timer = pipe.timer('foo').start()
    # Do something...
    pipe.incr('bar')
    foo_timer.stop()  # Will be sent when the managed block exits.

with statsd.pipeline() as pipe:
    foo_timer = pipe.timer('foo').start()
    # Do something...
    pipe.incr('bar')
    foo_timer.stop(send=False)  # Will not be sent.
    foo_timer.send()  # Will be sent when the managed block exits.
    # Do something else...

with statsd.pipeline() as pipe:
    foo_timer = pipe.timer('foo').start()
    pipe.incr('bar')
    # Do something...
    foo_timer.stop(send=False)  # Data will _not_ be sent