Skip to content

Commit 396d079

Browse files
salrashid123tseaver
authored andcommitted
Support 'trace' attribute of log entries (#5878)
See: #5505
1 parent ee19bbd commit 396d079

File tree

4 files changed

+188
-47
lines changed

4 files changed

+188
-47
lines changed

google/cloud/logging/entries.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,13 @@ class _BaseEntry(object):
7676
7777
:type resource: :class:`~google.cloud.logging.resource.Resource`
7878
:param resource: (Optional) Monitored resource of the entry
79+
80+
:type trace: str
81+
:param trace: (optional) traceid to apply to the entry.
7982
"""
8083
def __init__(self, payload, logger, insert_id=None, timestamp=None,
81-
labels=None, severity=None, http_request=None, resource=None):
84+
labels=None, severity=None, http_request=None, resource=None,
85+
trace=None):
8286
self.payload = payload
8387
self.logger = logger
8488
self.insert_id = insert_id
@@ -87,6 +91,7 @@ def __init__(self, payload, logger, insert_id=None, timestamp=None,
8791
self.severity = severity
8892
self.http_request = http_request
8993
self.resource = resource
94+
self.trace = trace
9095

9196
@classmethod
9297
def from_api_repr(cls, resource, client, loggers=None):
@@ -123,6 +128,7 @@ def from_api_repr(cls, resource, client, loggers=None):
123128
labels = resource.get('labels')
124129
severity = resource.get('severity')
125130
http_request = resource.get('httpRequest')
131+
trace = resource.get('trace')
126132

127133
monitored_resource_dict = resource.get('resource')
128134
monitored_resource = None
@@ -131,7 +137,7 @@ def from_api_repr(cls, resource, client, loggers=None):
131137

132138
return cls(payload, logger, insert_id=insert_id, timestamp=timestamp,
133139
labels=labels, severity=severity, http_request=http_request,
134-
resource=monitored_resource)
140+
resource=monitored_resource, trace=trace)
135141

136142

137143
class TextEntry(_BaseEntry):
@@ -185,15 +191,19 @@ class ProtobufEntry(_BaseEntry):
185191
186192
:type resource: :class:`~google.cloud.logging.resource.Resource`
187193
:param resource: (Optional) Monitored resource of the entry
194+
195+
:type trace: str
196+
:param trace: (optional) traceid to apply to the entry.
188197
"""
189198
_PAYLOAD_KEY = 'protoPayload'
190199

191200
def __init__(self, payload, logger, insert_id=None, timestamp=None,
192-
labels=None, severity=None, http_request=None, resource=None):
201+
labels=None, severity=None, http_request=None, resource=None,
202+
trace=None):
193203
super(ProtobufEntry, self).__init__(
194204
payload, logger, insert_id=insert_id, timestamp=timestamp,
195205
labels=labels, severity=severity, http_request=http_request,
196-
resource=resource)
206+
resource=resource, trace=trace)
197207
if isinstance(self.payload, any_pb2.Any):
198208
self.payload_pb = self.payload
199209
self.payload = None

google/cloud/logging/logger.py

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def batch(self, client=None):
9696
def _make_entry_resource(self, text=None, info=None, message=None,
9797
labels=None, insert_id=None, severity=None,
9898
http_request=None, timestamp=None,
99-
resource=_GLOBAL_RESOURCE):
99+
resource=_GLOBAL_RESOURCE, trace=None):
100100
"""Return a log entry resource of the appropriate type.
101101
102102
Helper for :meth:`log_text`, :meth:`log_struct`, and :meth:`log_proto`.
@@ -131,6 +131,9 @@ def _make_entry_resource(self, text=None, info=None, message=None,
131131
:type resource: :class:`~google.cloud.logging.resource.Resource`
132132
:param resource: (Optional) Monitored resource of the entry
133133
134+
:type trace: str
135+
:param trace: (optional) traceid to apply to the entry.
136+
134137
:rtype: dict
135138
:returns: The JSON resource created.
136139
"""
@@ -172,11 +175,14 @@ def _make_entry_resource(self, text=None, info=None, message=None,
172175
if timestamp is not None:
173176
entry['timestamp'] = _datetime_to_rfc3339(timestamp)
174177

178+
if trace is not None:
179+
entry['trace'] = trace
180+
175181
return entry
176182

177183
def log_text(self, text, client=None, labels=None, insert_id=None,
178184
severity=None, http_request=None, timestamp=None,
179-
resource=_GLOBAL_RESOURCE):
185+
resource=_GLOBAL_RESOURCE, trace=None):
180186
"""API call: log a text message via a POST request
181187
182188
See
@@ -203,22 +209,26 @@ def log_text(self, text, client=None, labels=None, insert_id=None,
203209
:param http_request: (optional) info about HTTP request associated with
204210
the entry
205211
212+
:type timestamp: :class:`datetime.datetime`
213+
:param timestamp: (optional) timestamp of event being logged.
214+
206215
:type resource: :class:`~google.cloud.logging.resource.Resource`
207216
:param resource: Monitored resource of the entry, defaults
208217
to the global resource type.
209218
210-
:type timestamp: :class:`datetime.datetime`
211-
:param timestamp: (optional) timestamp of event being logged.
219+
:type trace: str
220+
:param trace: (optional) traceid to apply to the entry.
212221
"""
213222
client = self._require_client(client)
214223
entry_resource = self._make_entry_resource(
215224
text=text, labels=labels, insert_id=insert_id, severity=severity,
216-
http_request=http_request, timestamp=timestamp, resource=resource)
225+
http_request=http_request, timestamp=timestamp, resource=resource,
226+
trace=trace)
217227
client.logging_api.write_entries([entry_resource])
218228

219229
def log_struct(self, info, client=None, labels=None, insert_id=None,
220230
severity=None, http_request=None, timestamp=None,
221-
resource=_GLOBAL_RESOURCE):
231+
resource=_GLOBAL_RESOURCE, trace=None):
222232
"""API call: log a structured message via a POST request
223233
224234
See
@@ -245,22 +255,26 @@ def log_struct(self, info, client=None, labels=None, insert_id=None,
245255
:param http_request: (optional) info about HTTP request associated with
246256
the entry.
247257
258+
:type timestamp: :class:`datetime.datetime`
259+
:param timestamp: (optional) timestamp of event being logged.
260+
248261
:type resource: :class:`~google.cloud.logging.resource.Resource`
249262
:param resource: Monitored resource of the entry, defaults
250263
to the global resource type.
251264
252-
:type timestamp: :class:`datetime.datetime`
253-
:param timestamp: (optional) timestamp of event being logged.
265+
:type trace: str
266+
:param trace: (optional) traceid to apply to the entry.
254267
"""
255268
client = self._require_client(client)
256269
entry_resource = self._make_entry_resource(
257270
info=info, labels=labels, insert_id=insert_id, severity=severity,
258-
http_request=http_request, timestamp=timestamp, resource=resource)
271+
http_request=http_request, timestamp=timestamp, resource=resource,
272+
trace=trace)
259273
client.logging_api.write_entries([entry_resource])
260274

261275
def log_proto(self, message, client=None, labels=None, insert_id=None,
262276
severity=None, http_request=None, timestamp=None,
263-
resource=_GLOBAL_RESOURCE):
277+
resource=_GLOBAL_RESOURCE, trace=None):
264278
"""API call: log a protobuf message via a POST request
265279
266280
See
@@ -287,18 +301,21 @@ def log_proto(self, message, client=None, labels=None, insert_id=None,
287301
:param http_request: (optional) info about HTTP request associated with
288302
the entry.
289303
304+
:type timestamp: :class:`datetime.datetime`
305+
:param timestamp: (optional) timestamp of event being logged.
306+
290307
:type resource: :class:`~google.cloud.logging.resource.Resource`
291308
:param resource: Monitored resource of the entry, defaults
292309
to the global resource type.
293310
294-
:type timestamp: :class:`datetime.datetime`
295-
:param timestamp: (optional) timestamp of event being logged.
311+
:type trace: str
312+
:param trace: (optional) traceid to apply to the entry.
296313
"""
297314
client = self._require_client(client)
298315
entry_resource = self._make_entry_resource(
299316
message=message, labels=labels, insert_id=insert_id,
300317
severity=severity, http_request=http_request, timestamp=timestamp,
301-
resource=resource)
318+
resource=resource, trace=trace)
302319
client.logging_api.write_entries([entry_resource])
303320

304321
def delete(self, client=None):
@@ -392,7 +409,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
392409
self.commit()
393410

394411
def log_text(self, text, labels=None, insert_id=None, severity=None,
395-
http_request=None, timestamp=None, resource=_GLOBAL_RESOURCE):
412+
http_request=None, timestamp=None, resource=_GLOBAL_RESOURCE,
413+
trace=None):
396414
"""Add a text entry to be logged during :meth:`commit`.
397415
398416
:type text: str
@@ -420,14 +438,17 @@ def log_text(self, text, labels=None, insert_id=None, severity=None,
420438
resource of the batch is used for this entry. If
421439
both this resource and the Batch resource are None,
422440
the API will return an error.
441+
442+
:type trace: str
443+
:param trace: (optional) traceid to apply to the entry.
423444
"""
424445
self.entries.append(
425446
('text', text, labels, insert_id, severity, http_request,
426-
timestamp, resource))
447+
timestamp, resource, trace))
427448

428449
def log_struct(self, info, labels=None, insert_id=None, severity=None,
429450
http_request=None, timestamp=None,
430-
resource=_GLOBAL_RESOURCE):
451+
resource=_GLOBAL_RESOURCE, trace=None):
431452
"""Add a struct entry to be logged during :meth:`commit`.
432453
433454
:type info: dict
@@ -455,14 +476,17 @@ def log_struct(self, info, labels=None, insert_id=None, severity=None,
455476
resource of the batch is used for this entry. If
456477
both this resource and the Batch resource are None,
457478
the API will return an error.
479+
480+
:type trace: str
481+
:param trace: (optional) traceid to apply to the entry.
458482
"""
459483
self.entries.append(
460484
('struct', info, labels, insert_id, severity, http_request,
461-
timestamp, resource))
485+
timestamp, resource, trace))
462486

463487
def log_proto(self, message, labels=None, insert_id=None, severity=None,
464488
http_request=None, timestamp=None,
465-
resource=_GLOBAL_RESOURCE):
489+
resource=_GLOBAL_RESOURCE, trace=None):
466490
"""Add a protobuf entry to be logged during :meth:`commit`.
467491
468492
:type message: protobuf message
@@ -490,10 +514,13 @@ def log_proto(self, message, labels=None, insert_id=None, severity=None,
490514
resource of the batch is used for this entry. If
491515
both this resource and the Batch resource are None,
492516
the API will return an error.
517+
518+
:type trace: str
519+
:param trace: (optional) traceid to apply to the entry.
493520
"""
494521
self.entries.append(
495522
('proto', message, labels, insert_id, severity, http_request,
496-
timestamp, resource))
523+
timestamp, resource, trace))
497524

498525
def commit(self, client=None):
499526
"""Send saved log entries as a single API call.
@@ -517,7 +544,7 @@ def commit(self, client=None):
517544

518545
entries = []
519546
for (entry_type, entry, labels, iid, severity, http_req,
520-
timestamp, resource) in self.entries:
547+
timestamp, resource, trace) in self.entries:
521548
if entry_type == 'text':
522549
info = {'textPayload': entry}
523550
elif entry_type == 'struct':
@@ -544,6 +571,8 @@ def commit(self, client=None):
544571
info['httpRequest'] = http_req
545572
if timestamp is not None:
546573
info['timestamp'] = _datetime_to_rfc3339(timestamp)
574+
if trace is not None:
575+
info['trace'] = trace
547576
entries.append(info)
548577

549578
client.logging_api.write_entries(entries, **kwargs)

tests/unit/test_entries.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def test_ctor_defaults(self):
6868
self.assertIsNone(entry.severity)
6969
self.assertIsNone(entry.http_request)
7070
self.assertIsNone(entry.resource)
71+
self.assertIsNone(entry.trace)
7172

7273
def test_ctor_explicit(self):
7374
import datetime
@@ -87,6 +88,7 @@ def test_ctor_explicit(self):
8788
'status': STATUS,
8889
}
8990
resource = Resource(type='global', labels={})
91+
TRACE = '12345678-1234-5678-1234-567812345678'
9092

9193
logger = _Logger(self.LOGGER_NAME, self.PROJECT)
9294
entry = self._make_one(PAYLOAD, logger,
@@ -95,7 +97,8 @@ def test_ctor_explicit(self):
9597
labels=LABELS,
9698
severity=SEVERITY,
9799
http_request=REQUEST,
98-
resource=resource)
100+
resource=resource,
101+
trace=TRACE)
99102
self.assertEqual(entry.payload, PAYLOAD)
100103
self.assertIs(entry.logger, logger)
101104
self.assertEqual(entry.insert_id, IID)
@@ -106,6 +109,7 @@ def test_ctor_explicit(self):
106109
self.assertEqual(entry.http_request['requestUrl'], URI)
107110
self.assertEqual(entry.http_request['status'], STATUS)
108111
self.assertEqual(entry.resource, resource)
112+
self.assertEqual(entry.trace, TRACE)
109113

110114
def test_from_api_repr_missing_data_no_loggers(self):
111115
client = _Client(self.PROJECT)
@@ -122,6 +126,7 @@ def test_from_api_repr_missing_data_no_loggers(self):
122126
self.assertIsNone(entry.timestamp)
123127
self.assertIsNone(entry.severity)
124128
self.assertIsNone(entry.http_request)
129+
self.assertIsNone(entry.trace)
125130
logger = entry.logger
126131
self.assertIsInstance(logger, _Logger)
127132
self.assertIs(logger.client, client)
@@ -154,6 +159,7 @@ def test_from_api_repr_w_loggers_no_logger_match(self):
154159
}
155160
)
156161
STATUS = '500'
162+
TRACE = '12345678-1234-5678-1234-567812345678'
157163
API_REPR = {
158164
'dummyPayload': PAYLOAD,
159165
'logName': LOG_NAME,
@@ -167,6 +173,7 @@ def test_from_api_repr_w_loggers_no_logger_match(self):
167173
'status': STATUS,
168174
},
169175
'resource': RESOURCE._to_dict(),
176+
'trace': TRACE
170177
}
171178
loggers = {}
172179
entry = klass.from_api_repr(API_REPR, client, loggers=loggers)
@@ -184,6 +191,7 @@ def test_from_api_repr_w_loggers_no_logger_match(self):
184191
self.assertEqual(logger.name, self.LOGGER_NAME)
185192
self.assertEqual(loggers, {LOG_NAME: logger})
186193
self.assertEqual(entry.resource, RESOURCE)
194+
self.assertEqual(entry.trace, TRACE)
187195

188196
def test_from_api_repr_w_loggers_w_logger_match(self):
189197
from datetime import datetime
@@ -196,12 +204,14 @@ def test_from_api_repr_w_loggers_w_logger_match(self):
196204
TIMESTAMP = _datetime_to_rfc3339_w_nanos(NOW)
197205
LOG_NAME = 'projects/%s/logs/%s' % (self.PROJECT, self.LOGGER_NAME)
198206
LABELS = {'foo': 'bar', 'baz': 'qux'}
207+
TRACE = '12345678-1234-5678-1234-567812345678'
199208
API_REPR = {
200209
'dummyPayload': PAYLOAD,
201210
'logName': LOG_NAME,
202211
'insertId': IID,
203212
'timestamp': TIMESTAMP,
204213
'labels': LABELS,
214+
'trace': TRACE
205215
}
206216
LOGGER = object()
207217
loggers = {LOG_NAME: LOGGER}
@@ -211,6 +221,7 @@ def test_from_api_repr_w_loggers_w_logger_match(self):
211221
self.assertEqual(entry.insert_id, IID)
212222
self.assertEqual(entry.timestamp, NOW)
213223
self.assertEqual(entry.labels, LABELS)
224+
self.assertEqual(entry.trace, TRACE)
214225
self.assertIs(entry.logger, LOGGER)
215226

216227

@@ -239,6 +250,7 @@ def test_constructor_basic(self):
239250
self.assertIsNone(pb_entry.labels)
240251
self.assertIsNone(pb_entry.severity)
241252
self.assertIsNone(pb_entry.http_request)
253+
self.assertIsNone(pb_entry.trace)
242254

243255
def test_constructor_with_any(self):
244256
from google.protobuf.any_pb2 import Any
@@ -253,6 +265,7 @@ def test_constructor_with_any(self):
253265
self.assertIsNone(pb_entry.labels)
254266
self.assertIsNone(pb_entry.severity)
255267
self.assertIsNone(pb_entry.http_request)
268+
self.assertIsNone(pb_entry.trace)
256269

257270
def test_parse_message(self):
258271
import json

0 commit comments

Comments
 (0)