Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating list_metrics() to Iterator pattern. #2653

Merged
merged 4 commits into from
Nov 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/logging-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ List all metrics for a project:

>>> from google.cloud import logging
>>> client = logging.Client()
>>> metrics, token = client.list_metrics()
>>> metrics = list(client.list_metrics())
>>> len(metrics)
1
>>> metric = metrics[0]
Expand Down
31 changes: 23 additions & 8 deletions logging/google/cloud/logging/_gax.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from google.cloud.iterator import GAXIterator
from google.cloud.logging._helpers import entry_from_resource
from google.cloud.logging.sink import Sink
from google.cloud.logging.metric import Metric


class _LoggingAPI(object):
Expand Down Expand Up @@ -316,21 +317,18 @@ def list_metrics(self, project, page_size=0, page_token=None):
passed, the API will return the first page of
metrics.

:rtype: tuple, (list, str)
:returns: list of mappings, plus a "next page token" string:
if not None, indicates that more metrics can be retrieved
with another call (pass that value as ``page_token``).
:rtype: :class:`~google.cloud.iterator.Iterator`
:returns: Iterator of
:class:`~google.cloud.logging.metric.Metric`
accessible to the current API.
"""
if page_token is None:
page_token = INITIAL_PAGE
options = CallOptions(page_token=page_token)
path = 'projects/%s' % (project,)
page_iter = self._gax_api.list_log_metrics(
path, page_size=page_size, options=options)
metrics = [MessageToDict(log_metric_pb)
for log_metric_pb in page_iter.next()]
token = page_iter.page_token or None
return metrics, token
return GAXIterator(self._client, page_iter, _item_to_metric)

def metric_create(self, project, metric_name, filter_, description):
"""API call: create a metric resource.
Expand Down Expand Up @@ -496,3 +494,20 @@ def _item_to_sink(iterator, log_sink_pb):
"""
resource = MessageToDict(log_sink_pb)
return Sink.from_api_repr(resource, iterator.client)


def _item_to_metric(iterator, log_metric_pb):
"""Convert a metric protobuf to the native object.

:type iterator: :class:`~google.cloud.iterator.Iterator`
:param iterator: The iterator that is currently in use.

:type log_metric_pb:
:class:`~google.logging.v2.logging_metrics_pb2.LogMetric`
:param log_metric_pb: Metric protobuf returned from the API.

:rtype: :class:`~google.cloud.logging.metric.Metric`
:returns: The next metric in the page.
"""
resource = MessageToDict(log_metric_pb)
return Metric.from_api_repr(resource, iterator.client)
13 changes: 4 additions & 9 deletions logging/google/cloud/logging/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,9 @@ def list_metrics(self, page_size=None, page_token=None):
passed, the API will return the first page of
metrics.

:rtype: tuple, (list, str)
:returns: list of :class:`google.cloud.logging.metric.Metric`, plus a
"next page token" string: if not None, indicates that
more metrics can be retrieved with another call (pass that
value as ``page_token``).
:rtype: :class:`~google.cloud.iterator.Iterator`
:returns: Iterator of :class:`~google.cloud.logging.metric.Metric`
accessible to the current client.
"""
resources, token = self.metrics_api.list_metrics(
return self.metrics_api.list_metrics(
self.project, page_size, page_token)
metrics = [Metric.from_api_repr(resource, self)
for resource in resources]
return metrics, token
39 changes: 26 additions & 13 deletions logging/google/cloud/logging/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from google.cloud.iterator import HTTPIterator
from google.cloud.logging._helpers import entry_from_resource
from google.cloud.logging.sink import Sink
from google.cloud.logging.metric import Metric


class Connection(base_connection.JSONConnection):
Expand Down Expand Up @@ -347,24 +348,21 @@ def list_metrics(self, project, page_size=None, page_token=None):
passed, the API will return the first page of
metrics.

:rtype: tuple, (list, str)
:returns: list of mappings, plus a "next page token" string:
if not None, indicates that more metrics can be retrieved
with another call (pass that value as ``page_token``).
:rtype: :class:`~google.cloud.iterator.Iterator`
:returns: Iterator of
:class:`~google.cloud.logging.metric.Metric`
accessible to the current API.
"""
params = {}
extra_params = {}

if page_size is not None:
params['pageSize'] = page_size

if page_token is not None:
params['pageToken'] = page_token
extra_params['pageSize'] = page_size

path = '/projects/%s/metrics' % (project,)
resp = self._connection.api_request(
method='GET', path=path, query_params=params)
metrics = resp.get('metrics', ())
return metrics, resp.get('nextPageToken')
return HTTPIterator(
client=self._client, path=path,
item_to_value=_item_to_metric, items_key='metrics',
page_token=page_token, extra_params=extra_params)

def metric_create(self, project, metric_name, filter_, description=None):
"""API call: create a metric resource.
Expand Down Expand Up @@ -497,3 +495,18 @@ def _item_to_sink(iterator, resource):
:returns: The next sink in the page.
"""
return Sink.from_api_repr(resource, iterator.client)


def _item_to_metric(iterator, resource):
"""Convert a metric resource to the native object.

:type iterator: :class:`~google.cloud.iterator.Iterator`
:param iterator: The iterator that is currently in use.

:type resource: dict
:param resource: Metric JSON resource returned from the API.

:rtype: :class:`~google.cloud.logging.metric.Metric`
:returns: The next metric in the page.
"""
return Metric.from_api_repr(resource, iterator.client)
52 changes: 34 additions & 18 deletions logging/unit_tests/test__gax.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,56 +843,72 @@ def test_ctor(self):
self.assertIs(api._gax_api, gax_api)

def test_list_metrics_no_paging(self):
import six
from google.gax import INITIAL_PAGE
from google.cloud._testing import _GAXPageIterator
from google.logging.v2.logging_metrics_pb2 import LogMetric
from google.cloud._testing import _GAXPageIterator
from google.cloud.logging.metric import Metric

TOKEN = 'TOKEN'
METRICS = [{
'name': self.METRIC_PATH,
'filter': self.FILTER,
'description': self.DESCRIPTION,
}]
metric_pb = LogMetric(name=self.METRIC_PATH,
description=self.DESCRIPTION,
filter=self.FILTER)
response = _GAXPageIterator([metric_pb], page_token=TOKEN)
gax_api = _GAXMetricsAPI(_list_log_metrics_response=response)
api = self._makeOne(gax_api, None)
client = object()
api = self._makeOne(gax_api, client)

metrics, token = api.list_metrics(self.PROJECT)
iterator = api.list_metrics(self.PROJECT)
page = six.next(iterator.pages)
metrics = list(page)
token = iterator.next_page_token

self.assertEqual(metrics, METRICS)
# First check the token.
self.assertEqual(token, TOKEN)
# Then check the metrics returned.
self.assertEqual(len(metrics), 1)
metric = metrics[0]
self.assertIsInstance(metric, Metric)
self.assertEqual(metric.name, self.METRIC_PATH)
self.assertEqual(metric.filter_, self.FILTER)
self.assertEqual(metric.description, self.DESCRIPTION)
self.assertIs(metric.client, client)

project, page_size, options = gax_api._list_log_metrics_called_with
self.assertEqual(project, self.PROJECT_PATH)
self.assertEqual(page_size, 0)
self.assertEqual(options.page_token, INITIAL_PAGE)

def test_list_metrics_w_paging(self):
from google.cloud._testing import _GAXPageIterator
from google.logging.v2.logging_metrics_pb2 import LogMetric
from google.cloud._testing import _GAXPageIterator
from google.cloud.logging.metric import Metric

TOKEN = 'TOKEN'
PAGE_SIZE = 42
METRICS = [{
'name': self.METRIC_PATH,
'filter': self.FILTER,
'description': self.DESCRIPTION,
}]
metric_pb = LogMetric(name=self.METRIC_PATH,
description=self.DESCRIPTION,
filter=self.FILTER)
response = _GAXPageIterator([metric_pb])
gax_api = _GAXMetricsAPI(_list_log_metrics_response=response)
api = self._makeOne(gax_api, None)
client = object()
api = self._makeOne(gax_api, client)

metrics, token = api.list_metrics(
iterator = api.list_metrics(
self.PROJECT, page_size=PAGE_SIZE, page_token=TOKEN)
metrics = list(iterator)
token = iterator.next_page_token

self.assertEqual(metrics, METRICS)
# First check the token.
self.assertIsNone(token)
# Then check the metrics returned.
self.assertEqual(len(metrics), 1)
metric = metrics[0]
self.assertIsInstance(metric, Metric)
self.assertEqual(metric.name, self.METRIC_PATH)
self.assertEqual(metric.filter_, self.FILTER)
self.assertEqual(metric.description, self.DESCRIPTION)
self.assertIs(metric.client, client)

project, page_size, options = gax_api._list_log_metrics_called_with
self.assertEqual(project, self.PROJECT_PATH)
Expand Down
86 changes: 57 additions & 29 deletions logging/unit_tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,55 +486,90 @@ def test_metric_explicit(self):

def test_list_metrics_no_paging(self):
from google.cloud.logging.metric import Metric
PROJECT = 'PROJECT'
TOKEN = 'TOKEN'
METRICS = [{

metrics = [{
'name': self.METRIC_NAME,
'filter': self.FILTER,
'description': self.DESCRIPTION,
}]
client = self._makeOne(project=PROJECT, credentials=_Credentials())
api = client._metrics_api = _DummyMetricsAPI()
api._list_metrics_response = METRICS, TOKEN
client = self._makeOne(
project=self.PROJECT, credentials=_Credentials(),
use_gax=False)
returned = {
'metrics': metrics,
}
client.connection = _Connection(returned)

metrics, token = client.list_metrics()
# Execute request.
iterator = client.list_metrics()
metrics = list(iterator)

# Check the metrics returned.
self.assertEqual(len(metrics), 1)
metric = metrics[0]
self.assertIsInstance(metric, Metric)
self.assertEqual(metric.name, self.METRIC_NAME)
self.assertEqual(metric.filter_, self.FILTER)
self.assertEqual(metric.description, self.DESCRIPTION)
self.assertEqual(token, TOKEN)
self.assertEqual(api._list_metrics_called_with,
(PROJECT, None, None))
self.assertIs(metric.client, client)

# Verify mocked transport.
called_with = client.connection._called_with
path = '/projects/%s/metrics' % (self.PROJECT,)
self.assertEqual(called_with, {
'method': 'GET',
'path': path,
'query_params': {},
})

def test_list_metrics_with_paging(self):
import six
from google.cloud.logging.metric import Metric
PROJECT = 'PROJECT'
TOKEN = 'TOKEN'
PAGE_SIZE = 42
METRICS = [{

token = 'TOKEN'
next_token = 'T00KEN'
page_size = 42
metrics = [{
'name': self.METRIC_NAME,
'filter': self.FILTER,
'description': self.DESCRIPTION,
}]
client = self._makeOne(project=PROJECT, credentials=_Credentials())
api = client._metrics_api = _DummyMetricsAPI()
api._list_metrics_response = METRICS, None
client = self._makeOne(
project=self.PROJECT, credentials=_Credentials(),
use_gax=False)
returned = {
'metrics': metrics,
'nextPageToken': next_token,
}
client.connection = _Connection(returned)

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.


# Execute request.
metrics, token = client.list_metrics(PAGE_SIZE, TOKEN)
# Test values are correct.
iterator = client.list_metrics(page_size, token)
page = six.next(iterator.pages)
metrics = list(page)

# First check the token.
self.assertEqual(iterator.next_page_token, next_token)
# Then check the metrics returned.
self.assertEqual(len(metrics), 1)
metric = metrics[0]
self.assertIsInstance(metric, Metric)
self.assertEqual(metric.name, self.METRIC_NAME)
self.assertEqual(metric.filter_, self.FILTER)
self.assertEqual(metric.description, self.DESCRIPTION)
self.assertIsNone(token)
self.assertEqual(api._list_metrics_called_with,
(PROJECT, PAGE_SIZE, TOKEN))
self.assertIs(metric.client, client)

# Verify mocked transport.
called_with = client.connection._called_with
path = '/projects/%s/metrics' % (self.PROJECT,)
self.assertEqual(called_with, {
'method': 'GET',
'path': path,
'query_params': {
'pageSize': page_size,
'pageToken': token,
},
})


class _Credentials(object):
Expand All @@ -550,13 +585,6 @@ def create_scoped(self, scope):
return self


class _DummyMetricsAPI(object):

def list_metrics(self, project, page_size, page_token):
self._list_metrics_called_with = (project, page_size, page_token)
return self._list_metrics_response


class _Connection(object):

_called_with = None
Expand Down
Loading