{"action":"created","comment":{"url":"https://api.github.com/repos/spotify/gordon/pulls/comments/195199782","pull_request_review_id":128519888,"id":195199782,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NTE5OTc4Mg==","diff_hunk":"@@ -0,0 +1,173 @@\n+# -*- coding: utf-8 -*-\n+# Copyright (c) 2018 Spotify AB\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\");\n+# you may not use this file except in compliance with the License.\n+# You may obtain a copy of the License at\n+#\n+# http://www.apache.org/licenses/LICENSE-2.0\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+\"\"\"\n+Gordon ships with a default IMetricRelay implementation, which\n+outputs metrics to the application logger using the standard\n+library `logging` module.\n+\n+This implementation is used by default if no other IMetricRelay\n+implementation is loaded and chosen.\n+\n+The default configuration that can be overriden is shown below.\n+\n+.. code-block:: ini\n+\n+    [metrics-logger]\n+    # One of the log levels available from the stdlib logging module.\n+    log_level = 'info'\n+    # Time unit used by LogTimer. Can be one of 's', 'ms', 'ns'.\n+    time_unit = 's'\n+\"\"\"\n+\n+import collections\n+import logging\n+import time\n+\n+import zope.interface\n+\n+from gordon import interfaces\n+\n+# TODO: update plugin loader to load metrics logger as default\n+\n+\n+@zope.interface.implementer(interfaces.ITimer)\n+class LogTimer:\n+    \"\"\"Timer that outputs metrics to the logger.\n+\n+    Args:\n+        metric (dict): Metric to output.\n+        logger (.LoggerAdapter): Object used for outputting metrics.\n+        time_unit (str): Unit for LogTimer output.\n+            Options: s, ms, ns.\n+    \"\"\"\n+    def __init__(self, metric, logger, time_unit):\n+        self.metric = metric\n+        self.logger = logger\n+        self.time_multiplier = self._time_unit_to_multiplier(time_unit)\n+\n+    def _time_unit_to_multiplier(self, unit):\n+        return {\n+            's': 1,\n+            'ms': 1E3,\n+            'ns': 1E9\n+        }[unit]\n+\n+    async def __aenter__(self):\n+        await self.start()\n+        return self\n+\n+    async def __aexit__(self, *args):\n+        await self.stop()\n+\n+    async def start(self):\n+        \"\"\"Start the timer.\"\"\"\n+        self._start_time = time.perf_counter()\n+\n+    async def stop(self):\n+        \"\"\"Stop the timer and output the time delta to the logger.\"\"\"\n+        time_elapsed = (\n+            time.perf_counter() - self._start_time) * self.time_multiplier\n+        self.metric['value'] = time_elapsed\n+        self.logger.log(self.metric)\n+\n+\n+class LoggerAdapter:\n+    \"\"\"Configurable adapter that formats and outputs metrics.\n+\n+    Args:\n+        level (str): Log level at which to output metric.\n+    \"\"\"\n+    LOGFMT = '[{metric_name}] value: {value}'\n+\n+    def __init__(self, level):\n+        self.level = level\n+        self._logger = logging.getLogger('gordon.metrics-logger')\n+\n+    def log(self, metric):\n+        \"\"\"Format and output metric.\n+\n+        Args:\n+            metric (dict): Complete metric.\n+        \"\"\"\n+        message = self.LOGFMT.format(**metric)\n+        if metric['context']:\n+            message += ' context: {context}'.format(context=metric['context'])","path":"gordon/metrics/log.py","position":106,"original_position":106,"commit_id":"9f39601c2910d53b459547907f2de1290e8de5d4","original_commit_id":"9faf061639dc8a1edd256a56d79e63bf66cffc70","user":{"login":"econchick","id":1191069,"node_id":"MDQ6VXNlcjExOTEwNjk=","avatar_url":"https://avatars0.githubusercontent.com/u/1191069?v=4","gravatar_id":"","url":"https://api.github.com/users/econchick","html_url":"https://github.com/econchick","followers_url":"https://api.github.com/users/econchick/followers","following_url":"https://api.github.com/users/econchick/following{/other_user}","gists_url":"https://api.github.com/users/econchick/gists{/gist_id}","starred_url":"https://api.github.com/users/econchick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/econchick/subscriptions","organizations_url":"https://api.github.com/users/econchick/orgs","repos_url":"https://api.github.com/users/econchick/repos","events_url":"https://api.github.com/users/econchick/events{/privacy}","received_events_url":"https://api.github.com/users/econchick/received_events","type":"User","site_admin":false},"body":"Another option if more readable:\r\n```\r\n[request-latency] value=1 attr1=value1 attr2=value2\r\n```","created_at":"2018-06-13T18:59:18Z","updated_at":"2018-06-13T18:59:18Z","html_url":"https://github.com/spotify/gordon/pull/23#discussion_r195199782","pull_request_url":"https://api.github.com/repos/spotify/gordon/pulls/23","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/spotify/gordon/pulls/comments/195199782"},"html":{"href":"https://github.com/spotify/gordon/pull/23#discussion_r195199782"},"pull_request":{"href":"https://api.github.com/repos/spotify/gordon/pulls/23"}},"in_reply_to_id":194443794},"pull_request":{"url":"https://api.github.com/repos/spotify/gordon/pulls/23","id":193071820,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkzMDcxODIw","html_url":"https://github.com/spotify/gordon/pull/23","diff_url":"https://github.com/spotify/gordon/pull/23.diff","patch_url":"https://github.com/spotify/gordon/pull/23.patch","issue_url":"https://api.github.com/repos/spotify/gordon/issues/23","number":23,"state":"open","locked":false,"title":"[WIP] Add metric logger metric relay implementation","user":{"login":"matt0bi","id":33331579,"node_id":"MDQ6VXNlcjMzMzMxNTc5","avatar_url":"https://avatars3.githubusercontent.com/u/33331579?v=4","gravatar_id":"","url":"https://api.github.com/users/matt0bi","html_url":"https://github.com/matt0bi","followers_url":"https://api.github.com/users/matt0bi/followers","following_url":"https://api.github.com/users/matt0bi/following{/other_user}","gists_url":"https://api.github.com/users/matt0bi/gists{/gist_id}","starred_url":"https://api.github.com/users/matt0bi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matt0bi/subscriptions","organizations_url":"https://api.github.com/users/matt0bi/orgs","repos_url":"https://api.github.com/users/matt0bi/repos","events_url":"https://api.github.com/users/matt0bi/events{/privacy}","received_events_url":"https://api.github.com/users/matt0bi/received_events","type":"User","site_admin":false},"body":"<!--  Thanks for sending a pull request!  Here are some tips for you:\r\n1. If this is your first time, read our contributor guidelines <https://github.com/spotify/gordon/blob/master/CONTRIBUTING.rst>\r\n2. If the PR is unfinished, please prefix the subject line with [WIP], [DRAFT], or [RFC].\r\n-->\r\n\r\n**What this PR does / why we need it**:\r\n\r\nThis PR implements the default metric relay, which outputs metrics to the logger.\r\n\r\n**Which issue(s) this PR fixes** \r\n<!-- optional; in `fixes #<issue number>, fixes #<issue_number>, ...` format, will close the issue(s) when PR gets merged: -->\r\nN/A\r\n\r\n**Special notes for your reviewer**:\r\n\r\nThis PR is WIP because it's based off #22. I'll update this PR with any changes in #22 that affect the code here. I'll also update this PR with any comments from #22 that are relevant to this one. \r\n\r\nNote that because there's an outstanding comment in #22 about the plugin loader, I didn't touch that part in this PR. Once that's resolved, I'll update the code here to tackle the \"plugin loader should load logger metrics by default\" issue.\r\n\r\n\r\n**Release note**:\r\n<!--  Write your release note:\r\n1. Enter your extended release note in the below block. If the PR requires additional action from users switching to the new release, start the release note with the string \"action required: \".\r\n2. If no release note is required, just write \"NONE\".\r\n-->\r\n```release-note\r\nAdd default metric logger.\r\n```\r\n\r\n@spotify/alf \r\n","created_at":"2018-06-06T16:30:04Z","updated_at":"2018-06-13T18:59:18Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b440f254b7978d0a5faa280f93cfe9065811b98c","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/spotify/gordon/pulls/23/commits","review_comments_url":"https://api.github.com/repos/spotify/gordon/pulls/23/comments","review_comment_url":"https://api.github.com/repos/spotify/gordon/pulls/comments{/number}","comments_url":"https://api.github.com/repos/spotify/gordon/issues/23/comments","statuses_url":"https://api.github.com/repos/spotify/gordon/statuses/9f39601c2910d53b459547907f2de1290e8de5d4","head":{"label":"spotify:feature/add-logger-metrics","ref":"feature/add-logger-metrics","sha":"9f39601c2910d53b459547907f2de1290e8de5d4","user":{"login":"spotify","id":251374,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==","avatar_url":"https://avatars2.githubusercontent.com/u/251374?v=4","gravatar_id":"","url":"https://api.github.com/users/spotify","html_url":"https://github.com/spotify","followers_url":"https://api.github.com/users/spotify/followers","following_url":"https://api.github.com/users/spotify/following{/other_user}","gists_url":"https://api.github.com/users/spotify/gists{/gist_id}","starred_url":"https://api.github.com/users/spotify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spotify/subscriptions","organizations_url":"https://api.github.com/users/spotify/orgs","repos_url":"https://api.github.com/users/spotify/repos","events_url":"https://api.github.com/users/spotify/events{/privacy}","received_events_url":"https://api.github.com/users/spotify/received_events","type":"Organization","site_admin":false},"repo":{"id":111466778,"node_id":"MDEwOlJlcG9zaXRvcnkxMTE0NjY3Nzg=","name":"gordon","full_name":"spotify/gordon","owner":{"login":"spotify","id":251374,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==","avatar_url":"https://avatars2.githubusercontent.com/u/251374?v=4","gravatar_id":"","url":"https://api.github.com/users/spotify","html_url":"https://github.com/spotify","followers_url":"https://api.github.com/users/spotify/followers","following_url":"https://api.github.com/users/spotify/following{/other_user}","gists_url":"https://api.github.com/users/spotify/gists{/gist_id}","starred_url":"https://api.github.com/users/spotify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spotify/subscriptions","organizations_url":"https://api.github.com/users/spotify/orgs","repos_url":"https://api.github.com/users/spotify/repos","events_url":"https://api.github.com/users/spotify/events{/privacy}","received_events_url":"https://api.github.com/users/spotify/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/spotify/gordon","description":"Event-driven Cloud DNS Registration ","fork":false,"url":"https://api.github.com/repos/spotify/gordon","forks_url":"https://api.github.com/repos/spotify/gordon/forks","keys_url":"https://api.github.com/repos/spotify/gordon/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spotify/gordon/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spotify/gordon/teams","hooks_url":"https://api.github.com/repos/spotify/gordon/hooks","issue_events_url":"https://api.github.com/repos/spotify/gordon/issues/events{/number}","events_url":"https://api.github.com/repos/spotify/gordon/events","assignees_url":"https://api.github.com/repos/spotify/gordon/assignees{/user}","branches_url":"https://api.github.com/repos/spotify/gordon/branches{/branch}","tags_url":"https://api.github.com/repos/spotify/gordon/tags","blobs_url":"https://api.github.com/repos/spotify/gordon/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spotify/gordon/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spotify/gordon/git/refs{/sha}","trees_url":"https://api.github.com/repos/spotify/gordon/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spotify/gordon/statuses/{sha}","languages_url":"https://api.github.com/repos/spotify/gordon/languages","stargazers_url":"https://api.github.com/repos/spotify/gordon/stargazers","contributors_url":"https://api.github.com/repos/spotify/gordon/contributors","subscribers_url":"https://api.github.com/repos/spotify/gordon/subscribers","subscription_url":"https://api.github.com/repos/spotify/gordon/subscription","commits_url":"https://api.github.com/repos/spotify/gordon/commits{/sha}","git_commits_url":"https://api.github.com/repos/spotify/gordon/git/commits{/sha}","comments_url":"https://api.github.com/repos/spotify/gordon/comments{/number}","issue_comment_url":"https://api.github.com/repos/spotify/gordon/issues/comments{/number}","contents_url":"https://api.github.com/repos/spotify/gordon/contents/{+path}","compare_url":"https://api.github.com/repos/spotify/gordon/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spotify/gordon/merges","archive_url":"https://api.github.com/repos/spotify/gordon/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spotify/gordon/downloads","issues_url":"https://api.github.com/repos/spotify/gordon/issues{/number}","pulls_url":"https://api.github.com/repos/spotify/gordon/pulls{/number}","milestones_url":"https://api.github.com/repos/spotify/gordon/milestones{/number}","notifications_url":"https://api.github.com/repos/spotify/gordon/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spotify/gordon/labels{/name}","releases_url":"https://api.github.com/repos/spotify/gordon/releases{/id}","deployments_url":"https://api.github.com/repos/spotify/gordon/deployments","created_at":"2017-11-20T21:52:25Z","updated_at":"2018-06-13T18:24:30Z","pushed_at":"2018-06-13T18:50:17Z","git_url":"git://github.com/spotify/gordon.git","ssh_url":"git@github.com:spotify/gordon.git","clone_url":"https://github.com/spotify/gordon.git","svn_url":"https://github.com/spotify/gordon","homepage":null,"size":135,"stargazers_count":13,"watchers_count":13,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":2,"open_issues":3,"watchers":13,"default_branch":"develop"}},"base":{"label":"spotify:feature/add-metrics","ref":"feature/add-metrics","sha":"7aea92d90a6d885cc9413413ec65334a54c6290d","user":{"login":"spotify","id":251374,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==","avatar_url":"https://avatars2.githubusercontent.com/u/251374?v=4","gravatar_id":"","url":"https://api.github.com/users/spotify","html_url":"https://github.com/spotify","followers_url":"https://api.github.com/users/spotify/followers","following_url":"https://api.github.com/users/spotify/following{/other_user}","gists_url":"https://api.github.com/users/spotify/gists{/gist_id}","starred_url":"https://api.github.com/users/spotify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spotify/subscriptions","organizations_url":"https://api.github.com/users/spotify/orgs","repos_url":"https://api.github.com/users/spotify/repos","events_url":"https://api.github.com/users/spotify/events{/privacy}","received_events_url":"https://api.github.com/users/spotify/received_events","type":"Organization","site_admin":false},"repo":{"id":111466778,"node_id":"MDEwOlJlcG9zaXRvcnkxMTE0NjY3Nzg=","name":"gordon","full_name":"spotify/gordon","owner":{"login":"spotify","id":251374,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==","avatar_url":"https://avatars2.githubusercontent.com/u/251374?v=4","gravatar_id":"","url":"https://api.github.com/users/spotify","html_url":"https://github.com/spotify","followers_url":"https://api.github.com/users/spotify/followers","following_url":"https://api.github.com/users/spotify/following{/other_user}","gists_url":"https://api.github.com/users/spotify/gists{/gist_id}","starred_url":"https://api.github.com/users/spotify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spotify/subscriptions","organizations_url":"https://api.github.com/users/spotify/orgs","repos_url":"https://api.github.com/users/spotify/repos","events_url":"https://api.github.com/users/spotify/events{/privacy}","received_events_url":"https://api.github.com/users/spotify/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/spotify/gordon","description":"Event-driven Cloud DNS Registration ","fork":false,"url":"https://api.github.com/repos/spotify/gordon","forks_url":"https://api.github.com/repos/spotify/gordon/forks","keys_url":"https://api.github.com/repos/spotify/gordon/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spotify/gordon/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spotify/gordon/teams","hooks_url":"https://api.github.com/repos/spotify/gordon/hooks","issue_events_url":"https://api.github.com/repos/spotify/gordon/issues/events{/number}","events_url":"https://api.github.com/repos/spotify/gordon/events","assignees_url":"https://api.github.com/repos/spotify/gordon/assignees{/user}","branches_url":"https://api.github.com/repos/spotify/gordon/branches{/branch}","tags_url":"https://api.github.com/repos/spotify/gordon/tags","blobs_url":"https://api.github.com/repos/spotify/gordon/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spotify/gordon/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spotify/gordon/git/refs{/sha}","trees_url":"https://api.github.com/repos/spotify/gordon/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spotify/gordon/statuses/{sha}","languages_url":"https://api.github.com/repos/spotify/gordon/languages","stargazers_url":"https://api.github.com/repos/spotify/gordon/stargazers","contributors_url":"https://api.github.com/repos/spotify/gordon/contributors","subscribers_url":"https://api.github.com/repos/spotify/gordon/subscribers","subscription_url":"https://api.github.com/repos/spotify/gordon/subscription","commits_url":"https://api.github.com/repos/spotify/gordon/commits{/sha}","git_commits_url":"https://api.github.com/repos/spotify/gordon/git/commits{/sha}","comments_url":"https://api.github.com/repos/spotify/gordon/comments{/number}","issue_comment_url":"https://api.github.com/repos/spotify/gordon/issues/comments{/number}","contents_url":"https://api.github.com/repos/spotify/gordon/contents/{+path}","compare_url":"https://api.github.com/repos/spotify/gordon/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spotify/gordon/merges","archive_url":"https://api.github.com/repos/spotify/gordon/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spotify/gordon/downloads","issues_url":"https://api.github.com/repos/spotify/gordon/issues{/number}","pulls_url":"https://api.github.com/repos/spotify/gordon/pulls{/number}","milestones_url":"https://api.github.com/repos/spotify/gordon/milestones{/number}","notifications_url":"https://api.github.com/repos/spotify/gordon/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spotify/gordon/labels{/name}","releases_url":"https://api.github.com/repos/spotify/gordon/releases{/id}","deployments_url":"https://api.github.com/repos/spotify/gordon/deployments","created_at":"2017-11-20T21:52:25Z","updated_at":"2018-06-13T18:24:30Z","pushed_at":"2018-06-13T18:50:17Z","git_url":"git://github.com/spotify/gordon.git","ssh_url":"git@github.com:spotify/gordon.git","clone_url":"https://github.com/spotify/gordon.git","svn_url":"https://github.com/spotify/gordon","homepage":null,"size":135,"stargazers_count":13,"watchers_count":13,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":2,"open_issues":3,"watchers":13,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/spotify/gordon/pulls/23"},"html":{"href":"https://github.com/spotify/gordon/pull/23"},"issue":{"href":"https://api.github.com/repos/spotify/gordon/issues/23"},"comments":{"href":"https://api.github.com/repos/spotify/gordon/issues/23/comments"},"review_comments":{"href":"https://api.github.com/repos/spotify/gordon/pulls/23/comments"},"review_comment":{"href":"https://api.github.com/repos/spotify/gordon/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/spotify/gordon/pulls/23/commits"},"statuses":{"href":"https://api.github.com/repos/spotify/gordon/statuses/9f39601c2910d53b459547907f2de1290e8de5d4"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"econchick"}}