summaryrefslogtreecommitdiff
path: root/docs/timing.rst
blob: ed85481fab9788efde9dabccb0751eea4eab2f7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
.. _timing-chapter:

============
Using Timers
============

:ref:`Timers <timer-type>` 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 :ref:`timing` method::

    import time
    from statsd import StatsClient

    statsd = StatsClient()

    start = time.time()
    time.sleep(3)

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


Using a context manager
=======================

Each ``StatsClient`` instance contains a :ref:`timer` attribute that can
be used as a context manager or a 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
=================

The ``timer`` attribute can also be used as a function decorator. 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)

.. warning::
   Decorators are not thread-safe and may cause errors when decorated
   functions are called concurrently. Use context managers or raw timers
   instead.


Using a Timer object directly
=============================

.. versionadded:: 2.1

:py:class:`statsd.client.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 :py:meth:`statsd.client.Timer.stop` is called, a :ref:`timing stat
<timer-type>`_ 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 :py:meth:`statsd.client.Timer.send` to send the stat when you're
ready.

.. _timer-direct-note:

.. note::
   This use of timers is compatible with :ref:`Pipelines
   <pipeline-chapter>`_ but be careful with the ``send()`` method. It
   *must* be called for the stat to be included when the Pipeline
   finally sends data, but ``send()`` will *not* immediately cause data
   to be sent in the context of a Pipeline. For example::

    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...