Skip to content

Commit f2d8ad6

Browse files
committed
Merge pull request #1584 from tseaver/logging-metric_create
Add 'metric.Metric' class and its 'create' API wrapper.
2 parents a8cdf27 + 5baba70 commit f2d8ad6

File tree

4 files changed

+222
-0
lines changed

4 files changed

+222
-0
lines changed

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
Client <logging-client>
115115
logging-logger
116116
logging-entries
117+
logging-metric
117118
logging-sink
118119

119120
.. toctree::

docs/logging-metric.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Metrics
2+
=======
3+
4+
.. automodule:: gcloud.logging.metric
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

gcloud/logging/metric.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Define Logging API Metrics."""
16+
17+
18+
class Metric(object):
19+
"""Metrics represent named filters for log entries.
20+
21+
See:
22+
https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/projects.metrics
23+
24+
:type name: string
25+
:param name: the name of the metric
26+
27+
:type filter_: string
28+
:param filter_: the advanced logs filter expression defining the entries
29+
tracked by the metric.
30+
31+
:type client: :class:`gcloud.logging.client.Client`
32+
:param client: A client which holds credentials and project configuration
33+
for the metric (which requires a project).
34+
35+
:type description: string
36+
:param description: an optional description of the metric
37+
"""
38+
def __init__(self, name, filter_, client, description=''):
39+
self.name = name
40+
self._client = client
41+
self.filter_ = filter_
42+
self.description = description
43+
44+
@property
45+
def client(self):
46+
"""Clent bound to the logger."""
47+
return self._client
48+
49+
@property
50+
def project(self):
51+
"""Project bound to the logger."""
52+
return self._client.project
53+
54+
@property
55+
def full_name(self):
56+
"""Fully-qualified name used in metric APIs"""
57+
return 'projects/%s/metrics/%s' % (self.project, self.name)
58+
59+
@property
60+
def path(self):
61+
"""URL path for the metric's APIs"""
62+
return '/%s' % (self.full_name,)
63+
64+
def _require_client(self, client):
65+
"""Check client or verify over-ride.
66+
67+
:type client: :class:`gcloud.logging.client.Client` or ``NoneType``
68+
:param client: the client to use. If not passed, falls back to the
69+
``client`` stored on the current metric.
70+
71+
:rtype: :class:`gcloud.logging.client.Client`
72+
:returns: The client passed in or the currently bound client.
73+
"""
74+
if client is None:
75+
client = self._client
76+
return client
77+
78+
def create(self, client=None):
79+
"""API call: create the metric via a PUT request
80+
81+
See:
82+
https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/projects.metrics/create
83+
84+
:type client: :class:`gcloud.logging.client.Client` or ``NoneType``
85+
:param client: the client to use. If not passed, falls back to the
86+
``client`` stored on the current metric.
87+
"""
88+
client = self._require_client(client)
89+
data = {
90+
'name': self.name,
91+
'filter': self.filter_,
92+
}
93+
if self.description:
94+
data['description'] = self.description
95+
client.connection.api_request(method='PUT', path=self.path, data=data)

gcloud/logging/test_metric.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import unittest2
16+
17+
18+
class TestMetric(unittest2.TestCase):
19+
20+
PROJECT = 'test-project'
21+
METRIC_NAME = 'metric-name'
22+
FILTER = 'logName:syslog AND severity>=ERROR'
23+
DESCRIPTION = 'DESCRIPTION'
24+
25+
def _getTargetClass(self):
26+
from gcloud.logging.metric import Metric
27+
return Metric
28+
29+
def _makeOne(self, *args, **kw):
30+
return self._getTargetClass()(*args, **kw)
31+
32+
def test_ctor_defaults(self):
33+
FULL = 'projects/%s/metrics/%s' % (self.PROJECT, self.METRIC_NAME)
34+
conn = _Connection()
35+
client = _Client(self.PROJECT, conn)
36+
metric = self._makeOne(self.METRIC_NAME, self.FILTER, client=client)
37+
self.assertEqual(metric.name, self.METRIC_NAME)
38+
self.assertEqual(metric.filter_, self.FILTER)
39+
self.assertEqual(metric.description, '')
40+
self.assertTrue(metric.client is client)
41+
self.assertEqual(metric.project, self.PROJECT)
42+
self.assertEqual(metric.full_name, FULL)
43+
self.assertEqual(metric.path, '/%s' % (FULL,))
44+
45+
def test_ctor_explicit(self):
46+
FULL = 'projects/%s/metrics/%s' % (self.PROJECT, self.METRIC_NAME)
47+
conn = _Connection()
48+
client = _Client(self.PROJECT, conn)
49+
metric = self._makeOne(self.METRIC_NAME, self.FILTER,
50+
client=client, description=self.DESCRIPTION)
51+
self.assertEqual(metric.name, self.METRIC_NAME)
52+
self.assertEqual(metric.filter_, self.FILTER)
53+
self.assertEqual(metric.description, self.DESCRIPTION)
54+
self.assertTrue(metric.client is client)
55+
self.assertEqual(metric.project, self.PROJECT)
56+
self.assertEqual(metric.full_name, FULL)
57+
self.assertEqual(metric.path, '/%s' % (FULL,))
58+
59+
def test_create_w_bound_client(self):
60+
FULL = 'projects/%s/metrics/%s' % (self.PROJECT, self.METRIC_NAME)
61+
RESOURCE = {
62+
'name': self.METRIC_NAME,
63+
'filter': self.FILTER,
64+
}
65+
conn = _Connection({'name': FULL})
66+
client = _Client(project=self.PROJECT, connection=conn)
67+
metric = self._makeOne(self.METRIC_NAME, self.FILTER, client=client)
68+
metric.create()
69+
self.assertEqual(len(conn._requested), 1)
70+
req = conn._requested[0]
71+
self.assertEqual(req['method'], 'PUT')
72+
self.assertEqual(req['path'], '/%s' % FULL)
73+
self.assertEqual(req['data'], RESOURCE)
74+
75+
def test_create_w_alternate_client(self):
76+
FULL = 'projects/%s/metrics/%s' % (self.PROJECT, self.METRIC_NAME)
77+
RESOURCE = {
78+
'name': self.METRIC_NAME,
79+
'filter': self.FILTER,
80+
'description': self.DESCRIPTION,
81+
}
82+
conn1 = _Connection({'name': FULL})
83+
client1 = _Client(project=self.PROJECT, connection=conn1)
84+
conn2 = _Connection({'name': FULL})
85+
client2 = _Client(project=self.PROJECT, connection=conn2)
86+
metric = self._makeOne(self.METRIC_NAME, self.FILTER, client=client1,
87+
description=self.DESCRIPTION)
88+
metric.create(client=client2)
89+
self.assertEqual(len(conn1._requested), 0)
90+
self.assertEqual(len(conn2._requested), 1)
91+
req = conn2._requested[0]
92+
self.assertEqual(req['method'], 'PUT')
93+
self.assertEqual(req['path'], '/%s' % FULL)
94+
self.assertEqual(req['data'], RESOURCE)
95+
96+
97+
class _Connection(object):
98+
99+
def __init__(self, *responses):
100+
self._responses = responses
101+
self._requested = []
102+
103+
def api_request(self, **kw):
104+
from gcloud.exceptions import NotFound
105+
self._requested.append(kw)
106+
107+
try:
108+
response, self._responses = self._responses[0], self._responses[1:]
109+
except: # pragma: NO COVER
110+
raise NotFound('miss')
111+
else:
112+
return response
113+
114+
115+
class _Client(object):
116+
117+
def __init__(self, project, connection=None):
118+
self.project = project
119+
self.connection = connection

0 commit comments

Comments
 (0)