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

feat: allow modifying LogEntry data using extra argument #129

Merged
merged 37 commits into from Jan 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
55383da
added http request to transports
daniel-sanche Dec 9, 2020
3c67803
got it working on gae flex
daniel-sanche Dec 9, 2020
4be2e19
refactored _helpers to support http_requests
daniel-sanche Dec 9, 2020
61115d1
added comments
daniel-sanche Dec 9, 2020
f7aa0e0
fixed helper tests
daniel-sanche Dec 9, 2020
1459f7e
changed order of outputs
daniel-sanche Dec 9, 2020
96cf896
improved test_django
daniel-sanche Dec 9, 2020
a8d54c8
added django http tests
daniel-sanche Dec 9, 2020
841e68a
added tests to flask
daniel-sanche Dec 9, 2020
a3bd27c
fixed appengine tests
daniel-sanche Dec 9, 2020
e8733f4
fixed transport tests
daniel-sanche Dec 10, 2020
2f73049
ran blacken
daniel-sanche Dec 10, 2020
c28d3fd
allow user overrides
daniel-sanche Dec 10, 2020
e6ccd30
fixed lint issue
daniel-sanche Dec 10, 2020
b653b22
fixed trace path
daniel-sanche Dec 10, 2020
889af77
implemented update to base handler
daniel-sanche Dec 10, 2020
a1a4a25
added unit test for base handler
daniel-sanche Dec 10, 2020
745a2c4
fixed how traces are handled
daniel-sanche Dec 10, 2020
2d5ad97
added system test
daniel-sanche Dec 11, 2020
b5ad409
loop through both handler classes
daniel-sanche Dec 11, 2020
a298856
renamed test function
daniel-sanche Dec 11, 2020
6ca954e
added protocol to http request
daniel-sanche Dec 11, 2020
16e7888
added supported frameworks
daniel-sanche Dec 11, 2020
36a71ab
added tests for protocol
daniel-sanche Dec 11, 2020
6b549bd
removed unneded assertions
daniel-sanche Dec 11, 2020
e91548c
renamed test function
daniel-sanche Dec 11, 2020
5f9d932
added tests for sparse http requests
daniel-sanche Dec 11, 2020
69c0d39
added comment
daniel-sanche Dec 11, 2020
5bb9e51
blackened
daniel-sanche Dec 11, 2020
6d1974d
use proto instead of dict for http_request
daniel-sanche Dec 11, 2020
b2ad3eb
Merge branch 'support_http_requests' into manual_data
daniel-sanche Dec 11, 2020
d22ed8e
fixed tests after merge
daniel-sanche Dec 11, 2020
d97f2d1
blacken
daniel-sanche Dec 11, 2020
d67213d
fixed tests
daniel-sanche Dec 12, 2020
f995671
fixed null check
daniel-sanche Dec 12, 2020
f186b8a
Merge branch 'master' into manual_data
daniel-sanche Dec 17, 2020
2d4aff6
fixed merge issues
daniel-sanche Dec 17, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 15 additions & 5 deletions google/cloud/logging_v2/handlers/app_engine.py
Expand Up @@ -113,15 +113,25 @@ def emit(self, record):
record (logging.LogRecord): The record to be logged.
"""
message = super(AppEngineHandler, self).format(record)
inferred_http, inferred_trace = get_request_data()
if inferred_trace is not None:
inferred_trace = f"projects/{self.project_id}/traces/{inferred_trace}"
# allow user overrides
trace = getattr(record, "trace", inferred_trace)
span_id = getattr(record, "span_id", None)
http_request = getattr(record, "http_request", inferred_http)
resource = getattr(record, "resource", self.resource)
user_labels = getattr(record, "labels", {})
# merge labels
gae_labels = self.get_gae_labels()
http_request, trace_id = get_request_data()
if trace_id is not None:
trace_id = f"projects/{self.project_id}/traces/{trace_id}"
gae_labels.update(user_labels)
# send off request
self.transport.send(
record,
message,
resource=self.resource,
resource=resource,
labels=gae_labels,
trace=trace_id,
trace=trace,
span_id=span_id,
http_request=http_request,
)
22 changes: 21 additions & 1 deletion google/cloud/logging_v2/handlers/handlers.py
Expand Up @@ -87,6 +87,7 @@ def __init__(
self.name = name
self.client = client
self.transport = transport(client, name)
self.project_id = client.project
self.resource = resource
self.labels = labels

Expand All @@ -101,7 +102,26 @@ def emit(self, record):
record (logging.LogRecord): The record to be logged.
"""
message = super(CloudLoggingHandler, self).format(record)
self.transport.send(record, message, resource=self.resource, labels=self.labels)
trace_id = getattr(record, "trace", None)
span_id = getattr(record, "span_id", None)
http_request = getattr(record, "http_request", None)
resource = getattr(record, "resource", self.resource)
user_labels = getattr(record, "labels", {})
# merge labels
total_labels = self.labels if self.labels is not None else {}
total_labels.update(user_labels)
if len(total_labels) == 0:
total_labels = None
# send off request
self.transport.send(
record,
message,
resource=resource,
labels=(total_labels if total_labels else None),
trace=trace_id,
span_id=span_id,
http_request=http_request,
)


def setup_logging(
Expand Down
36 changes: 35 additions & 1 deletion tests/system/test_system.py
Expand Up @@ -27,7 +27,8 @@
from google.api_core.exceptions import ServiceUnavailable
import google.cloud.logging
from google.cloud._helpers import UTC
from google.cloud.logging_v2.handlers.handlers import CloudLoggingHandler
from google.cloud.logging_v2.handlers import AppEngineHandler
from google.cloud.logging_v2.handlers import CloudLoggingHandler
from google.cloud.logging_v2.handlers.transports import SyncTransport
from google.cloud.logging_v2 import client
from google.cloud.logging_v2.resource import Resource
Expand Down Expand Up @@ -308,6 +309,39 @@ def test_log_handler_sync(self):
self.assertEqual(len(entries), 1)
self.assertEqual(entries[0].payload, expected_payload)

def test_handlers_w_extras(self):
LOG_MESSAGE = "Testing with injected extras."

for cls in [CloudLoggingHandler, AppEngineHandler]:
LOGGER_NAME = f"{cls.__name__}-handler_extras"
handler_name = self._logger_name(LOGGER_NAME)

handler = cls(Config.CLIENT, name=handler_name, transport=SyncTransport)

# only create the logger to delete, hidden otherwise
logger = Config.CLIENT.logger(handler.name)
self.to_delete.append(logger)

cloud_logger = logging.getLogger(LOGGER_NAME)
cloud_logger.addHandler(handler)
expected_request = {"requestUrl": "localhost"}
extra = {
"trace": "123",
"span_id": "456",
"http_request": expected_request,
"resource": Resource(type="cloudiot_device", labels={}),
"labels": {"test-label": "manual"},
}
cloud_logger.warn(LOG_MESSAGE, extra=extra)

entries = _list_entries(logger)
self.assertEqual(len(entries), 1)
self.assertEqual(entries[0].trace, extra["trace"])
self.assertEqual(entries[0].span_id, extra["span_id"])
self.assertEqual(entries[0].http_request, expected_request)
self.assertEqual(entries[0].labels, extra["labels"])
self.assertEqual(entries[0].resource.type, extra["resource"].type)

def test_log_root_handler(self):
LOG_MESSAGE = "It was the best of times."

Expand Down
62 changes: 60 additions & 2 deletions tests/unit/handlers/test_app_engine.py
Expand Up @@ -118,10 +118,60 @@ def test_emit(self):
gae_resource,
gae_labels,
expected_trace_id,
None,
expected_http_request,
),
)

def test_emit_manual_field_override(self):
from google.cloud.logging_v2.resource import Resource

inferred_http_request = {"request_url": "test"}
inferred_trace_id = "trace-test"
get_request_patch = mock.patch(
"google.cloud.logging_v2.handlers.app_engine.get_request_data",
return_value=(inferred_http_request, inferred_trace_id),
)
with get_request_patch:
# library integrations mocked to return test data
client = mock.Mock(project=self.PROJECT, spec=["project"])
handler = self._make_one(client, transport=_Transport)
gae_labels = handler.get_gae_labels()
logname = "app"
message = "hello world"
record = logging.LogRecord(
logname, logging, None, None, message, None, None
)
handler.project_id = self.PROJECT
# set attributes manually
expected_trace = "123"
setattr(record, "trace", expected_trace)
expected_span = "456"
setattr(record, "span_id", expected_span)
expected_http = {"reuqest_url": "manual"}
setattr(record, "http_request", expected_http)
expected_resource = Resource(type="test", labels={})
setattr(record, "resource", expected_resource)
additional_labels = {"test-label": "manual"}
expected_labels = dict(gae_labels)
expected_labels.update(additional_labels)
setattr(record, "labels", additional_labels)
handler.emit(record)
self.assertIs(handler.transport.client, client)
self.assertEqual(handler.transport.name, logname)
self.assertEqual(
handler.transport.send_called_with,
(
record,
message,
expected_resource,
expected_labels,
expected_trace,
expected_span,
expected_http,
),
)

def _get_gae_labels_helper(self, trace_id):
get_request_patch = mock.patch(
"google.cloud.logging_v2.handlers.app_engine.get_request_data",
Expand Down Expand Up @@ -156,5 +206,13 @@ def __init__(self, client, name):
self.client = client
self.name = name

def send(self, record, message, resource, labels, trace, http_request):
self.send_called_with = (record, message, resource, labels, trace, http_request)
def send(self, record, message, resource, labels, trace, span_id, http_request):
self.send_called_with = (
record,
message,
resource,
labels,
trace,
span_id,
http_request,
)
60 changes: 57 additions & 3 deletions tests/unit/handlers/test_handlers.py
Expand Up @@ -85,7 +85,44 @@ def test_emit(self):

self.assertEqual(
handler.transport.send_called_with,
(record, message, _GLOBAL_RESOURCE, None),
(record, message, _GLOBAL_RESOURCE, None, None, None, None),
)

def test_emit_manual_field_override(self):
from google.cloud.logging_v2.logger import _GLOBAL_RESOURCE
from google.cloud.logging_v2.resource import Resource

client = _Client(self.PROJECT)
handler = self._make_one(
client, transport=_Transport, resource=_GLOBAL_RESOURCE
)
logname = "loggername"
message = "hello world"
record = logging.LogRecord(logname, logging, None, None, message, None, None)
# set attributes manually
expected_trace = "123"
setattr(record, "trace", expected_trace)
expected_span = "456"
setattr(record, "span_id", expected_span)
expected_http = {"reuqest_url": "manual"}
setattr(record, "http_request", expected_http)
expected_resource = Resource(type="test", labels={})
setattr(record, "resource", expected_resource)
expected_labels = {"test-label": "manual"}
setattr(record, "labels", expected_labels)
handler.emit(record)

self.assertEqual(
handler.transport.send_called_with,
(
record,
message,
expected_resource,
expected_labels,
expected_trace,
expected_span,
expected_http,
),
)


Expand Down Expand Up @@ -148,5 +185,22 @@ def __init__(self, client, name):
self.client = client
self.name = name

def send(self, record, message, resource, labels=None):
self.send_called_with = (record, message, resource, labels)
def send(
self,
record,
message,
resource,
labels=None,
trace=None,
span_id=None,
http_request=None,
):
self.send_called_with = (
record,
message,
resource,
labels,
trace,
span_id,
http_request,
)