~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/services/timeline/timeline.py

  • Committer: Robert Collins
  • Date: 2011-08-10 01:00:53 UTC
  • mto: This revision was merged to the branch mainline in revision 13644.
  • Revision ID: robertc@robertcollins.net-20110810010053-w2tcm21i87fwqr3s
Use the new extracted timeline module.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
 
# GNU Affero General Public License version 3 (see the file LICENSE).
3
 
 
4
 
"""Coordinate a sequence of non overlapping TimedActionss."""
5
 
 
6
 
__all__ = ['Timeline']
7
 
 
8
 
__metaclass__ = type
9
 
 
10
 
import datetime
11
 
 
12
 
from pytz import utc as UTC
13
 
 
14
 
from timedaction import TimedAction
15
 
from nestingtimedaction import NestingTimedAction
16
 
 
17
 
 
18
 
class OverlappingActionError(Exception):
19
 
    """A new action was attempted without finishing the prior one."""
20
 
    # To make analysis easy we do not permit overlapping actions by default:
21
 
    # each action that is being timed and accrued must complete before the next
22
 
    # is started. This means, for instance, that sending mail cannot do SQL
23
 
    # queries, as both are timed and accrued. OTOH it makes analysis and
24
 
    # serialisation of timelines simpler, and for the current use cases in 
25
 
    # Launchpad this is sufficient. This constraint should not be considered
26
 
    # sacrosanct - if, in future, we desire timelines with overlapping actions,
27
 
    # as long as the OOPS analysis code is extended to generate sensible
28
 
    # reports in those situations, this can be changed. In the interim, actions
29
 
    # can be explicitly setup to permit nesting by passing allow_nested=True
30
 
    # which will cause the action to be recorded with 0 duration and a -start
31
 
    # and -stop suffix added to its category. This is potentially lossy but
32
 
    # good enough to get nested metrics and can be iterated on in the future to
33
 
    # do an actual stacked/tree model of actions - if needed.
34
 
 
35
 
 
36
 
class Timeline:
37
 
    """A sequence of TimedActions.
38
 
 
39
 
    This is used for collecting expensive/external actions inside Launchpad
40
 
    requests.
41
 
 
42
 
    :ivar actions: The actions.
43
 
    :ivar baseline: The point the timeline starts at.
44
 
    """
45
 
 
46
 
    def __init__(self, actions=None):
47
 
        """Create a Timeline.
48
 
        
49
 
        :param actions: An optional object to use to store the timeline. This
50
 
            must implement the list protocol.
51
 
        """
52
 
        if actions is None:
53
 
            actions = []
54
 
        self.actions = actions
55
 
        self.baseline = datetime.datetime.now(UTC)
56
 
 
57
 
    def start(self, category, detail, allow_nested=False):
58
 
        """Create a new TimedAction at the end of the timeline.
59
 
 
60
 
        :param category: the category for the action.
61
 
        :param detail: The detail for the action.
62
 
        :param allow_nested: If True treat this action as a nested action -
63
 
            record it twice with 0 duration, once at the start and once at the
64
 
            finish.
65
 
        :return: A TimedAction for that category and detail.
66
 
        """
67
 
        if allow_nested:
68
 
            result = NestingTimedAction(category, detail, self)
69
 
        else:
70
 
            result = TimedAction(category, detail, self)
71
 
        if self.actions and self.actions[-1].duration is None:
72
 
            raise OverlappingActionError(self.actions[-1], result)
73
 
        self.actions.append(result)
74
 
        return result