Merge ~twom/launchpad:stats-add-ppa-latency into launchpad:master

Proposed by Tom Wardill
Status: Merged
Approved by: Tom Wardill
Approved revision: 053ef92adb7509a05c0f63f32d2d3d3266f885ca
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~twom/launchpad:stats-add-ppa-latency
Merge into: launchpad:master
Diff against target: 176 lines (+103/-1)
2 files modified
lib/lp/services/statsd/numbercruncher.py (+48/-0)
lib/lp/services/statsd/tests/test_numbercruncher.py (+55/-1)
Reviewer Review Type Date Requested Status
Thiago F. Pappacena (community) Approve
Review via email: mp+397834@code.launchpad.net

Commit message

Add PPA build and publishing latency stats

To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

LGTM

review: Approve
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/services/statsd/numbercruncher.py b/lib/lp/services/statsd/numbercruncher.py
2index b143927..a90a815 100644
3--- a/lib/lp/services/statsd/numbercruncher.py
4+++ b/lib/lp/services/statsd/numbercruncher.py
5@@ -31,10 +31,12 @@ from lp.buildmaster.interfaces.builder import IBuilderSet
6 from lp.buildmaster.manager import PrefetchedBuilderFactory
7 from lp.code.enums import CodeImportJobState
8 from lp.code.model.codeimportjob import CodeImportJob
9+from lp.soyuz.model.archive import Archive
10 from lp.services.database.interfaces import IStore
11 from lp.services.librarian.model import LibraryFileContent
12 from lp.services.statsd.interfaces.statsd_client import IStatsdClient
13
14+
15 NUMBER_CRUNCHER_LOG_NAME = "number-cruncher"
16
17
18@@ -45,6 +47,7 @@ class NumberCruncher(service.Service):
19 BUILDER_INTERVAL = 60
20 LIBRARIAN_INTERVAL = 3600
21 CODE_IMPORT_INTERVAL = 60
22+ PPA_LATENCY_INTERVAL = 3600
23
24 def __init__(self, clock=None, builder_factory=None):
25 if clock is None:
26@@ -181,6 +184,50 @@ class NumberCruncher(service.Service):
27 self.logger.exception("Failure while updating code import stats.")
28 transaction.abort()
29
30+ def updatePPABuildLatencyStats(self):
31+ """Update stats about build latencies.
32+
33+ This aborts the current transaction before returning.
34+ """
35+
36+ try:
37+ self.logger.debug("Update PPA build latency stats.")
38+ query = """
39+ SELECT
40+ avg(extract(
41+ epoch FROM bpb.date_first_dispatched - bpb.date_created)
42+ )/60,
43+ avg(extract(
44+ epoch FROM bpr.datecreated - bpb.date_finished))/60,
45+ avg(extract(
46+ epoch FROM bpph.datecreated - bpr.datecreated))/60,
47+ avg(extract(
48+ epoch FROM bpph.datepublished - bpph.datecreated))/60
49+ FROM
50+ archive,
51+ binarypackagebuild bpb,
52+ binarypackagepublishinghistory bpph,
53+ binarypackagerelease bpr
54+ WHERE
55+ archive.purpose = 2
56+ AND bpph.archive = archive.id
57+ AND bpph.archive = bpb.archive
58+ AND bpr.id = bpph.binarypackagerelease
59+ AND bpr.build = bpb.id
60+ AND bpb.distro_arch_series = bpph.distroarchseries
61+ AND bpph.datepublished >= %s
62+ """ % "(NOW() at time zone 'UTC' - interval '1 hour')"
63+ results = IStore(Archive).execute(query).get_one()
64+ self._sendGauge("ppa.startdelay", results[0])
65+ self._sendGauge("ppa.uploaddelay", results[1])
66+ self._sendGauge("ppa.processaccepted", results[2])
67+ self._sendGauge("ppa.publishdistro", results[3])
68+ self.logger.debug("PPA build latency stats update complete.")
69+ except Exception:
70+ self.logger.exception(
71+ "Failure while update PPA build latency stats.")
72+ transaction.abort()
73+
74 def startService(self):
75 self.logger.info("Starting number-cruncher service.")
76 self.loops = []
77@@ -190,6 +237,7 @@ class NumberCruncher(service.Service):
78 (self.BUILDER_INTERVAL, self.updateBuilderStats),
79 (self.LIBRARIAN_INTERVAL, self.updateLibrarianStats),
80 (self.CODE_IMPORT_INTERVAL, self.updateCodeImportStats),
81+ (self.PPA_LATENCY_INTERVAL, self.updatePPABuildLatencyStats),
82 ):
83 loop, stopping_deferred = self._startLoop(interval, callback)
84 self.loops.append(loop)
85diff --git a/lib/lp/services/statsd/tests/test_numbercruncher.py b/lib/lp/services/statsd/tests/test_numbercruncher.py
86index f2ea44e..3433282 100644
87--- a/lib/lp/services/statsd/tests/test_numbercruncher.py
88+++ b/lib/lp/services/statsd/tests/test_numbercruncher.py
89@@ -7,6 +7,9 @@ from __future__ import absolute_import, print_function, unicode_literals
90
91 __metaclass__ = type
92
93+from datetime import datetime
94+
95+import pytz
96 from storm.store import Store
97 from testtools.matchers import (
98 Equals,
99@@ -19,7 +22,10 @@ from twisted.internet import task
100 from zope.component import getUtility
101 from zope.security.proxy import removeSecurityProxy
102
103-from lp.buildmaster.enums import BuilderCleanStatus
104+from lp.buildmaster.enums import (
105+ BuilderCleanStatus,
106+ BuildStatus,
107+ )
108 from lp.buildmaster.interactor import BuilderSlave
109 from lp.buildmaster.interfaces.processor import IProcessorSet
110 from lp.buildmaster.model.buildqueue import BuildQueue
111@@ -30,6 +36,7 @@ from lp.services.database.policy import DatabaseBlockedPolicy
112 from lp.services.log.logger import BufferLogger
113 from lp.services.statsd.numbercruncher import NumberCruncher
114 from lp.services.statsd.tests import StatsMixin
115+from lp.soyuz.enums import PackagePublishingStatus
116 from lp.testing import TestCaseWithFactory
117 from lp.testing.fakemethod import FakeMethod
118 from lp.testing.layers import ZopelessDatabaseLayer
119@@ -284,6 +291,42 @@ class TestNumberCruncher(StatsMixin, TestCaseWithFactory):
120 self.assertIn(
121 "Failure while updating code import stats.",
122 cruncher.logger.getLogBuffer())
123+ self.assertFalse(is_transaction_in_progress())
124+
125+ def test_updatePPABuildLatencyStats(self):
126+ archive = self.factory.makeArchive()
127+ bpph = self.factory.makeBinaryPackagePublishingHistory(
128+ archive=archive, status=PackagePublishingStatus.PUBLISHED)
129+ bpph.binarypackagerelease.build.updateStatus(
130+ BuildStatus.BUILDING, date_started=datetime.now(pytz.UTC))
131+ bpph.binarypackagerelease.build.updateStatus(BuildStatus.FULLYBUILT)
132+ clock = task.Clock()
133+ cruncher = NumberCruncher(clock=clock)
134+ cruncher.updatePPABuildLatencyStats()
135+ self.assertEqual(4, self.stats_client.gauge.call_count)
136+ # The raw values here are non-deterministic and affected
137+ # by the test data, so just check that the gauges exist
138+ keys = [x[0][0] for x in self.stats_client.gauge.call_args_list]
139+ gauges = [
140+ "ppa.startdelay,env=test",
141+ "ppa.uploaddelay,env=test",
142+ "ppa.processaccepted,env=test",
143+ "ppa.publishdistro,env=test"]
144+ for gauge in gauges:
145+ self.assertIn(gauge, keys)
146+
147+ def test_updatePPABuildLatencyStats_error(self):
148+ clock = task.Clock()
149+ cruncher = NumberCruncher(clock=clock)
150+ cruncher.logger = BufferLogger()
151+ with DatabaseBlockedPolicy():
152+ cruncher.updatePPABuildLatencyStats()
153+
154+ self.assertFalse(is_transaction_in_progress())
155+ self.assertIn(
156+ "Failure while update PPA build latency stats.",
157+ cruncher.logger.getLogBuffer())
158+ self.assertFalse(is_transaction_in_progress())
159
160 def test_startService_starts_update_queues_loop(self):
161 clock = task.Clock()
162@@ -328,3 +371,14 @@ class TestNumberCruncher(StatsMixin, TestCaseWithFactory):
163 advance = NumberCruncher.CODE_IMPORT_INTERVAL + 1
164 clock.advance(advance)
165 self.assertNotEqual(0, cruncher.updateCodeImportStats.call_count)
166+
167+ def test_startService_starts_update_ppa_build_latency_loop(self):
168+ clock = task.Clock()
169+ cruncher = NumberCruncher(clock=clock)
170+
171+ cruncher.updatePPABuildLatencyStats = FakeMethod()
172+
173+ cruncher.startService()
174+ advance = NumberCruncher.PPA_LATENCY_INTERVAL + 1
175+ clock.advance(advance)
176+ self.assertNotEqual(0, cruncher.updatePPABuildLatencyStats.call_count)

Subscribers

People subscribed via source and target branches

to status/vote changes: