Merge ~cjwatson/launchpad:statsd-implicit-env into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: dcb4e0d4e56b25935379a55894dc5a37dd00ace3
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:statsd-implicit-env
Merge into: launchpad:master
Diff against target: 264 lines (+39/-63)
9 files modified
lib/lp/buildmaster/manager.py (+3/-6)
lib/lp/buildmaster/model/buildfarmjobbehaviour.py (+2/-3)
lib/lp/services/job/runner.py (+4/-9)
lib/lp/services/statsd/model/statsd_client.py (+10/-7)
lib/lp/services/statsd/numbercruncher.py (+5/-12)
lib/lp/services/statsd/tests/__init__.py (+6/-3)
lib/lp/services/statsd/tests/test_statsd_client.py (+0/-10)
lib/lp/services/webapp/publication.py (+4/-8)
lib/lp/services/webapp/tests/test_publication.py (+5/-5)
Reviewer Review Type Date Requested Status
Tom Wardill (community) Approve
Review via email: mp+393792@code.launchpad.net

Commit message

StatsdClient: Automatically add env label

Description of the change

Having to add the appropriate env label manually at each call site is a bit too cumbersome and error-prone, and indeed we'd forgotten to include it for traversal and publication duration timings. Add it automatically in the StatsdClient wrapper instead.

To post a comment you must log in.
Revision history for this message
Tom Wardill (twom) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/buildmaster/manager.py b/lib/lp/buildmaster/manager.py
index e9732ea..7bbe4aa 100644
--- a/lib/lp/buildmaster/manager.py
+++ b/lib/lp/buildmaster/manager.py
@@ -532,13 +532,10 @@ class SlaveScanner:
532 if builder.current_build is not None:532 if builder.current_build is not None:
533 builder.current_build.gotFailure()533 builder.current_build.gotFailure()
534 self.statsd_client.incr(534 self.statsd_client.incr(
535 'builders.judged_failed,build=True,arch={},env={}'.format(535 'builders.judged_failed,build=True,arch={}'.format(
536 builder.current_build.processor.name,536 builder.current_build.processor.name))
537 self.statsd_client.lp_environment))
538 else:537 else:
539 self.statsd_client.incr(538 self.statsd_client.incr('builders.judged_failed,build=False')
540 'builders.judged_failed,build=False,env={}'.format(
541 self.statsd_client.lp_environment))
542 recover_failure(self.logger, vitals, builder, retry, failure.value)539 recover_failure(self.logger, vitals, builder, retry, failure.value)
543 transaction.commit()540 transaction.commit()
544 except Exception:541 except Exception:
diff --git a/lib/lp/buildmaster/model/buildfarmjobbehaviour.py b/lib/lp/buildmaster/model/buildfarmjobbehaviour.py
index 88ede6a..13a38d7 100644
--- a/lib/lp/buildmaster/model/buildfarmjobbehaviour.py
+++ b/lib/lp/buildmaster/model/buildfarmjobbehaviour.py
@@ -158,10 +158,9 @@ class BuildFarmJobBehaviourBase:
158 job_type_name = job_type.name if job_type else 'UNKNOWN'158 job_type_name = job_type.name if job_type else 'UNKNOWN'
159 statsd_client = getUtility(IStatsdClient)159 statsd_client = getUtility(IStatsdClient)
160 statsd_client.incr(160 statsd_client.incr(
161 'build.count,job_type={},builder_name={},env={}'.format(161 'build.count,job_type={},builder_name={}'.format(
162 job_type_name,162 job_type_name,
163 self._builder.name,163 self._builder.name))
164 statsd_client.lp_environment))
165164
166 logger.info(165 logger.info(
167 "Job %s (%s) started on %s: %s %s"166 "Job %s (%s) started on %s: %s %s"
diff --git a/lib/lp/services/job/runner.py b/lib/lp/services/job/runner.py
index b0b65a2..15ea4e9 100644
--- a/lib/lp/services/job/runner.py
+++ b/lib/lp/services/job/runner.py
@@ -326,25 +326,20 @@ class BaseRunnableJob(BaseRunnableJobSource):
326 """See `IJob`."""326 """See `IJob`."""
327 self.job.start(manage_transaction=manage_transaction)327 self.job.start(manage_transaction=manage_transaction)
328 statsd = getUtility(IStatsdClient)328 statsd = getUtility(IStatsdClient)
329 statsd.incr('job.start_count,type={},env={}'.format(329 statsd.incr('job.start_count,type={}'.format(self.__class__.__name__))
330 self.__class__.__name__,
331 statsd.lp_environment))
332330
333 def complete(self, manage_transaction=False):331 def complete(self, manage_transaction=False):
334 """See `IJob`."""332 """See `IJob`."""
335 self.job.complete(manage_transaction=manage_transaction)333 self.job.complete(manage_transaction=manage_transaction)
336 statsd = getUtility(IStatsdClient)334 statsd = getUtility(IStatsdClient)
337 statsd.incr('job.complete_count,type={},env={}'.format(335 statsd.incr('job.complete_count,type={}'.format(
338 self.__class__.__name__,336 self.__class__.__name__))
339 statsd.lp_environment))
340337
341 def fail(self, manage_transaction=False):338 def fail(self, manage_transaction=False):
342 """See `IJob`."""339 """See `IJob`."""
343 self.job.fail(manage_transaction=manage_transaction)340 self.job.fail(manage_transaction=manage_transaction)
344 statsd = getUtility(IStatsdClient)341 statsd = getUtility(IStatsdClient)
345 statsd.incr('job.fail_count,type={},env={}'.format(342 statsd.incr('job.fail_count,type={}'.format(self.__class__.__name__))
346 self.__class__.__name__,
347 statsd.lp_environment))
348343
349344
350class BaseJobRunner(LazrJobRunner):345class BaseJobRunner(LazrJobRunner):
diff --git a/lib/lp/services/statsd/model/statsd_client.py b/lib/lp/services/statsd/model/statsd_client.py
index 6ccf027..7d6c3c1 100644
--- a/lib/lp/services/statsd/model/statsd_client.py
+++ b/lib/lp/services/statsd/model/statsd_client.py
@@ -43,14 +43,17 @@ class StatsdClient:
43 self._make_client()43 self._make_client()
4444
45 def __getattr__(self, name):45 def __getattr__(self, name):
46 # This is a convenience to keep all statsd client related
47 # items on the client. Having this separate from prefix
48 # allows us to use it as a label, rather than as part of the
49 # gauge name
50 if name == 'lp_environment':
51 return config.statsd.environment
52 if self._client is not None:46 if self._client is not None:
53 return getattr(self._client, name)47 wrapped = getattr(self._client, name)
48 if name in ("timer", "timing", "incr", "decr", "gauge", "set"):
49 def wrapper(stat, *args, **kwargs):
50 return wrapped(
51 "%s,env=%s" % (stat, config.statsd.environment),
52 *args, **kwargs)
53
54 return wrapper
55 else:
56 return wrapped
54 else:57 else:
55 # Prevent unnecessary network traffic if this Launchpad instance58 # Prevent unnecessary network traffic if this Launchpad instance
56 # has no statsd configuration.59 # has no statsd configuration.
diff --git a/lib/lp/services/statsd/numbercruncher.py b/lib/lp/services/statsd/numbercruncher.py
index 27c61a4..3f1a6e1 100644
--- a/lib/lp/services/statsd/numbercruncher.py
+++ b/lib/lp/services/statsd/numbercruncher.py
@@ -88,8 +88,7 @@ class NumberCruncher(service.Service):
88 virt = queue_type == 'virt'88 virt = queue_type == 'virt'
89 for arch, value in contents.items():89 for arch, value in contents.items():
90 gauge_name = (90 gauge_name = (
91 "buildqueue,virtualized={},arch={},env={}".format(91 "buildqueue,virtualized={},arch={}".format(virt, arch))
92 virt, arch, self.statsd_client.lp_environment))
93 self._sendGauge(gauge_name, value[0])92 self._sendGauge(gauge_name, value[0])
94 self.logger.debug("Build queue stats update complete.")93 self.logger.debug("Build queue stats update complete.")
95 except Exception:94 except Exception:
@@ -122,8 +121,8 @@ class NumberCruncher(service.Service):
122 counts['idle'] += 1121 counts['idle'] += 1
123 for processor, counts in counts_by_processor.items():122 for processor, counts in counts_by_processor.items():
124 for count_name, count_value in counts.items():123 for count_name, count_value in counts.items():
125 gauge_name = "builders,status={},arch={},env={}".format(124 gauge_name = "builders,status={},arch={}".format(
126 count_name, processor, self.statsd_client.lp_environment)125 count_name, processor)
127 self._sendGauge(gauge_name, count_value)126 self._sendGauge(gauge_name, count_value)
128 self.logger.debug("Builder stats update complete.")127 self.logger.debug("Builder stats update complete.")
129128
@@ -149,14 +148,8 @@ class NumberCruncher(service.Service):
149 store = IStore(LibraryFileContent)148 store = IStore(LibraryFileContent)
150 total_files, total_filesize = store.find(149 total_files, total_filesize = store.find(
151 (Count(), Sum(LibraryFileContent.filesize))).one()150 (Count(), Sum(LibraryFileContent.filesize))).one()
152 self._sendGauge(151 self._sendGauge("librarian.total_files", total_files)
153 "librarian.total_files,env={}".format(152 self._sendGauge("librarian.total_filesize", total_filesize)
154 self.statsd_client.lp_environment),
155 total_files)
156 self._sendGauge(
157 "librarian.total_filesize,env={}".format(
158 self.statsd_client.lp_environment),
159 total_filesize)
160 self.logger.debug("Librarian stats update complete.")153 self.logger.debug("Librarian stats update complete.")
161 except Exception:154 except Exception:
162 self.logger.exception("Failure while updating librarian stats:")155 self.logger.exception("Failure while updating librarian stats:")
diff --git a/lib/lp/services/statsd/tests/__init__.py b/lib/lp/services/statsd/tests/__init__.py
index 23fb067..c9c9ef5 100644
--- a/lib/lp/services/statsd/tests/__init__.py
+++ b/lib/lp/services/statsd/tests/__init__.py
@@ -8,9 +8,11 @@ from __future__ import absolute_import, print_function, unicode_literals
8__metaclass__ = type8__metaclass__ = type
9__all__ = ['StatsMixin']9__all__ = ['StatsMixin']
1010
11from fixtures import MockPatchObject
12from zope.component import getUtility
13
11from lp.services.compat import mock14from lp.services.compat import mock
12from lp.services.statsd.interfaces.statsd_client import IStatsdClient15from lp.services.statsd.interfaces.statsd_client import IStatsdClient
13from lp.testing.fixture import ZopeUtilityFixture
1416
1517
16class StatsMixin:18class StatsMixin:
@@ -18,7 +20,8 @@ class StatsMixin:
18 def setUpStats(self):20 def setUpStats(self):
19 # Install a mock statsd client so we can assert against the call21 # Install a mock statsd client so we can assert against the call
20 # counts and args.22 # counts and args.
23 self.pushConfig("statsd", environment="test")
24 statsd_client = getUtility(IStatsdClient)
21 self.stats_client = mock.Mock()25 self.stats_client = mock.Mock()
22 self.stats_client.lp_environment = "test"
23 self.useFixture(26 self.useFixture(
24 ZopeUtilityFixture(self.stats_client, IStatsdClient))27 MockPatchObject(statsd_client, "_client", self.stats_client))
diff --git a/lib/lp/services/statsd/tests/test_statsd_client.py b/lib/lp/services/statsd/tests/test_statsd_client.py
index 2e1a8e1..709b41c 100644
--- a/lib/lp/services/statsd/tests/test_statsd_client.py
+++ b/lib/lp/services/statsd/tests/test_statsd_client.py
@@ -50,13 +50,3 @@ class TestClientConfiguration(TestCase):
50 "port: 9999\nprefix: test\nenvironment: test\n")50 "port: 9999\nprefix: test\nenvironment: test\n")
51 client.reload()51 client.reload()
52 self.assertIsInstance(client._client, StatsClient)52 self.assertIsInstance(client._client, StatsClient)
53
54 def test_lp_environment_is_available(self):
55 client = getUtility(IStatsdClient)
56 self.addCleanup(client.reload)
57 config.push(
58 'statsd_test',
59 "[statsd]\nhost: 127.0.01\n"
60 "port: 9999\nprefix: test\nenvironment: test\n")
61 client.reload()
62 self.assertEqual(client.lp_environment, "test")
diff --git a/lib/lp/services/webapp/publication.py b/lib/lp/services/webapp/publication.py
index 9a9a0e3..7325d9f 100644
--- a/lib/lp/services/webapp/publication.py
+++ b/lib/lp/services/webapp/publication.py
@@ -795,16 +795,13 @@ class LaunchpadBrowserPublication(
795 status = request.response.getStatus()795 status = request.response.getStatus()
796 if status == 404: # Not Found796 if status == 404: # Not Found
797 OpStats.stats['404s'] += 1797 OpStats.stats['404s'] += 1
798 statsd_client.incr('errors.404,env={}'.format(798 statsd_client.incr('errors.404')
799 statsd_client.lp_environment))
800 elif status == 500: # Unhandled exceptions799 elif status == 500: # Unhandled exceptions
801 OpStats.stats['500s'] += 1800 OpStats.stats['500s'] += 1
802 statsd_client.incr('errors.500,env={}'.format(801 statsd_client.incr('errors.500')
803 statsd_client.lp_environment))
804 elif status == 503: # Timeouts802 elif status == 503: # Timeouts
805 OpStats.stats['503s'] += 1803 OpStats.stats['503s'] += 1
806 statsd_client.incr('errors.503,env={}'.format(804 statsd_client.incr('errors.503')
807 statsd_client.lp_environment))
808805
809 # Increment counters for status code groups.806 # Increment counters for status code groups.
810 status_group = str(status)[0] + 'XXs'807 status_group = str(status)[0] + 'XXs'
@@ -813,8 +810,7 @@ class LaunchpadBrowserPublication(
813 # Increment counter for 5XXs_b.810 # Increment counter for 5XXs_b.
814 if is_browser(request) and status_group == '5XXs':811 if is_browser(request) and status_group == '5XXs':
815 OpStats.stats['5XXs_b'] += 1812 OpStats.stats['5XXs_b'] += 1
816 statsd_client.incr('errors.5XX,env={}'.format(813 statsd_client.incr('errors.5XX')
817 statsd_client.lp_environment))
818814
819 # Make sure our databases are in a sane state for the next request.815 # Make sure our databases are in a sane state for the next request.
820 thread_name = threading.current_thread().name816 thread_name = threading.current_thread().name
diff --git a/lib/lp/services/webapp/tests/test_publication.py b/lib/lp/services/webapp/tests/test_publication.py
index 245fc28..a2a4953 100644
--- a/lib/lp/services/webapp/tests/test_publication.py
+++ b/lib/lp/services/webapp/tests/test_publication.py
@@ -326,11 +326,11 @@ class TestPublisherStats(StatsMixin, TestCaseWithFactory):
326 MatchesListwise(326 MatchesListwise(
327 [MatchesListwise(327 [MatchesListwise(
328 (Equals('traversal_duration,success=True,'328 (Equals('traversal_duration,success=True,'
329 'pageid=RootObject-index-html'),329 'pageid=RootObject-index-html,env=test'),
330 GreaterThan(0))),330 GreaterThan(0))),
331 MatchesListwise(331 MatchesListwise(
332 (Equals('publication_duration,success=True,'332 (Equals('publication_duration,success=True,'
333 'pageid=RootObject-index-html'),333 'pageid=RootObject-index-html,env=test'),
334 GreaterThan(0)))]))334 GreaterThan(0)))]))
335335
336 def test_traversal_failure_stats(self):336 def test_traversal_failure_stats(self):
@@ -350,7 +350,7 @@ class TestPublisherStats(StatsMixin, TestCaseWithFactory):
350 MatchesListwise(350 MatchesListwise(
351 [MatchesListwise(351 [MatchesListwise(
352 (Equals('traversal_duration,success=False,'352 (Equals('traversal_duration,success=False,'
353 'pageid=None'),353 'pageid=None,env=test'),
354 GreaterThan(0)))]))354 GreaterThan(0)))]))
355355
356 def test_publication_failure_stats(self):356 def test_publication_failure_stats(self):
@@ -370,11 +370,11 @@ class TestPublisherStats(StatsMixin, TestCaseWithFactory):
370 MatchesListwise(370 MatchesListwise(
371 [MatchesListwise(371 [MatchesListwise(
372 (Equals('traversal_duration,success=True,'372 (Equals('traversal_duration,success=True,'
373 'pageid=RootObject-index-html'),373 'pageid=RootObject-index-html,env=test'),
374 GreaterThan(0))),374 GreaterThan(0))),
375 MatchesListwise(375 MatchesListwise(
376 (Equals('publication_duration,success=False,'376 (Equals('publication_duration,success=False,'
377 'pageid=RootObject-index-html'),377 'pageid=RootObject-index-html,env=test'),
378 GreaterThan(0)))]))378 GreaterThan(0)))]))
379379
380 def test_prepPageIDForMetrics_none(self):380 def test_prepPageIDForMetrics_none(self):

Subscribers

People subscribed via source and target branches

to status/vote changes: