From 36a9520f28819a693bef829a48b664da95806ed7 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Mon, 28 Mar 2016 16:03:26 -0400 Subject: [PATCH 1/2] Add 'severity'/'http_request' attrs to '_BaseEntry'. Parse from API resource if found. --- gcloud/logging/entries.py | 18 ++++++++++++--- gcloud/logging/test_entries.py | 40 ++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/gcloud/logging/entries.py b/gcloud/logging/entries.py index ca1cf62f5db4..e26ac7ef0cd3 100644 --- a/gcloud/logging/entries.py +++ b/gcloud/logging/entries.py @@ -40,14 +40,23 @@ class _BaseEntry(object): :type labels: dict or :class:`NoneType` :param labels: (optional) mapping of labels for the entry + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry """ - def __init__(self, payload, logger, - insert_id=None, timestamp=None, labels=None): + def __init__(self, payload, logger, insert_id=None, timestamp=None, + labels=None, severity=None, http_request=None): self.payload = payload self.logger = logger self.insert_id = insert_id self.timestamp = timestamp self.labels = labels + self.severity = severity + self.http_request = http_request @classmethod def from_api_repr(cls, resource, client, loggers=None): @@ -82,7 +91,10 @@ def from_api_repr(cls, resource, client, loggers=None): if timestamp is not None: timestamp = _rfc3339_nanos_to_datetime(timestamp) labels = resource.get('labels') - return cls(payload, logger, insert_id, timestamp, labels) + severity = resource.get('severity') + http_request = resource.get('httpRequest') + return cls(payload, logger, insert_id=insert_id, timestamp=timestamp, + labels=labels, severity=severity, http_request=http_request) class TextEntry(_BaseEntry): diff --git a/gcloud/logging/test_entries.py b/gcloud/logging/test_entries.py index 2da275d71ea0..cb78d51a2e18 100644 --- a/gcloud/logging/test_entries.py +++ b/gcloud/logging/test_entries.py @@ -40,6 +40,8 @@ def test_ctor_defaults(self): self.assertTrue(entry.insert_id is None) self.assertTrue(entry.timestamp is None) self.assertTrue(entry.labels is None) + self.assertTrue(entry.severity is None) + self.assertTrue(entry.http_request is None) def test_ctor_explicit(self): import datetime @@ -47,13 +49,31 @@ def test_ctor_explicit(self): IID = 'IID' TIMESTAMP = datetime.datetime.now() LABELS = {'foo': 'bar', 'baz': 'qux'} + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' logger = _Logger(self.LOGGER_NAME, self.PROJECT) - entry = self._makeOne(PAYLOAD, logger, IID, TIMESTAMP, LABELS) + entry = self._makeOne(PAYLOAD, logger, + insert_id=IID, + timestamp=TIMESTAMP, + labels=LABELS, + severity=SEVERITY, + http_request={ + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + }, + ) self.assertEqual(entry.payload, PAYLOAD) self.assertTrue(entry.logger is logger) self.assertEqual(entry.insert_id, IID) self.assertEqual(entry.timestamp, TIMESTAMP) self.assertEqual(entry.labels, LABELS) + self.assertEqual(entry.severity, SEVERITY) + self.assertEqual(entry.http_request['requestMethod'], METHOD) + self.assertEqual(entry.http_request['requestUrl'], URI) + self.assertEqual(entry.http_request['status'], STATUS) def test_from_api_repr_missing_data_no_loggers(self): client = _Client(self.PROJECT) @@ -68,6 +88,8 @@ def test_from_api_repr_missing_data_no_loggers(self): self.assertEqual(entry.payload, PAYLOAD) self.assertTrue(entry.insert_id is None) self.assertTrue(entry.timestamp is None) + self.assertTrue(entry.severity is None) + self.assertTrue(entry.http_request is None) logger = entry.logger self.assertTrue(isinstance(logger, _Logger)) self.assertTrue(logger.client is client) @@ -76,27 +98,41 @@ def test_from_api_repr_missing_data_no_loggers(self): def test_from_api_repr_w_loggers_no_logger_match(self): from datetime import datetime from gcloud._helpers import UTC + klass = self._getTargetClass() client = _Client(self.PROJECT) PAYLOAD = 'PAYLOAD' + SEVERITY = 'CRITICAL' 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) LABELS = {'foo': 'bar', 'baz': 'qux'} + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' API_REPR = { 'dummyPayload': PAYLOAD, 'logName': LOG_NAME, 'insertId': IID, 'timestamp': TIMESTAMP, 'labels': LABELS, + 'severity': SEVERITY, + 'httpRequest': { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + }, } 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) self.assertEqual(entry.labels, LABELS) + self.assertEqual(entry.severity, SEVERITY) + self.assertEqual(entry.http_request['requestMethod'], METHOD) + self.assertEqual(entry.http_request['requestUrl'], URI) + self.assertEqual(entry.http_request['status'], STATUS) logger = entry.logger self.assertTrue(isinstance(logger, _Logger)) self.assertTrue(logger.client is client) From 145cbfbdce788e1b81883b97955919974b4057ea Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Mon, 28 Mar 2016 16:36:16 -0400 Subject: [PATCH 2/2] Add support for logging w/ per-request metadata. - insert_id - severity - http_request See: #1566. --- gcloud/logging/logger.py | 129 +++++++++++++++++++--- gcloud/logging/test_entries.py | 12 +-- gcloud/logging/test_logger.py | 189 ++++++++++++++++++++++++++------- 3 files changed, 273 insertions(+), 57 deletions(-) diff --git a/gcloud/logging/logger.py b/gcloud/logging/logger.py index f9dc41ff6459..f7bb50ee4a80 100644 --- a/gcloud/logging/logger.py +++ b/gcloud/logging/logger.py @@ -89,7 +89,8 @@ def batch(self, client=None): return Batch(self, client) def _make_entry_resource(self, text=None, info=None, message=None, - labels=None): + labels=None, insert_id=None, severity=None, + http_request=None): """Return a log entry resource of the appropriate type. Helper for :meth:`log_text`, :meth:`log_struct`, and :meth:`log_proto`. @@ -107,6 +108,16 @@ def _make_entry_resource(self, text=None, info=None, message=None, :type labels: dict or :class:`NoneType` :param labels: labels passed in to calling method. + + :type insert_id: string or :class:`NoneType` + :param insert_id: (optional) unique ID for log entry. + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry """ resource = { 'logName': self.full_name, @@ -130,9 +141,19 @@ def _make_entry_resource(self, text=None, info=None, message=None, if labels is not None: resource['labels'] = labels + if insert_id is not None: + resource['insertId'] = insert_id + + if severity is not None: + resource['severity'] = severity + + if http_request is not None: + resource['httpRequest'] = http_request + return resource - def log_text(self, text, client=None, labels=None): + def log_text(self, text, client=None, labels=None, insert_id=None, + severity=None, http_request=None): """API call: log a text message via a POST request See: @@ -147,16 +168,28 @@ def log_text(self, text, client=None, labels=None): :type labels: dict or :class:`NoneType` :param labels: (optional) mapping of labels for the entry. + + :type insert_id: string or :class:`NoneType` + :param insert_id: (optional) unique ID for log entry. + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry """ client = self._require_client(client) - entry_resource = self._make_entry_resource(text=text, labels=labels) - + entry_resource = self._make_entry_resource( + text=text, labels=labels, insert_id=insert_id, severity=severity, + http_request=http_request) data = {'entries': [entry_resource]} client.connection.api_request( method='POST', path='/entries:write', data=data) - def log_struct(self, info, client=None, labels=None): + def log_struct(self, info, client=None, labels=None, insert_id=None, + severity=None, http_request=None): """API call: log a structured message via a POST request See: @@ -171,15 +204,28 @@ def log_struct(self, info, client=None, labels=None): :type labels: dict or :class:`NoneType` :param labels: (optional) mapping of labels for the entry. + + :type insert_id: string or :class:`NoneType` + :param insert_id: (optional) unique ID for log entry. + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry """ client = self._require_client(client) - entry_resource = self._make_entry_resource(info=info, labels=labels) + entry_resource = self._make_entry_resource( + info=info, labels=labels, insert_id=insert_id, severity=severity, + http_request=http_request) data = {'entries': [entry_resource]} client.connection.api_request( method='POST', path='/entries:write', data=data) - def log_proto(self, message, client=None, labels=None): + def log_proto(self, message, client=None, labels=None, insert_id=None, + severity=None, http_request=None): """API call: log a protobuf message via a POST request See: @@ -194,10 +240,21 @@ def log_proto(self, message, client=None, labels=None): :type labels: dict or :class:`NoneType` :param labels: (optional) mapping of labels for the entry. + + :type insert_id: string or :class:`NoneType` + :param insert_id: (optional) unique ID for log entry. + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry """ client = self._require_client(client) entry_resource = self._make_entry_resource( - message=message, labels=labels) + message=message, labels=labels, insert_id=insert_id, + severity=severity, http_request=http_request) data = {'entries': [entry_resource]} client.connection.api_request( @@ -283,7 +340,8 @@ def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is None: self.commit() - def log_text(self, text, labels=None): + def log_text(self, text, labels=None, insert_id=None, severity=None, + http_request=None): """Add a text entry to be logged during :meth:`commit`. :type text: string @@ -291,10 +349,22 @@ def log_text(self, text, labels=None): :type labels: dict or :class:`NoneType` :param labels: (optional) mapping of labels for the entry. + + :type insert_id: string or :class:`NoneType` + :param insert_id: (optional) unique ID for log entry. + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry. """ - self.entries.append(('text', text, labels)) + self.entries.append( + ('text', text, labels, insert_id, severity, http_request)) - def log_struct(self, info, labels=None): + def log_struct(self, info, labels=None, insert_id=None, severity=None, + http_request=None): """Add a struct entry to be logged during :meth:`commit`. :type info: dict @@ -302,10 +372,22 @@ def log_struct(self, info, labels=None): :type labels: dict or :class:`NoneType` :param labels: (optional) mapping of labels for the entry. + + :type insert_id: string or :class:`NoneType` + :param insert_id: (optional) unique ID for log entry. + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry. """ - self.entries.append(('struct', info, labels)) + self.entries.append( + ('struct', info, labels, insert_id, severity, http_request)) - def log_proto(self, message, labels=None): + def log_proto(self, message, labels=None, insert_id=None, severity=None, + http_request=None): """Add a protobuf entry to be logged during :meth:`commit`. :type message: protobuf message @@ -313,8 +395,19 @@ def log_proto(self, message, labels=None): :type labels: dict or :class:`NoneType` :param labels: (optional) mapping of labels for the entry. + + :type insert_id: string or :class:`NoneType` + :param insert_id: (optional) unique ID for log entry. + + :type severity: string or :class:`NoneType` + :param severity: (optional) severity of event being logged. + + :type http_request: dict or :class:`NoneType` + :param http_request: (optional) info about HTTP request associated with + the entry. """ - self.entries.append(('proto', message, labels)) + self.entries.append( + ('proto', message, labels, insert_id, severity, http_request)) def commit(self, client=None): """Send saved log entries as a single API call. @@ -334,7 +427,7 @@ def commit(self, client=None): data['labels'] = self.logger.labels entries = data['entries'] = [] - for entry_type, entry, labels in self.entries: + for entry_type, entry, labels, iid, severity, http_req in self.entries: if entry_type == 'text': info = {'textPayload': entry} elif entry_type == 'struct': @@ -347,6 +440,12 @@ def commit(self, client=None): raise ValueError('Unknown entry type: %s' % (entry_type,)) if labels is not None: info['labels'] = labels + if iid is not None: + info['insertId'] = iid + if severity is not None: + info['severity'] = severity + if http_req is not None: + info['httpRequest'] = http_req entries.append(info) client.connection.api_request( diff --git a/gcloud/logging/test_entries.py b/gcloud/logging/test_entries.py index cb78d51a2e18..312e456d63e0 100644 --- a/gcloud/logging/test_entries.py +++ b/gcloud/logging/test_entries.py @@ -53,18 +53,18 @@ def test_ctor_explicit(self): METHOD = 'POST' URI = 'https://api.example.com/endpoint' STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } logger = _Logger(self.LOGGER_NAME, self.PROJECT) entry = self._makeOne(PAYLOAD, logger, insert_id=IID, timestamp=TIMESTAMP, labels=LABELS, severity=SEVERITY, - http_request={ - 'requestMethod': METHOD, - 'requestUrl': URI, - 'status': STATUS, - }, - ) + http_request=REQUEST) self.assertEqual(entry.payload, PAYLOAD) self.assertTrue(entry.logger is logger) self.assertEqual(entry.insert_id, IID) diff --git a/gcloud/logging/test_logger.py b/gcloud/logging/test_logger.py index ad698de504f9..069ad2f47d2e 100644 --- a/gcloud/logging/test_logger.py +++ b/gcloud/logging/test_logger.py @@ -123,16 +123,27 @@ def test_log_text_w_default_labels(self): self.assertEqual(req['path'], '/entries:write') self.assertEqual(req['data'], SENT) - def test_log_text_w_unicode_explicit_client_and_labels(self): + def test_log_text_w_unicode_explicit_client_labels_severity_httpreq(self): TEXT = u'TEXT' DEFAULT_LABELS = {'foo': 'spam'} LABELS = {'foo': 'bar', 'baz': 'qux'} + IID = 'IID' + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } conn = _Connection({}) client1 = _Client(self.PROJECT, object()) client2 = _Client(self.PROJECT, conn) logger = self._makeOne(self.LOGGER_NAME, client=client1, labels=DEFAULT_LABELS) - logger.log_text(TEXT, client=client2, labels=LABELS) + logger.log_text(TEXT, client=client2, labels=LABELS, + insert_id=IID, severity=SEVERITY, http_request=REQUEST) self.assertEqual(len(conn._requested), 1) req = conn._requested[0] SENT = { @@ -144,6 +155,9 @@ def test_log_text_w_unicode_explicit_client_and_labels(self): 'type': 'global', }, 'labels': LABELS, + 'insertId': IID, + 'severity': SEVERITY, + 'httpRequest': REQUEST, }], } self.assertEqual(req['method'], 'POST') @@ -197,16 +211,28 @@ def test_log_struct_w_default_labels(self): self.assertEqual(req['path'], '/entries:write') self.assertEqual(req['data'], SENT) - def test_log_struct_w_explicit_client_and_labels(self): + def test_log_struct_w_explicit_client_labels_severity_httpreq(self): STRUCT = {'message': 'MESSAGE', 'weather': 'cloudy'} DEFAULT_LABELS = {'foo': 'spam'} LABELS = {'foo': 'bar', 'baz': 'qux'} + IID = 'IID' + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } conn = _Connection({}) client1 = _Client(self.PROJECT, object()) client2 = _Client(self.PROJECT, conn) logger = self._makeOne(self.LOGGER_NAME, client=client1, labels=DEFAULT_LABELS) - logger.log_struct(STRUCT, client=client2, labels=LABELS) + logger.log_struct(STRUCT, client=client2, labels=LABELS, + insert_id=IID, severity=SEVERITY, + http_request=REQUEST) self.assertEqual(len(conn._requested), 1) req = conn._requested[0] SENT = { @@ -218,6 +244,9 @@ def test_log_struct_w_explicit_client_and_labels(self): 'type': 'global', }, 'labels': LABELS, + 'insertId': IID, + 'severity': SEVERITY, + 'httpRequest': REQUEST, }], } self.assertEqual(req['method'], 'POST') @@ -277,19 +306,31 @@ def test_log_proto_w_default_labels(self): self.assertEqual(req['path'], '/entries:write') self.assertEqual(req['data'], SENT) - def test_log_proto_w_explicit_client_and_labels(self): + def test_log_proto_w_explicit_client_labels_severity_httpreq(self): import json from google.protobuf.json_format import MessageToJson from google.protobuf.struct_pb2 import Struct, Value message = Struct(fields={'foo': Value(bool_value=True)}) DEFAULT_LABELS = {'foo': 'spam'} LABELS = {'foo': 'bar', 'baz': 'qux'} + IID = 'IID' + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } conn = _Connection({}) client1 = _Client(self.PROJECT, object()) client2 = _Client(self.PROJECT, conn) logger = self._makeOne(self.LOGGER_NAME, client=client1, labels=DEFAULT_LABELS) - logger.log_proto(message, client=client2, labels=LABELS) + logger.log_proto(message, client=client2, labels=LABELS, + insert_id=IID, severity=SEVERITY, + http_request=REQUEST) self.assertEqual(len(conn._requested), 1) req = conn._requested[0] SENT = { @@ -301,6 +342,9 @@ def test_log_proto_w_explicit_client_and_labels(self): 'type': 'global', }, 'labels': LABELS, + 'insertId': IID, + 'severity': SEVERITY, + 'httpRequest': REQUEST, }], } self.assertEqual(req['method'], 'POST') @@ -402,18 +446,31 @@ def test_log_text_defaults(self): batch = self._makeOne(logger, client=CLIENT) batch.log_text(TEXT) self.assertEqual(len(connection._requested), 0) - self.assertEqual(batch.entries, [('text', TEXT, None)]) + self.assertEqual(batch.entries, + [('text', TEXT, None, None, None, None)]) def test_log_text_explicit(self): TEXT = 'This is the entry text' LABELS = {'foo': 'bar', 'baz': 'qux'} + IID = 'IID' + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } connection = _Connection() CLIENT = _Client(project=self.PROJECT, connection=connection) logger = _Logger() batch = self._makeOne(logger, client=CLIENT) - batch.log_text(TEXT, labels=LABELS) + batch.log_text(TEXT, labels=LABELS, insert_id=IID, severity=SEVERITY, + http_request=REQUEST) self.assertEqual(len(connection._requested), 0) - self.assertEqual(batch.entries, [('text', TEXT, LABELS)]) + self.assertEqual(batch.entries, + [('text', TEXT, LABELS, IID, SEVERITY, REQUEST)]) def test_log_struct_defaults(self): STRUCT = {'message': 'Message text', 'weather': 'partly cloudy'} @@ -423,18 +480,31 @@ def test_log_struct_defaults(self): batch = self._makeOne(logger, client=CLIENT) batch.log_struct(STRUCT) self.assertEqual(len(connection._requested), 0) - self.assertEqual(batch.entries, [('struct', STRUCT, None)]) + self.assertEqual(batch.entries, + [('struct', STRUCT, None, None, None, None)]) def test_log_struct_explicit(self): STRUCT = {'message': 'Message text', 'weather': 'partly cloudy'} LABELS = {'foo': 'bar', 'baz': 'qux'} + IID = 'IID' + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } connection = _Connection() CLIENT = _Client(project=self.PROJECT, connection=connection) logger = _Logger() batch = self._makeOne(logger, client=CLIENT) - batch.log_struct(STRUCT, labels=LABELS) + batch.log_struct(STRUCT, labels=LABELS, insert_id=IID, + severity=SEVERITY, http_request=REQUEST) self.assertEqual(len(connection._requested), 0) - self.assertEqual(batch.entries, [('struct', STRUCT, LABELS)]) + self.assertEqual(batch.entries, + [('struct', STRUCT, LABELS, IID, SEVERITY, REQUEST)]) def test_log_proto_defaults(self): from google.protobuf.struct_pb2 import Struct, Value @@ -445,26 +515,39 @@ def test_log_proto_defaults(self): batch = self._makeOne(logger, client=CLIENT) batch.log_proto(message) self.assertEqual(len(connection._requested), 0) - self.assertEqual(batch.entries, [('proto', message, None)]) + self.assertEqual(batch.entries, + [('proto', message, None, None, None, None)]) def test_log_proto_explicit(self): from google.protobuf.struct_pb2 import Struct, Value message = Struct(fields={'foo': Value(bool_value=True)}) LABELS = {'foo': 'bar', 'baz': 'qux'} + IID = 'IID' + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } connection = _Connection() CLIENT = _Client(project=self.PROJECT, connection=connection) logger = _Logger() batch = self._makeOne(logger, client=CLIENT) - batch.log_proto(message, labels=LABELS) + batch.log_proto(message, labels=LABELS, insert_id=IID, + severity=SEVERITY, http_request=REQUEST) self.assertEqual(len(connection._requested), 0) - self.assertEqual(batch.entries, [('proto', message, LABELS)]) + self.assertEqual(batch.entries, + [('proto', message, LABELS, IID, SEVERITY, REQUEST)]) def test_commit_w_invalid_entry_type(self): logger = _Logger() conn = _Connection() CLIENT = _Client(project=self.PROJECT, connection=conn) batch = self._makeOne(logger, CLIENT) - batch.entries.append(('bogus', 'BOGUS', None)) + batch.entries.append(('bogus', 'BOGUS', None, None, None, None)) with self.assertRaises(ValueError): batch.commit() @@ -475,6 +558,9 @@ def test_commit_w_bound_client(self): TEXT = 'This is the entry text' STRUCT = {'message': TEXT, 'weather': 'partly cloudy'} message = Struct(fields={'foo': Value(bool_value=True)}) + IID1 = 'IID1' + IID2 = 'IID2' + IID3 = 'IID3' conn = _Connection({}) CLIENT = _Client(project=self.PROJECT, connection=conn) logger = _Logger() @@ -484,15 +570,16 @@ def test_commit_w_bound_client(self): 'type': 'global', }, 'entries': [ - {'textPayload': TEXT}, - {'jsonPayload': STRUCT}, - {'protoPayload': json.loads(MessageToJson(message))}, + {'textPayload': TEXT, 'insertId': IID1}, + {'jsonPayload': STRUCT, 'insertId': IID2}, + {'protoPayload': json.loads(MessageToJson(message)), + 'insertId': IID3}, ], } batch = self._makeOne(logger, client=CLIENT) - batch.log_text(TEXT) - batch.log_struct(STRUCT) - batch.log_proto(message) + batch.log_text(TEXT, insert_id=IID1) + batch.log_struct(STRUCT, insert_id=IID2) + batch.log_proto(message, insert_id=IID3) batch.commit() self.assertEqual(list(batch.entries), []) self.assertEqual(len(conn._requested), 1) @@ -511,6 +598,15 @@ def test_commit_w_alternate_client(self): message = Struct(fields={'foo': Value(bool_value=True)}) DEFAULT_LABELS = {'foo': 'spam'} LABELS = {'foo': 'bar', 'baz': 'qux'} + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } conn1 = _Connection() conn2 = _Connection({}) CLIENT1 = _Client(project=self.PROJECT, connection=conn1) @@ -522,14 +618,15 @@ def test_commit_w_alternate_client(self): 'labels': DEFAULT_LABELS, 'entries': [ {'textPayload': TEXT, 'labels': LABELS}, - {'jsonPayload': STRUCT}, - {'protoPayload': json.loads(MessageToJson(message))}, + {'jsonPayload': STRUCT, 'severity': SEVERITY}, + {'protoPayload': json.loads(MessageToJson(message)), + 'httpRequest': REQUEST}, ], } batch = self._makeOne(logger, client=CLIENT1) batch.log_text(TEXT, labels=LABELS) - batch.log_struct(STRUCT) - batch.log_proto(message) + batch.log_struct(STRUCT, severity=SEVERITY) + batch.log_proto(message, http_request=REQUEST) batch.commit(client=CLIENT2) self.assertEqual(list(batch.entries), []) self.assertEqual(len(conn1._requested), 0) @@ -549,6 +646,15 @@ def test_context_mgr_success(self): message = Struct(fields={'foo': Value(bool_value=True)}) DEFAULT_LABELS = {'foo': 'spam'} LABELS = {'foo': 'bar', 'baz': 'qux'} + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } conn = _Connection({}) CLIENT = _Client(project=self.PROJECT, connection=conn) logger = Logger('logger_name', CLIENT, labels=DEFAULT_LABELS) @@ -559,17 +665,18 @@ def test_context_mgr_success(self): }, 'labels': DEFAULT_LABELS, 'entries': [ - {'textPayload': TEXT}, + {'textPayload': TEXT, 'httpRequest': REQUEST}, {'jsonPayload': STRUCT, 'labels': LABELS}, - {'protoPayload': json.loads(MessageToJson(message))}, + {'protoPayload': json.loads(MessageToJson(message)), + 'severity': SEVERITY}, ], } batch = self._makeOne(logger, client=CLIENT) with batch as other: - other.log_text(TEXT) + other.log_text(TEXT, http_request=REQUEST) other.log_struct(STRUCT, labels=LABELS) - other.log_proto(message) + other.log_proto(message, severity=SEVERITY) self.assertEqual(list(batch.entries), []) self.assertEqual(len(conn._requested), 1) @@ -583,22 +690,32 @@ def test_context_mgr_failure(self): TEXT = 'This is the entry text' STRUCT = {'message': TEXT, 'weather': 'partly cloudy'} LABELS = {'foo': 'bar', 'baz': 'qux'} + IID = 'IID' + SEVERITY = 'CRITICAL' + METHOD = 'POST' + URI = 'https://api.example.com/endpoint' + STATUS = '500' + REQUEST = { + 'requestMethod': METHOD, + 'requestUrl': URI, + 'status': STATUS, + } message = Struct(fields={'foo': Value(bool_value=True)}) conn = _Connection({}) CLIENT = _Client(project=self.PROJECT, connection=conn) logger = _Logger() UNSENT = [ - ('text', TEXT, None), - ('struct', STRUCT, None), - ('proto', message, LABELS), + ('text', TEXT, None, IID, None, None), + ('struct', STRUCT, None, None, SEVERITY, None), + ('proto', message, LABELS, None, None, REQUEST), ] batch = self._makeOne(logger, client=CLIENT) try: with batch as other: - other.log_text(TEXT) - other.log_struct(STRUCT) - other.log_proto(message, labels=LABELS) + other.log_text(TEXT, insert_id=IID) + other.log_struct(STRUCT, severity=SEVERITY) + other.log_proto(message, labels=LABELS, http_request=REQUEST) raise _Bugout() except _Bugout: pass