Skip to content

Commit 77b91b9

Browse files
author
Bill Prin
committed
Add Factory Methods for Metric/Resource/Timeseries
1 parent ca1686c commit 77b91b9

File tree

5 files changed

+207
-0
lines changed

5 files changed

+207
-0
lines changed

gcloud/monitoring/client.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,22 @@
2828
https://cloud.google.com/monitoring/api/v3/
2929
"""
3030

31+
import datetime
32+
3133
from gcloud.client import JSONClient
3234
from gcloud.monitoring.connection import Connection
3335
from gcloud.monitoring.group import Group
36+
from gcloud.monitoring.metric import Metric
3437
from gcloud.monitoring.metric import MetricDescriptor
3538
from gcloud.monitoring.metric import MetricKind
3639
from gcloud.monitoring.metric import ValueType
3740
from gcloud.monitoring.query import Query
41+
from gcloud.monitoring.resource import Resource
3842
from gcloud.monitoring.resource import ResourceDescriptor
43+
from gcloud.monitoring.timeseries import Point
44+
from gcloud.monitoring.timeseries import TimeSeries
45+
46+
_UTCNOW = datetime.datetime.utcnow # To be replaced by tests.
3947

4048

4149
class Client(JSONClient):
@@ -195,6 +203,121 @@ def metric_descriptor(self, type_,
195203
display_name=display_name,
196204
)
197205

206+
@staticmethod
207+
def metric(type_, labels):
208+
"""Construct a metric object.
209+
210+
The type of the Metric should match the type of a MetricDescriptor.
211+
For a list of built-in Metric types and the associated labels, see:
212+
213+
https://cloud.google.com/monitoring/api/metrics
214+
215+
Here is an example of creating using a built-in metric type:
216+
217+
>>> metric = client.metric('instance/cpu/utilization' labels={
218+
... 'instance_name': 'my-instance',
219+
... })
220+
221+
For custom metrics, the simplest way to get the type is from the
222+
:class:`gcloud.monitoring.metric.MetricDescriptor` class used to
223+
create the custom metric::
224+
225+
>>> metric = client.metric(metric_descriptor.type, labels={
226+
... 'instance_name': 'my-instance',
227+
... })
228+
229+
:type type_: string
230+
:param type_: The metric type name.
231+
232+
:type labels: dict
233+
:param labels: A mapping from label names to values for all labels
234+
enumerated in the associated :class:`MetricDescriptor`.
235+
236+
:rtype: :class:`gcloud.metric.Metric`
237+
:returns: The Metric created with the passed in arguments
238+
"""
239+
return Metric(type=type_, labels=labels)
240+
241+
@staticmethod
242+
def resource(type_, labels):
243+
"""Construct a resource object.
244+
245+
For a list of possible MonitoredResources and their associated labels,
246+
see:
247+
248+
https://cloud.google.com/monitoring/api/resources
249+
250+
For example, to create a Resource object for a GCE instance::
251+
252+
>>> type_ = 'https://cloud.google.com/monitoring/api/resources'
253+
... resource = client.resource(type_, labels= {
254+
... 'project_id': 'my-project-id',
255+
... 'instance_id': 'my-instance-id',
256+
... 'zone': 'us-central1-f'
257+
... })
258+
259+
:type type_: string
260+
:param type_: The monitored resource type name.
261+
262+
:type labels: dict
263+
:param labels: A mapping from label names to values for all labels
264+
enumerated in the associated :class:`ResourceDescriptor`.
265+
266+
:rtype: :class:`gcloud.resource.Resource`
267+
:returns: The Resource created with the passed in arguments
268+
"""
269+
return Resource(type_, labels)
270+
271+
@staticmethod
272+
def timeseries(value, metric, resource,
273+
start_time=None, end_time=None):
274+
"""Constructs a TimeSeries object for a single data point.
275+
276+
Note that while TimeSeries objects returned by the API can have
277+
multiple data points when queried as aggregates, TimeSeries created
278+
on the client-side can have at most one point.
279+
280+
For example::
281+
282+
>>> timeseries = client.timeseries(value, metric, resource
283+
... end_time=end)
284+
285+
For more information, see:
286+
287+
https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TimeSeries
288+
289+
:type value: bool, int, string, or float
290+
:param value: The value of the data point to create for the TimeSeries.
291+
Note that this parameter can be multiple types and the TypedValue
292+
of the `gcloud.monitoring.TimeSeries.Point` will be mapped from
293+
the type passed in. For example, a Python float will be sent
294+
to the API as a doubleValue.
295+
296+
:type metric: :class:`~gcloud.monitoring.metric.Metric`
297+
:param metric: A metric object.
298+
299+
:type resource: :class:`~gcloud.monitoring.resource.Resource`
300+
:param resource: A resource object.
301+
302+
:type start_time: :class:`datetime.datetime`
303+
:param start_time: The start time for the point written to the
304+
timeseries. Defaults to None, which has meaning dependent on the
305+
metric_kind of the metric being written to.
306+
307+
:type end_time: :class`datetime.datetime`
308+
:param end_time: The end time for the point written to the timeseries.
309+
Defaults to the current time, as obtained by calling
310+
:meth:`datetime.datetime.utcnow`
311+
312+
:rtype: :class:`gcloud.timeseries.TimeSeries`
313+
:returns: The TimeSeries created with the passed in arguments
314+
"""
315+
if end_time is None:
316+
end_time = _UTCNOW()
317+
point = Point(value=value, start_time=start_time, end_time=end_time)
318+
return TimeSeries(metric=metric, resource=resource, metric_kind=None,
319+
value_type=None, points=[point])
320+
198321
def fetch_metric_descriptor(self, metric_type):
199322
"""Look up a metric descriptor by type.
200323

gcloud/monitoring/metric.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ def __repr__(self):
319319
class Metric(collections.namedtuple('Metric', 'type labels')):
320320
"""A specific metric identified by specifying values for all labels.
321321
322+
The preferred way to construct a metric object is using the
323+
:meth:`~gcloud.monitoring.client.Client.metric` factory method
324+
of the :class:`~gcloud.monitoring.client.Client` class.
325+
322326
:type type: string
323327
:param type: The metric type name.
324328

gcloud/monitoring/resource.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ def __repr__(self):
158158
class Resource(collections.namedtuple('Resource', 'type labels')):
159159
"""A monitored resource identified by specifying values for all labels.
160160
161+
The preferred way to construct a resource object is using the
162+
:meth:`~gcloud.monitoring.client.Client.resource` factory method
163+
of the :class:`~gcloud.monitoring.client.Client` class.
164+
161165
:type type: string
162166
:param type: The resource type name.
163167

gcloud/monitoring/test_client.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,78 @@ def test_metric_descriptor_factory(self):
157157
self.assertEqual(descriptor.description, DESCRIPTION)
158158
self.assertEqual(descriptor.display_name, '')
159159

160+
def test_metric_factory(self):
161+
TYPE = 'custom.googleapis.com/my_metric'
162+
LABELS = {
163+
'instance_name': 'my-instance'
164+
}
165+
166+
client = self._makeOne(project=PROJECT, credentials=_Credentials())
167+
client.connection = _Connection() # For safety's sake.
168+
metric = client.metric(TYPE, LABELS)
169+
self.assertEqual(metric.type, TYPE)
170+
self.assertEqual(metric.labels, LABELS)
171+
172+
def test_resource_factory(self):
173+
TYPE = 'https://cloud.google.com/monitoring/api/resources'
174+
LABELS = {
175+
'project_id': 'my-project-id',
176+
'instance_id': 'my-instance-id',
177+
'zone': 'us-central1-f'
178+
}
179+
180+
client = self._makeOne(project=PROJECT, credentials=_Credentials())
181+
client.connection = _Connection() # For safety's sake.
182+
resource = client.resource(TYPE, LABELS)
183+
self.assertEqual(resource.type, TYPE)
184+
self.assertEqual(resource.labels, LABELS)
185+
186+
def test_timeseries_factory(self):
187+
import datetime
188+
from gcloud._testing import _Monkey
189+
import gcloud.monitoring.client
190+
METRIC_TYPE = 'custom.googleapis.com/my_metric'
191+
METRIC_LABELS = {
192+
'instance_name': 'my-instance'
193+
}
194+
195+
RESOURCE_TYPE = 'https://cloud.google.com/monitoring/api/resources'
196+
RESOURCE_LABELS = {
197+
'project_id': 'my-project-id',
198+
'instance_id': 'my-instance-id',
199+
'zone': 'us-central1-f'
200+
}
201+
202+
VALUE = 42
203+
204+
client = self._makeOne(project=PROJECT, credentials=_Credentials())
205+
client.connection = _Connection() # For safety's sake.
206+
metric = client.metric(METRIC_TYPE, METRIC_LABELS)
207+
resource = client.resource(RESOURCE_TYPE, RESOURCE_LABELS)
208+
NOW = datetime.datetime.utcnow()
209+
timeseries = client.timeseries(VALUE, metric, resource, end_time=NOW)
210+
211+
self.assertEqual(timeseries.metric, metric)
212+
self.assertEqual(timeseries.resource, resource)
213+
self.assertEqual(len(timeseries.points), 1)
214+
self.assertEqual(timeseries.points[0].value, VALUE)
215+
self.assertIsNone(timeseries.points[0].start_time)
216+
self.assertEqual(timeseries.points[0].end_time, NOW)
217+
218+
NEW_NOW = datetime.datetime.utcnow()
219+
timeseries_with_start = client.timeseries(VALUE, metric,
220+
resource,
221+
start_time=NOW,
222+
end_time=NEW_NOW)
223+
self.assertEqual(timeseries_with_start.points[0].start_time, NOW)
224+
self.assertEqual(timeseries_with_start.points[0].end_time, NEW_NOW)
225+
226+
with _Monkey(gcloud.monitoring.client, _UTCNOW=lambda: NOW):
227+
timeseries_no_end = client.timeseries(VALUE, metric, resource)
228+
229+
self.assertEqual(timeseries_no_end.points[0].end_time, NOW)
230+
self.assertIsNone(timeseries_no_end.points[0].start_time)
231+
160232
def test_fetch_metric_descriptor(self):
161233
TYPE = 'custom.googleapis.com/my_metric'
162234
NAME = 'projects/{project}/metricDescriptors/{type}'.format(

gcloud/monitoring/timeseries.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class TimeSeries(collections.namedtuple(
3232
'TimeSeries', 'metric resource metric_kind value_type points')):
3333
"""A single time series of metric values.
3434
35+
The preferred way to construct a TimeSeries object is using the
36+
:meth:`~gcloud.monitoring.client.Client.timeseries` factory method
37+
of the :class:`~gcloud.monitoring.client.Client` class.
38+
3539
:type metric: :class:`~gcloud.monitoring.metric.Metric`
3640
:param metric: A metric object.
3741

0 commit comments

Comments
 (0)