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

Add support for parsing log entries w/ 'protoPayload' from resources #1578

Merged
merged 2 commits into from
Mar 22, 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
6 changes: 5 additions & 1 deletion gcloud/logging/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from gcloud.client import JSONClient
from gcloud.logging.connection import Connection
from gcloud.logging.entries import ProtobufEntry
from gcloud.logging.entries import StructEntry
from gcloud.logging.entries import TextEntry
from gcloud.logging.logger import Logger
Expand Down Expand Up @@ -71,13 +72,16 @@ def _entry_from_resource(self, resource, loggers):
:rtype; One of:
:class:`gcloud.logging.entries.TextEntry`,
:class:`gcloud.logging.entries.StructEntry`,
:class:`gcloud.logging.entries.ProtobufEntry`
:returns: the entry instance, constructed via the resource
"""
if 'textPayload' in resource:
return TextEntry.from_api_repr(resource, self, loggers)
elif 'jsonPayload' in resource:
return StructEntry.from_api_repr(resource, self, loggers)
raise ValueError('Cannot parse job resource')
elif 'protoPayload' in resource:
return ProtobufEntry.from_api_repr(resource, self, loggers)
raise ValueError('Cannot parse log entry resource')

def list_entries(self, projects=None, filter_=None, order_by=None,
page_size=None, page_token=None):
Expand Down
13 changes: 11 additions & 2 deletions gcloud/logging/entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def from_api_repr(cls, resource, client, loggers=None):


class TextEntry(_BaseEntry):
"""Entry created via a write request with ``textPayload``.
"""Entry created with ``textPayload``.

See:
https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/LogEntry
Expand All @@ -85,9 +85,18 @@ class TextEntry(_BaseEntry):


class StructEntry(_BaseEntry):
"""Entry created via a write request with ``jsonPayload``.
"""Entry created with ``jsonPayload``.

See:
https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/LogEntry
"""
_PAYLOAD_KEY = 'jsonPayload'


class ProtobufEntry(_BaseEntry):
"""Entry created with ``protoPayload``.

See:
https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/LogEntry
"""
_PAYLOAD_KEY = 'protoPayload'

This comment was marked as spam.

This comment was marked as spam.

30 changes: 29 additions & 1 deletion gcloud/logging/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@ def test_list_entries_defaults(self):
self.assertEqual(req['data'], SENT)

def test_list_entries_explicit(self):
# pylint: disable=too-many-statements
from datetime import datetime
from gcloud._helpers import UTC
from gcloud.logging import DESCENDING
from gcloud.logging.entries import ProtobufEntry
from gcloud.logging.entries import StructEntry
from gcloud.logging.logger import Logger
from gcloud.logging.test_entries import _datetime_to_rfc3339_w_nanos
Expand All @@ -116,7 +118,10 @@ def test_list_entries_explicit(self):
NOW = datetime.utcnow().replace(tzinfo=UTC)
TIMESTAMP = _datetime_to_rfc3339_w_nanos(NOW)
IID1 = 'IID1'
IID2 = 'IID2'
PAYLOAD = {'message': 'MESSAGE', 'weather': 'partly cloudy'}
PROTO_PAYLOAD = PAYLOAD.copy()
PROTO_PAYLOAD['@type'] = 'type.googleapis.com/testing.example'

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

TOKEN = 'TOKEN'
PAGE_SIZE = 42
SENT = {
Expand All @@ -136,6 +141,15 @@ def test_list_entries_explicit(self):
'timestamp': TIMESTAMP,
'logName': 'projects/%s/logs/%s' % (
self.PROJECT, self.LOGGER_NAME),
}, {
'protoPayload': PROTO_PAYLOAD,
'insertId': IID2,
'resource': {
'type': 'global',
},
'timestamp': TIMESTAMP,
'logName': 'projects/%s/logs/%s' % (
self.PROJECT, self.LOGGER_NAME),
}],
}
creds = _Credentials()
Expand All @@ -144,7 +158,8 @@ def test_list_entries_explicit(self):
entries, token = client.list_entries(
projects=[PROJECT1, PROJECT2], filter_=FILTER, order_by=DESCENDING,
page_size=PAGE_SIZE, page_token=TOKEN)
self.assertEqual(len(entries), 1)
self.assertEqual(len(entries), 2)

entry = entries[0]
self.assertTrue(isinstance(entry, StructEntry))
self.assertEqual(entry.insert_id, IID1)
Expand All @@ -155,6 +170,19 @@ def test_list_entries_explicit(self):
self.assertEqual(logger.name, self.LOGGER_NAME)
self.assertTrue(logger.client is client)
self.assertEqual(logger.project, self.PROJECT)

entry = entries[1]
self.assertTrue(isinstance(entry, ProtobufEntry))
self.assertEqual(entry.insert_id, IID2)
self.assertEqual(entry.payload, PROTO_PAYLOAD)
self.assertEqual(entry.timestamp, NOW)
logger = entry.logger
self.assertEqual(logger.name, self.LOGGER_NAME)
self.assertTrue(logger.client is client)
self.assertEqual(logger.project, self.PROJECT)

self.assertTrue(entries[0].logger is entries[1].logger)

self.assertEqual(token, None)
self.assertEqual(len(conn._requested), 1)
req = conn._requested[0]
Expand Down
119 changes: 10 additions & 109 deletions gcloud/logging/test_entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
import unittest2


class TestTextEntry(unittest2.TestCase):
class Test_BaseEntry(unittest2.TestCase):

PROJECT = 'PROJECT'
LOGGER_NAME = 'LOGGER_NAME'

def _getTargetClass(self):
from gcloud.logging.entries import TextEntry
return TextEntry
from gcloud.logging.entries import _BaseEntry

class _Dummy(_BaseEntry):
_PAYLOAD_KEY = 'dummyPayload'

return _Dummy

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
Expand Down Expand Up @@ -53,7 +57,7 @@ def test_from_api_repr_missing_data_no_loggers(self):
PAYLOAD = 'PAYLOAD'
LOG_NAME = 'projects/%s/logs/%s' % (self.PROJECT, self.LOGGER_NAME)
API_REPR = {
'textPayload': PAYLOAD,
'dummyPayload': PAYLOAD,
'logName': LOG_NAME,
}
klass = self._getTargetClass()
Expand All @@ -76,7 +80,7 @@ def test_from_api_repr_w_loggers_no_logger_match(self):
TIMESTAMP = _datetime_to_rfc3339_w_nanos(NOW)
LOG_NAME = 'projects/%s/logs/%s' % (self.PROJECT, self.LOGGER_NAME)
API_REPR = {
'textPayload': PAYLOAD,
'dummyPayload': PAYLOAD,
'logName': LOG_NAME,
'insertId': IID,
'timestamp': TIMESTAMP,
Expand All @@ -103,110 +107,7 @@ def test_from_api_repr_w_loggers_w_logger_match(self):
TIMESTAMP = _datetime_to_rfc3339_w_nanos(NOW)
LOG_NAME = 'projects/%s/logs/%s' % (self.PROJECT, self.LOGGER_NAME)
API_REPR = {
'textPayload': PAYLOAD,
'logName': LOG_NAME,
'insertId': IID,
'timestamp': TIMESTAMP,
}
LOGGER = object()
loggers = {LOG_NAME: LOGGER}
klass = self._getTargetClass()
entry = klass.from_api_repr(API_REPR, client, loggers=loggers)
self.assertEqual(entry.payload, PAYLOAD)
self.assertEqual(entry.insert_id, IID)
self.assertEqual(entry.timestamp, NOW)
self.assertTrue(entry.logger is LOGGER)


class TestStructEntry(unittest2.TestCase):

PROJECT = 'PROJECT'
LOGGER_NAME = 'LOGGER_NAME'

def _getTargetClass(self):
from gcloud.logging.entries import StructEntry
return StructEntry

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_ctor_defaults(self):
PAYLOAD = {'message': 'MESSAGE', 'weather': 'partly cloudy'}
logger = _Logger(self.LOGGER_NAME, self.PROJECT)
entry = self._makeOne(PAYLOAD, logger)
self.assertEqual(entry.payload, PAYLOAD)
self.assertTrue(entry.logger is logger)
self.assertTrue(entry.insert_id is None)
self.assertTrue(entry.timestamp is None)

def test_ctor_explicit(self):
import datetime
PAYLOAD = {'message': 'MESSAGE', 'weather': 'partly cloudy'}
IID = 'IID'
TIMESTAMP = datetime.datetime.now()
logger = _Logger(self.LOGGER_NAME, self.PROJECT)
entry = self._makeOne(PAYLOAD, logger, IID, TIMESTAMP)
self.assertEqual(entry.payload, PAYLOAD)
self.assertTrue(entry.logger is logger)
self.assertEqual(entry.insert_id, IID)
self.assertEqual(entry.timestamp, TIMESTAMP)

def test_from_api_repr_missing_data_no_loggers(self):
client = _Client(self.PROJECT)
PAYLOAD = {'message': 'MESSAGE', 'weather': 'partly cloudy'}
LOG_NAME = 'projects/%s/logs/%s' % (self.PROJECT, self.LOGGER_NAME)
API_REPR = {
'jsonPayload': PAYLOAD,
'logName': LOG_NAME,
}
klass = self._getTargetClass()
entry = klass.from_api_repr(API_REPR, client)
self.assertEqual(entry.payload, PAYLOAD)
self.assertTrue(entry.insert_id is None)
self.assertTrue(entry.timestamp is None)
logger = entry.logger
self.assertTrue(isinstance(logger, _Logger))
self.assertTrue(logger.client is client)
self.assertEqual(logger.name, self.LOGGER_NAME)

def test_from_api_repr_w_loggers_no_logger_match(self):
from datetime import datetime
from gcloud._helpers import UTC
client = _Client(self.PROJECT)
PAYLOAD = {'message': 'MESSAGE', 'weather': 'partly cloudy'}
IID = 'IID'
NOW = datetime.utcnow().replace(tzinfo=UTC)
TIMESTAMP = _datetime_to_rfc3339_w_nanos(NOW)
LOG_NAME = 'projects/%s/logs/%s' % (self.PROJECT, self.LOGGER_NAME)
API_REPR = {
'jsonPayload': PAYLOAD,
'logName': LOG_NAME,
'insertId': IID,
'timestamp': TIMESTAMP,
}
loggers = {}
klass = self._getTargetClass()
entry = klass.from_api_repr(API_REPR, client, loggers=loggers)
self.assertEqual(entry.payload, PAYLOAD)
self.assertEqual(entry.insert_id, IID)
self.assertEqual(entry.timestamp, NOW)
logger = entry.logger
self.assertTrue(isinstance(logger, _Logger))
self.assertTrue(logger.client is client)
self.assertEqual(logger.name, self.LOGGER_NAME)
self.assertEqual(loggers, {LOG_NAME: logger})

def test_from_api_repr_w_loggers_w_logger_match(self):
from datetime import datetime
from gcloud._helpers import UTC
client = _Client(self.PROJECT)
PAYLOAD = {'message': 'MESSAGE', 'weather': 'partly cloudy'}
IID = 'IID'
NOW = datetime.utcnow().replace(tzinfo=UTC)
TIMESTAMP = _datetime_to_rfc3339_w_nanos(NOW)
LOG_NAME = 'projects/%s/logs/%s' % (self.PROJECT, self.LOGGER_NAME)
API_REPR = {
'jsonPayload': PAYLOAD,
'dummyPayload': PAYLOAD,
'logName': LOG_NAME,
'insertId': IID,
'timestamp': TIMESTAMP,
Expand Down