From 50bf43476752c01fd0da4dd5fa079cf8637da451 Mon Sep 17 00:00:00 2001 From: Angela Li Date: Fri, 12 May 2017 11:41:00 -0700 Subject: [PATCH 1/6] Stop writing to '/var/log/app_engine/' and write logs to Stackdriver logging API --- logging/google/cloud/logging/client.py | 2 +- .../cloud/logging/handlers/app_engine.py | 80 +++++++++++-------- .../handlers/transports/background_thread.py | 17 +++- .../cloud/logging/handlers/transports/base.py | 6 +- .../cloud/logging/handlers/transports/sync.py | 8 +- .../tests/unit/handlers/test_app_engine.py | 62 ++++++++------ .../transports/test_background_thread.py | 20 +++-- .../unit/handlers/transports/test_base.py | 2 +- .../unit/handlers/transports/test_sync.py | 17 +++- logging/tests/unit/test_client.py | 22 ++--- 10 files changed, 150 insertions(+), 86 deletions(-) diff --git a/logging/google/cloud/logging/client.py b/logging/google/cloud/logging/client.py index 34bf8a3074e9..cb6d9d70fb4f 100644 --- a/logging/google/cloud/logging/client.py +++ b/logging/google/cloud/logging/client.py @@ -303,7 +303,7 @@ def get_default_handler(self): """ if (_APPENGINE_FLEXIBLE_ENV_VM in os.environ or _APPENGINE_FLEXIBLE_ENV_FLEX in os.environ): - return AppEngineHandler() + return AppEngineHandler(self) elif _CONTAINER_ENGINE_ENV in os.environ: return ContainerEngineHandler() else: diff --git a/logging/google/cloud/logging/handlers/app_engine.py b/logging/google/cloud/logging/handlers/app_engine.py index 4184c2054b1a..a0a25d24a8ec 100644 --- a/logging/google/cloud/logging/handlers/app_engine.py +++ b/logging/google/cloud/logging/handlers/app_engine.py @@ -27,47 +27,63 @@ # /appengine-vmruntime/vmruntime/cloud_logging.py import logging.handlers -import os -from google.cloud.logging.handlers._helpers import format_stackdriver_json +from google.cloud.logging.handlers.handlers import CloudLoggingHandler +from google.cloud.logging.handlers.transports import BackgroundThreadTransport +from google.cloud.logging.resource import Resource -_LOG_PATH_TEMPLATE = '/var/log/app_engine/app.{pid}.json' -_MAX_LOG_BYTES = 128 * 1024 * 1024 -_LOG_FILE_COUNT = 3 +DEFAULT_LOGGER_NAME = 'python' +EXCLUDED_LOGGER_DEFAULTS = ('google.cloud', 'oauth2client') -class AppEngineHandler(logging.handlers.RotatingFileHandler): - """A handler that writes to the App Engine fluentd Stackdriver log file. +_GLOBAL_RESOURCE = Resource(type='global', labels={}) - Writes to the file that the fluentd agent on App Engine Flexible is - configured to discover logs and send them to Stackdriver Logging. - Log entries are wrapped in JSON and with appropriate metadata. The - process of converting the user's formatted logs into a JSON payload for - Stackdriver Logging consumption is implemented as part of the handler - itself, and not as a formatting step, so as not to interfere with - user-defined logging formats. + +class AppEngineHandler(CloudLoggingHandler): + """A handler that directly makes Stackdriver logging API calls. + + This handler can be used to route Python standard logging messages directly + to the Stackdriver Logging API. + + This handler supports both an asynchronous and synchronous transport. + + :type client: :class:`google.cloud.logging.client` + :param client: the authenticated Google Cloud Logging client for this + handler to use + + :type name: str + :param name: the name of the custom log in Stackdriver Logging. Defaults + to 'python'. The name of the Python logger will be represented + in the ``python_logger`` field. + + :type transport: type + :param transport: Class for creating new transport objects. It should + extend from the base :class:`.Transport` type and + implement :meth`.Transport.send`. Defaults to + :class:`.BackgroundThreadTransport`. The other + option is :class:`.SyncTransport`. + + :type resource: :class:`~google.cloud.logging.resource.Resource` + :param resource: Monitored resource of the entry, defaults + to the global resource type. """ - def __init__(self): - """Construct the handler + def __init__(self, client, + name=DEFAULT_LOGGER_NAME, + transport=BackgroundThreadTransport, + resource=_GLOBAL_RESOURCE): + super(AppEngineHandler, self).__init__(client, name, transport) + self.resource=resource - Large log entries will get mangled if multiple workers write to the - same file simultaneously, so we'll use the worker's PID to pick a log - filename. - """ - self.filename = _LOG_PATH_TEMPLATE.format(pid=os.getpid()) - super(AppEngineHandler, self).__init__(self.filename, - maxBytes=_MAX_LOG_BYTES, - backupCount=_LOG_FILE_COUNT) + def emit(self, record): + """Actually log the specified logging record. - def format(self, record): - """Format the specified record into the expected JSON structure. + Overrides the default emit behavior of ``StreamHandler``. - :type record: :class:`~logging.LogRecord` - :param record: the log record + See: https://docs.python.org/2/library/logging.html#handler-objects - :rtype: str - :returns: JSON str to be written to the log file + :type record: :class:`logging.LogRecord` + :param record: The record to be logged. """ - message = super(AppEngineHandler, self).format(record) - return format_stackdriver_json(record, message) + message = super(CloudLoggingHandler, self).format(record) + self.transport.send(record, message, self.resource) diff --git a/logging/google/cloud/logging/handlers/transports/background_thread.py b/logging/google/cloud/logging/handlers/transports/background_thread.py index b179ec2ab876..417e639f8753 100644 --- a/logging/google/cloud/logging/handlers/transports/background_thread.py +++ b/logging/google/cloud/logging/handlers/transports/background_thread.py @@ -28,12 +28,15 @@ from six.moves import queue from google.cloud.logging.handlers.transports.base import Transport +from google.cloud.logging.resource import Resource + _DEFAULT_GRACE_PERIOD = 5.0 # Seconds _DEFAULT_MAX_BATCH_SIZE = 10 _WORKER_THREAD_NAME = 'google.cloud.logging.Worker' _WORKER_TERMINATOR = object() _LOGGER = logging.getLogger(__name__) +_GLOBAL_RESOURCE = Resource(type='global', labels={}) def _get_many(queue_, max_items=None): @@ -203,7 +206,7 @@ def _main_thread_terminated(self): else: print('Failed to send %d pending logs.' % (self._queue.qsize(),)) - def enqueue(self, record, message): + def enqueue(self, record, message, resource=None): """Queues a log entry to be written by the background thread. :type record: :class:`logging.LogRecord` @@ -212,6 +215,9 @@ def enqueue(self, record, message): :type message: str :param message: The message from the ``LogRecord`` after being formatted by the associated log formatters. + + :type resource: :class:`~google.cloud.logging.resource.Resource` + :param resource: (Optional) Monitored resource of the entry """ self._queue.put_nowait({ 'info': { @@ -219,6 +225,7 @@ def enqueue(self, record, message): 'python_logger': record.name, }, 'severity': record.levelname, + 'resource': resource, }) def flush(self): @@ -253,7 +260,7 @@ def __init__(self, client, name, grace_period=_DEFAULT_GRACE_PERIOD, self.worker = _Worker(logger) self.worker.start() - def send(self, record, message): + def send(self, record, message, resource=_GLOBAL_RESOURCE): """Overrides Transport.send(). :type record: :class:`logging.LogRecord` @@ -262,8 +269,12 @@ def send(self, record, message): :type message: str :param message: The message from the ``LogRecord`` after being formatted by the associated log formatters. + + :type resource: :class:`~google.cloud.logging.resource.Resource` + :param resource: Monitored resource of the entry, defaults + to the global resource type. """ - self.worker.enqueue(record, message) + self.worker.enqueue(record, message, resource) def flush(self): """Submit any pending log records.""" diff --git a/logging/google/cloud/logging/handlers/transports/base.py b/logging/google/cloud/logging/handlers/transports/base.py index 4fbb7964146c..eef1afdad18e 100644 --- a/logging/google/cloud/logging/handlers/transports/base.py +++ b/logging/google/cloud/logging/handlers/transports/base.py @@ -22,7 +22,7 @@ class Transport(object): client and name object, and must override :meth:`send`. """ - def send(self, record, message): + def send(self, record, message, resource): """Transport send to be implemented by subclasses. :type record: :class:`logging.LogRecord` @@ -31,6 +31,10 @@ def send(self, record, message): :type message: str :param message: The message from the ``LogRecord`` after being formatted by the associated log formatters. + + :type resource: :class:`~google.cloud.logging.resource.Resource` + :param resource: Monitored resource of the entry, defaults + to the global resource type. """ raise NotImplementedError diff --git a/logging/google/cloud/logging/handlers/transports/sync.py b/logging/google/cloud/logging/handlers/transports/sync.py index eec5ffecf6ee..d1aa2e69dca4 100644 --- a/logging/google/cloud/logging/handlers/transports/sync.py +++ b/logging/google/cloud/logging/handlers/transports/sync.py @@ -18,6 +18,10 @@ """ from google.cloud.logging.handlers.transports.base import Transport +from google.cloud.logging.resource import Resource + + +_GLOBAL_RESOURCE = Resource(type='global', labels={}) class SyncTransport(Transport): @@ -29,7 +33,7 @@ class SyncTransport(Transport): def __init__(self, client, name): self.logger = client.logger(name) - def send(self, record, message): + def send(self, record, message, resource=_GLOBAL_RESOURCE): """Overrides transport.send(). :type record: :class:`logging.LogRecord` @@ -40,4 +44,4 @@ def send(self, record, message): formatted by the associated log formatters. """ info = {'message': message, 'python_logger': record.name} - self.logger.log_struct(info, severity=record.levelname) + self.logger.log_struct(info, severity=record.levelname, resource=resource) diff --git a/logging/tests/unit/handlers/test_app_engine.py b/logging/tests/unit/handlers/test_app_engine.py index 9be8a2bec9b3..d0749f9d9550 100644 --- a/logging/tests/unit/handlers/test_app_engine.py +++ b/logging/tests/unit/handlers/test_app_engine.py @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import logging import unittest +from google.cloud.logging.resource import Resource class TestAppEngineHandlerHandler(unittest.TestCase): @@ -24,34 +26,42 @@ def _get_target_class(self): return AppEngineHandler def _make_one(self, *args, **kw): - import tempfile + return self._get_target_class()(*args, **kw) - from google.cloud._testing import _Monkey - from google.cloud.logging.handlers import app_engine as _MUT + def test_ctor(self): + client = _Client(self.PROJECT) + handler = self._make_one(client, transport=_Transport) + self.assertEqual(handler.client, client) - tmpdir = tempfile.mktemp() - with _Monkey(_MUT, _LOG_PATH_TEMPLATE=tmpdir): - return self._get_target_class()(*args, **kw) + def test_emit(self): + RESOURCE = Resource( + type='gae_app', + labels={ + 'module_id': 'default', + 'version_id': 'test', + }) - def test_format(self): - import json - import logging - - handler = self._make_one() + client = _Client(self.PROJECT) + handler = self._make_one(client, transport=_Transport, resource=RESOURCE) logname = 'loggername' message = 'hello world' - record = logging.LogRecord(logname, logging.INFO, None, - None, message, None, None) - record.created = 5.03 - expected_payload = { - 'message': message, - 'timestamp': { - 'seconds': 5, - 'nanos': int(.03 * 1e9), - }, - 'thread': record.thread, - 'severity': record.levelname, - } - payload = handler.format(record) - - self.assertEqual(payload, json.dumps(expected_payload)) + record = logging.LogRecord(logname, logging, None, None, message, + None, None) + handler.emit(record) + + self.assertEqual(handler.transport.send_called_with, (record, message, RESOURCE)) + + +class _Client(object): + + def __init__(self, project): + self.project = project + + +class _Transport(object): + + def __init__(self, client, name): + pass + + def send(self, record, message, resource): + self.send_called_with = (record, message, resource) \ No newline at end of file diff --git a/logging/tests/unit/handlers/transports/test_background_thread.py b/logging/tests/unit/handlers/transports/test_background_thread.py index f8770cc5d127..8d62f66b8a96 100644 --- a/logging/tests/unit/handlers/transports/test_background_thread.py +++ b/logging/tests/unit/handlers/transports/test_background_thread.py @@ -14,6 +14,7 @@ import logging import unittest +from google.cloud.logging.resource import Resource import mock from six.moves import queue @@ -47,6 +48,13 @@ def test_constructor(self): self.assertEqual(logger.name, name) def test_send(self): + RESOURCE = Resource( + type='gae_app', + labels={ + 'module_id': 'default', + 'version_id': 'test', + }) + client = _Client(self.PROJECT) name = 'python_logger' @@ -54,13 +62,14 @@ def test_send(self): python_logger_name = 'mylogger' message = 'hello world' + record = logging.LogRecord( python_logger_name, logging.INFO, None, None, message, None, None) - transport.send(record, message) + transport.send(record, message, RESOURCE) - transport.worker.enqueue.assert_called_once_with(record, message) + transport.worker.enqueue.assert_called_once_with(record, message, RESOURCE) def test_flush(self): client = _Client(self.PROJECT) @@ -278,15 +287,16 @@ def join(self, timeout=None): class _Batch(object): + from google.cloud.logging.logger import _GLOBAL_RESOURCE def __init__(self): self.entries = [] self.commit_called = False self.commit_count = None - def log_struct(self, info, severity=logging.INFO): - self.log_struct_called_with = (info, severity) - self.entries.append(info) + def log_struct(self, record, severity=logging.INFO, resource=_GLOBAL_RESOURCE): + self.log_struct_called_with = (record, severity, resource) + self.entries.append(record) def commit(self): self.commit_called = True diff --git a/logging/tests/unit/handlers/transports/test_base.py b/logging/tests/unit/handlers/transports/test_base.py index 29aca81bab3f..f797e0b09338 100644 --- a/logging/tests/unit/handlers/transports/test_base.py +++ b/logging/tests/unit/handlers/transports/test_base.py @@ -31,7 +31,7 @@ def _make_one(self, *args, **kw): def test_send_is_abstract(self): target = self._make_one() with self.assertRaises(NotImplementedError): - target.send(None, None) + target.send(None, None, None) def test_flush_is_abstract_and_optional(self): target = self._make_one() diff --git a/logging/tests/unit/handlers/transports/test_sync.py b/logging/tests/unit/handlers/transports/test_sync.py index 562a7175380b..64c61cf23c4a 100644 --- a/logging/tests/unit/handlers/transports/test_sync.py +++ b/logging/tests/unit/handlers/transports/test_sync.py @@ -14,6 +14,8 @@ import logging import unittest +from google.cloud.logging.resource import Resource +from google.cloud.logging.logger import _GLOBAL_RESOURCE class TestSyncHandler(unittest.TestCase): @@ -36,6 +38,13 @@ def test_ctor(self): self.assertEqual(transport.logger.name, 'python_logger') def test_send(self): + RESOURCE = Resource( + type='gae_app', + labels={ + 'module_id': 'default', + 'version_id': 'test', + }) + client = _Client(self.PROJECT) stackdriver_logger_name = 'python' @@ -45,12 +54,12 @@ def test_send(self): record = logging.LogRecord(python_logger_name, logging.INFO, None, None, message, None, None) - transport.send(record, message) + transport.send(record, message, RESOURCE) EXPECTED_STRUCT = { 'message': message, 'python_logger': python_logger_name, } - EXPECTED_SENT = (EXPECTED_STRUCT, 'INFO') + EXPECTED_SENT = (EXPECTED_STRUCT, 'INFO', RESOURCE) self.assertEqual( transport.logger.log_struct_called_with, EXPECTED_SENT) @@ -60,8 +69,8 @@ class _Logger(object): def __init__(self, name): self.name = name - def log_struct(self, message, severity=None): - self.log_struct_called_with = (message, severity) + def log_struct(self, message, severity=None, resource=_GLOBAL_RESOURCE): + self.log_struct_called_with = (message, severity, resource) class _Client(object): diff --git a/logging/tests/unit/test_client.py b/logging/tests/unit/test_client.py index 6cd7c42926f6..1655dd7ad1c6 100644 --- a/logging/tests/unit/test_client.py +++ b/logging/tests/unit/test_client.py @@ -560,23 +560,23 @@ def test_list_metrics_with_paging(self): }) def test_get_default_handler_app_engine(self): + import httplib2 import os from google.cloud._testing import _Monkey - from google.cloud._testing import _tempdir from google.cloud.logging.client import _APPENGINE_FLEXIBLE_ENV_VM - from google.cloud.logging.handlers import app_engine as _MUT from google.cloud.logging.handlers import AppEngineHandler - client = self._make_one(project=self.PROJECT, - credentials=_make_credentials(), - _use_grpc=False) + http_mock = mock.Mock(spec=httplib2.Http) + credentials = _make_credentials() + deepcopy = mock.Mock(return_value=http_mock) - with _tempdir() as tempdir: - temp_log_path = os.path.join(tempdir, '{pid}') - with _Monkey(_MUT, _LOG_PATH_TEMPLATE=temp_log_path): - with _Monkey(os, environ={_APPENGINE_FLEXIBLE_ENV_VM: 'True'}): - handler = client.get_default_handler() - handler.close() # allow tempdir cleanup on Windows + with _Monkey(os, environ={_APPENGINE_FLEXIBLE_ENV_VM: 'True'}): + with mock.patch('copy.deepcopy', new=deepcopy): + client = self._make_one(project=self.PROJECT, + credentials=credentials, + _use_grpc=False) + handler = client.get_default_handler() + deepcopy.assert_called_once_with(client._http) self.assertIsInstance(handler, AppEngineHandler) From 4d1924f0b3024c3b81e6a7af118d50d137e4098b Mon Sep 17 00:00:00 2001 From: Angela Li Date: Fri, 12 May 2017 17:02:10 -0700 Subject: [PATCH 2/6] Address jon and bill's comments --- .../cloud/logging/handlers/app_engine.py | 28 ++++++++----------- .../google/cloud/logging/handlers/handlers.py | 10 +++++-- .../handlers/transports/background_thread.py | 4 +-- .../tests/unit/handlers/test_app_engine.py | 13 +++++---- logging/tests/unit/handlers/test_handlers.py | 10 ++++--- .../transports/test_background_thread.py | 6 ++-- 6 files changed, 37 insertions(+), 34 deletions(-) diff --git a/logging/google/cloud/logging/handlers/app_engine.py b/logging/google/cloud/logging/handlers/app_engine.py index a0a25d24a8ec..834ca8347160 100644 --- a/logging/google/cloud/logging/handlers/app_engine.py +++ b/logging/google/cloud/logging/handlers/app_engine.py @@ -27,6 +27,7 @@ # /appengine-vmruntime/vmruntime/cloud_logging.py import logging.handlers +import os from google.cloud.logging.handlers.handlers import CloudLoggingHandler from google.cloud.logging.handlers.transports import BackgroundThreadTransport @@ -36,7 +37,14 @@ EXCLUDED_LOGGER_DEFAULTS = ('google.cloud', 'oauth2client') -_GLOBAL_RESOURCE = Resource(type='global', labels={}) +GAE_RESOURCE = Resource( + type='gae_app', + labels={ + 'project_id': os.getenv('GCLOUD_PROJECT'), + 'module_id': os.getenv('GAE_SERVICE'), + 'version_id': os.getenv('GAE_VERSION'), + }, +) class AppEngineHandler(CloudLoggingHandler): @@ -71,19 +79,5 @@ class AppEngineHandler(CloudLoggingHandler): def __init__(self, client, name=DEFAULT_LOGGER_NAME, transport=BackgroundThreadTransport, - resource=_GLOBAL_RESOURCE): - super(AppEngineHandler, self).__init__(client, name, transport) - self.resource=resource - - def emit(self, record): - """Actually log the specified logging record. - - Overrides the default emit behavior of ``StreamHandler``. - - See: https://docs.python.org/2/library/logging.html#handler-objects - - :type record: :class:`logging.LogRecord` - :param record: The record to be logged. - """ - message = super(CloudLoggingHandler, self).format(record) - self.transport.send(record, message, self.resource) + resource=GAE_RESOURCE): + super(AppEngineHandler, self).__init__(client, name, transport, resource) diff --git a/logging/google/cloud/logging/handlers/handlers.py b/logging/google/cloud/logging/handlers/handlers.py index 62ec6c6d561a..c1a88a269524 100644 --- a/logging/google/cloud/logging/handlers/handlers.py +++ b/logging/google/cloud/logging/handlers/handlers.py @@ -17,6 +17,7 @@ import logging from google.cloud.logging.handlers.transports import BackgroundThreadTransport +from google.cloud.logging.logger import _GLOBAL_RESOURCE DEFAULT_LOGGER_NAME = 'python' @@ -52,6 +53,9 @@ class CloudLoggingHandler(logging.StreamHandler): :class:`.BackgroundThreadTransport`. The other option is :class:`.SyncTransport`. + :type resource: :class:`~google.cloud.logging.resource.Resource` + :param resource: (Optional) Monitored resource of the entry + Example: .. code-block:: python @@ -73,11 +77,13 @@ class CloudLoggingHandler(logging.StreamHandler): def __init__(self, client, name=DEFAULT_LOGGER_NAME, - transport=BackgroundThreadTransport): + transport=BackgroundThreadTransport, + resource=_GLOBAL_RESOURCE): super(CloudLoggingHandler, self).__init__() self.name = name self.client = client self.transport = transport(client, name) + self.resource=resource def emit(self, record): """Actually log the specified logging record. @@ -90,7 +96,7 @@ def emit(self, record): :param record: The record to be logged. """ message = super(CloudLoggingHandler, self).format(record) - self.transport.send(record, message) + self.transport.send(record, message, self.resource) def setup_logging(handler, excluded_loggers=EXCLUDED_LOGGER_DEFAULTS, diff --git a/logging/google/cloud/logging/handlers/transports/background_thread.py b/logging/google/cloud/logging/handlers/transports/background_thread.py index 417e639f8753..7cc94b02ffe3 100644 --- a/logging/google/cloud/logging/handlers/transports/background_thread.py +++ b/logging/google/cloud/logging/handlers/transports/background_thread.py @@ -28,15 +28,13 @@ from six.moves import queue from google.cloud.logging.handlers.transports.base import Transport -from google.cloud.logging.resource import Resource - +from google.cloud.logging.logger import _GLOBAL_RESOURCE _DEFAULT_GRACE_PERIOD = 5.0 # Seconds _DEFAULT_MAX_BATCH_SIZE = 10 _WORKER_THREAD_NAME = 'google.cloud.logging.Worker' _WORKER_TERMINATOR = object() _LOGGER = logging.getLogger(__name__) -_GLOBAL_RESOURCE = Resource(type='global', labels={}) def _get_many(queue_, max_items=None): diff --git a/logging/tests/unit/handlers/test_app_engine.py b/logging/tests/unit/handlers/test_app_engine.py index d0749f9d9550..6f946e15fb6c 100644 --- a/logging/tests/unit/handlers/test_app_engine.py +++ b/logging/tests/unit/handlers/test_app_engine.py @@ -13,6 +13,7 @@ # limitations under the License. import logging +import os import unittest from google.cloud.logging.resource import Resource @@ -37,12 +38,14 @@ def test_emit(self): RESOURCE = Resource( type='gae_app', labels={ - 'module_id': 'default', - 'version_id': 'test', - }) + 'project_id': os.getenv('GCLOUD_PROJECT'), + 'module_id': os.getenv('GAE_SERVICE'), + 'version_id': os.getenv('GAE_VERSION'), + }, + ) client = _Client(self.PROJECT) - handler = self._make_one(client, transport=_Transport, resource=RESOURCE) + handler = self._make_one(client, transport=_Transport) logname = 'loggername' message = 'hello world' record = logging.LogRecord(logname, logging, None, None, message, @@ -64,4 +67,4 @@ def __init__(self, client, name): pass def send(self, record, message, resource): - self.send_called_with = (record, message, resource) \ No newline at end of file + self.send_called_with = (record, message, resource) diff --git a/logging/tests/unit/handlers/test_handlers.py b/logging/tests/unit/handlers/test_handlers.py index 26d3e6352024..05dc87631478 100644 --- a/logging/tests/unit/handlers/test_handlers.py +++ b/logging/tests/unit/handlers/test_handlers.py @@ -35,15 +35,17 @@ def test_ctor(self): self.assertEqual(handler.client, client) def test_emit(self): + from google.cloud.logging.logger import _GLOBAL_RESOURCE + client = _Client(self.PROJECT) - handler = self._make_one(client, transport=_Transport) + 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) handler.emit(record) - self.assertEqual(handler.transport.send_called_with, (record, message)) + self.assertEqual(handler.transport.send_called_with, (record, message, _GLOBAL_RESOURCE)) class TestSetupLogging(unittest.TestCase): @@ -108,5 +110,5 @@ class _Transport(object): def __init__(self, client, name): pass - def send(self, record, message): - self.send_called_with = (record, message) + def send(self, record, message, resource): + self.send_called_with = (record, message, resource) diff --git a/logging/tests/unit/handlers/transports/test_background_thread.py b/logging/tests/unit/handlers/transports/test_background_thread.py index 8d62f66b8a96..78484857c35b 100644 --- a/logging/tests/unit/handlers/transports/test_background_thread.py +++ b/logging/tests/unit/handlers/transports/test_background_thread.py @@ -294,9 +294,9 @@ def __init__(self): self.commit_called = False self.commit_count = None - def log_struct(self, record, severity=logging.INFO, resource=_GLOBAL_RESOURCE): - self.log_struct_called_with = (record, severity, resource) - self.entries.append(record) + def log_struct(self, info, severity=logging.INFO, resource=_GLOBAL_RESOURCE): + self.log_struct_called_with = (info, severity, resource) + self.entries.append(info) def commit(self): self.commit_called = True From 2591ef1c16c09026edc9e22638b1e892bb0199ac Mon Sep 17 00:00:00 2001 From: Angela Li Date: Mon, 15 May 2017 12:34:53 -0700 Subject: [PATCH 3/6] fix stuff --- .../cloud/logging/handlers/app_engine.py | 48 ++++++++----------- .../google/cloud/logging/handlers/handlers.py | 4 +- .../handlers/transports/background_thread.py | 5 +- .../cloud/logging/handlers/transports/base.py | 2 +- .../cloud/logging/handlers/transports/sync.py | 5 +- .../tests/unit/handlers/test_app_engine.py | 28 ++++++----- .../transports/test_background_thread.py | 12 ++--- .../unit/handlers/transports/test_sync.py | 14 ++---- 8 files changed, 49 insertions(+), 69 deletions(-) diff --git a/logging/google/cloud/logging/handlers/app_engine.py b/logging/google/cloud/logging/handlers/app_engine.py index 834ca8347160..eb4bd10f9c79 100644 --- a/logging/google/cloud/logging/handlers/app_engine.py +++ b/logging/google/cloud/logging/handlers/app_engine.py @@ -14,37 +14,18 @@ """Logging handler for App Engine Flexible -Logs to the well-known file that the fluentd sidecar container on App Engine -Flexible is configured to read from and send to Stackdriver Logging. - -See the fluentd configuration here: - -https://github.com/GoogleCloudPlatform/appengine-sidecars-docker/tree/master/fluentd_logger +Sends logs to the Stackdriver Logging API with the appropriate resource and labels for App Engine logs. """ -# This file is largely copied from: -# https://github.com/GoogleCloudPlatform/python-compat-runtime/blob/master -# /appengine-vmruntime/vmruntime/cloud_logging.py - -import logging.handlers import os from google.cloud.logging.handlers.handlers import CloudLoggingHandler from google.cloud.logging.handlers.transports import BackgroundThreadTransport from google.cloud.logging.resource import Resource -DEFAULT_LOGGER_NAME = 'python' - -EXCLUDED_LOGGER_DEFAULTS = ('google.cloud', 'oauth2client') - -GAE_RESOURCE = Resource( - type='gae_app', - labels={ - 'project_id': os.getenv('GCLOUD_PROJECT'), - 'module_id': os.getenv('GAE_SERVICE'), - 'version_id': os.getenv('GAE_VERSION'), - }, -) +_GAE_PROJECT_ENV = 'GCLOUD_PROJECT' +_GAE_SERVICE_ENV = 'GAE_SERVICE' +_GAE_VERSION_ENV = 'GAE_VERSION' class AppEngineHandler(CloudLoggingHandler): @@ -76,8 +57,21 @@ class AppEngineHandler(CloudLoggingHandler): to the global resource type. """ + DEFAULT_LOGGER_NAME = 'projects/{}/logs/app'.format(os.environ.get(_GAE_PROJECT_ENV)) + def __init__(self, client, - name=DEFAULT_LOGGER_NAME, - transport=BackgroundThreadTransport, - resource=GAE_RESOURCE): - super(AppEngineHandler, self).__init__(client, name, transport, resource) + transport=BackgroundThreadTransport): + super(AppEngineHandler, self).__init__(client, name=self.DEFAULT_LOGGER_NAME, + transport=transport, resource=self.gae_resource) + + @property + def gae_resource(self): + gae_resource = Resource( + type='gae_app', + labels={ + 'project_id': os.environ.get(_GAE_PROJECT_ENV), + 'module_id': os.environ.get(_GAE_SERVICE_ENV), + 'version_id': os.environ.get(_GAE_VERSION_ENV), + }, + ) + return gae_resource diff --git a/logging/google/cloud/logging/handlers/handlers.py b/logging/google/cloud/logging/handlers/handlers.py index c1a88a269524..dfedc556c8b0 100644 --- a/logging/google/cloud/logging/handlers/handlers.py +++ b/logging/google/cloud/logging/handlers/handlers.py @@ -83,7 +83,7 @@ def __init__(self, client, self.name = name self.client = client self.transport = transport(client, name) - self.resource=resource + self.resource = resource def emit(self, record): """Actually log the specified logging record. @@ -96,7 +96,7 @@ def emit(self, record): :param record: The record to be logged. """ message = super(CloudLoggingHandler, self).format(record) - self.transport.send(record, message, self.resource) + self.transport.send(record, message, resource=self.resource) def setup_logging(handler, excluded_loggers=EXCLUDED_LOGGER_DEFAULTS, diff --git a/logging/google/cloud/logging/handlers/transports/background_thread.py b/logging/google/cloud/logging/handlers/transports/background_thread.py index 7cc94b02ffe3..6c1af4838bc5 100644 --- a/logging/google/cloud/logging/handlers/transports/background_thread.py +++ b/logging/google/cloud/logging/handlers/transports/background_thread.py @@ -28,7 +28,6 @@ from six.moves import queue from google.cloud.logging.handlers.transports.base import Transport -from google.cloud.logging.logger import _GLOBAL_RESOURCE _DEFAULT_GRACE_PERIOD = 5.0 # Seconds _DEFAULT_MAX_BATCH_SIZE = 10 @@ -258,7 +257,7 @@ def __init__(self, client, name, grace_period=_DEFAULT_GRACE_PERIOD, self.worker = _Worker(logger) self.worker.start() - def send(self, record, message, resource=_GLOBAL_RESOURCE): + def send(self, record, message, resource=None): """Overrides Transport.send(). :type record: :class:`logging.LogRecord` @@ -272,7 +271,7 @@ def send(self, record, message, resource=_GLOBAL_RESOURCE): :param resource: Monitored resource of the entry, defaults to the global resource type. """ - self.worker.enqueue(record, message, resource) + self.worker.enqueue(record, message, resource=resource) def flush(self): """Submit any pending log records.""" diff --git a/logging/google/cloud/logging/handlers/transports/base.py b/logging/google/cloud/logging/handlers/transports/base.py index eef1afdad18e..da27e60d809d 100644 --- a/logging/google/cloud/logging/handlers/transports/base.py +++ b/logging/google/cloud/logging/handlers/transports/base.py @@ -22,7 +22,7 @@ class Transport(object): client and name object, and must override :meth:`send`. """ - def send(self, record, message, resource): + def send(self, record, message, resource=None): """Transport send to be implemented by subclasses. :type record: :class:`logging.LogRecord` diff --git a/logging/google/cloud/logging/handlers/transports/sync.py b/logging/google/cloud/logging/handlers/transports/sync.py index d1aa2e69dca4..7233ec891529 100644 --- a/logging/google/cloud/logging/handlers/transports/sync.py +++ b/logging/google/cloud/logging/handlers/transports/sync.py @@ -21,9 +21,6 @@ from google.cloud.logging.resource import Resource -_GLOBAL_RESOURCE = Resource(type='global', labels={}) - - class SyncTransport(Transport): """Basic sychronous transport. @@ -33,7 +30,7 @@ class SyncTransport(Transport): def __init__(self, client, name): self.logger = client.logger(name) - def send(self, record, message, resource=_GLOBAL_RESOURCE): + def send(self, record, message, resource=None): """Overrides transport.send(). :type record: :class:`logging.LogRecord` diff --git a/logging/tests/unit/handlers/test_app_engine.py b/logging/tests/unit/handlers/test_app_engine.py index 6f946e15fb6c..7c9772dad350 100644 --- a/logging/tests/unit/handlers/test_app_engine.py +++ b/logging/tests/unit/handlers/test_app_engine.py @@ -13,12 +13,11 @@ # limitations under the License. import logging -import os import unittest -from google.cloud.logging.resource import Resource class TestAppEngineHandlerHandler(unittest.TestCase): + PROJECT = 'PROJECT' def _get_target_class(self): @@ -30,29 +29,32 @@ def _make_one(self, *args, **kw): return self._get_target_class()(*args, **kw) def test_ctor(self): + import os + from google.cloud._testing import _Monkey + from google.cloud.logging.handlers.app_engine import _GAE_PROJECT_ENV, _GAE_SERVICE_ENV, _GAE_VERSION_ENV + client = _Client(self.PROJECT) - handler = self._make_one(client, transport=_Transport) + with _Monkey(os, environ={_GAE_PROJECT_ENV: 'test_project', + _GAE_SERVICE_ENV: 'test_service', + _GAE_VERSION_ENV: 'test_version'}): + handler = self._make_one(client, transport=_Transport) self.assertEqual(handler.client, client) + self.assertEqual(handler.resource.type, 'gae_app') + self.assertEqual(handler.resource.labels['project_id'], 'test_project') + self.assertEqual(handler.resource.labels['module_id'], 'test_service') + self.assertEqual(handler.resource.labels['version_id'], 'test_version') def test_emit(self): - RESOURCE = Resource( - type='gae_app', - labels={ - 'project_id': os.getenv('GCLOUD_PROJECT'), - 'module_id': os.getenv('GAE_SERVICE'), - 'version_id': os.getenv('GAE_VERSION'), - }, - ) - client = _Client(self.PROJECT) handler = self._make_one(client, transport=_Transport) + gae_resource = handler.gae_resource logname = 'loggername' message = 'hello world' record = logging.LogRecord(logname, logging, None, None, message, None, None) handler.emit(record) - self.assertEqual(handler.transport.send_called_with, (record, message, RESOURCE)) + self.assertEqual(handler.transport.send_called_with, (record, message, gae_resource)) class _Client(object): diff --git a/logging/tests/unit/handlers/transports/test_background_thread.py b/logging/tests/unit/handlers/transports/test_background_thread.py index 78484857c35b..149c37c8cde0 100644 --- a/logging/tests/unit/handlers/transports/test_background_thread.py +++ b/logging/tests/unit/handlers/transports/test_background_thread.py @@ -14,7 +14,6 @@ import logging import unittest -from google.cloud.logging.resource import Resource import mock from six.moves import queue @@ -48,12 +47,7 @@ def test_constructor(self): self.assertEqual(logger.name, name) def test_send(self): - RESOURCE = Resource( - type='gae_app', - labels={ - 'module_id': 'default', - 'version_id': 'test', - }) + from google.cloud.logging.logger import _GLOBAL_RESOURCE client = _Client(self.PROJECT) name = 'python_logger' @@ -67,9 +61,9 @@ def test_send(self): python_logger_name, logging.INFO, None, None, message, None, None) - transport.send(record, message, RESOURCE) + transport.send(record, message, _GLOBAL_RESOURCE) - transport.worker.enqueue.assert_called_once_with(record, message, RESOURCE) + transport.worker.enqueue.assert_called_once_with(record, message, _GLOBAL_RESOURCE) def test_flush(self): client = _Client(self.PROJECT) diff --git a/logging/tests/unit/handlers/transports/test_sync.py b/logging/tests/unit/handlers/transports/test_sync.py index 64c61cf23c4a..475ecc9c6a71 100644 --- a/logging/tests/unit/handlers/transports/test_sync.py +++ b/logging/tests/unit/handlers/transports/test_sync.py @@ -14,8 +14,6 @@ import logging import unittest -from google.cloud.logging.resource import Resource -from google.cloud.logging.logger import _GLOBAL_RESOURCE class TestSyncHandler(unittest.TestCase): @@ -38,12 +36,7 @@ def test_ctor(self): self.assertEqual(transport.logger.name, 'python_logger') def test_send(self): - RESOURCE = Resource( - type='gae_app', - labels={ - 'module_id': 'default', - 'version_id': 'test', - }) + from google.cloud.logging.logger import _GLOBAL_RESOURCE client = _Client(self.PROJECT) @@ -54,17 +47,18 @@ def test_send(self): record = logging.LogRecord(python_logger_name, logging.INFO, None, None, message, None, None) - transport.send(record, message, RESOURCE) + transport.send(record, message, _GLOBAL_RESOURCE) EXPECTED_STRUCT = { 'message': message, 'python_logger': python_logger_name, } - EXPECTED_SENT = (EXPECTED_STRUCT, 'INFO', RESOURCE) + EXPECTED_SENT = (EXPECTED_STRUCT, 'INFO', _GLOBAL_RESOURCE) self.assertEqual( transport.logger.log_struct_called_with, EXPECTED_SENT) class _Logger(object): + from google.cloud.logging.logger import _GLOBAL_RESOURCE def __init__(self, name): self.name = name From 38f62d9b67d41bf2e2938065860e4dbb7004efe4 Mon Sep 17 00:00:00 2001 From: Angela Li Date: Tue, 16 May 2017 11:10:14 -0700 Subject: [PATCH 4/6] Change default logName --- logging/google/cloud/logging/handlers/app_engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/google/cloud/logging/handlers/app_engine.py b/logging/google/cloud/logging/handlers/app_engine.py index eb4bd10f9c79..4e09a76b8921 100644 --- a/logging/google/cloud/logging/handlers/app_engine.py +++ b/logging/google/cloud/logging/handlers/app_engine.py @@ -57,7 +57,7 @@ class AppEngineHandler(CloudLoggingHandler): to the global resource type. """ - DEFAULT_LOGGER_NAME = 'projects/{}/logs/app'.format(os.environ.get(_GAE_PROJECT_ENV)) + DEFAULT_LOGGER_NAME = 'app' def __init__(self, client, transport=BackgroundThreadTransport): From 737e81703c1f7883628295e42ebcf6c554277959 Mon Sep 17 00:00:00 2001 From: Angela Li Date: Tue, 16 May 2017 11:45:47 -0700 Subject: [PATCH 5/6] fix style --- .../cloud/logging/handlers/app_engine.py | 53 ++++++++----------- .../handlers/transports/background_thread.py | 5 +- .../cloud/logging/handlers/transports/base.py | 3 +- .../cloud/logging/handlers/transports/sync.py | 5 +- .../tests/unit/handlers/test_app_engine.py | 32 +++++------ 5 files changed, 43 insertions(+), 55 deletions(-) diff --git a/logging/google/cloud/logging/handlers/app_engine.py b/logging/google/cloud/logging/handlers/app_engine.py index 4e09a76b8921..08b2a883b521 100644 --- a/logging/google/cloud/logging/handlers/app_engine.py +++ b/logging/google/cloud/logging/handlers/app_engine.py @@ -14,7 +14,8 @@ """Logging handler for App Engine Flexible -Sends logs to the Stackdriver Logging API with the appropriate resource and labels for App Engine logs. +Sends logs to the Stackdriver Logging API with the appropriate resource +and labels for App Engine logs. """ import os @@ -23,49 +24,41 @@ from google.cloud.logging.handlers.transports import BackgroundThreadTransport from google.cloud.logging.resource import Resource +_DEFAULT_GAE_LOGGER_NAME = 'app' + _GAE_PROJECT_ENV = 'GCLOUD_PROJECT' _GAE_SERVICE_ENV = 'GAE_SERVICE' _GAE_VERSION_ENV = 'GAE_VERSION' class AppEngineHandler(CloudLoggingHandler): - """A handler that directly makes Stackdriver logging API calls. - - This handler can be used to route Python standard logging messages directly - to the Stackdriver Logging API. - - This handler supports both an asynchronous and synchronous transport. - - :type client: :class:`google.cloud.logging.client` - :param client: the authenticated Google Cloud Logging client for this - handler to use + """A logging handler that sends App Engine-formatted logs to Stackdriver. - :type name: str - :param name: the name of the custom log in Stackdriver Logging. Defaults - to 'python'. The name of the Python logger will be represented - in the ``python_logger`` field. + :type client: :class:`~google.cloud.logging.client.Client` + :param client: The authenticated Google Cloud Logging client for this + handler to use. :type transport: type - :param transport: Class for creating new transport objects. It should - extend from the base :class:`.Transport` type and - implement :meth`.Transport.send`. Defaults to - :class:`.BackgroundThreadTransport`. The other - option is :class:`.SyncTransport`. - - :type resource: :class:`~google.cloud.logging.resource.Resource` - :param resource: Monitored resource of the entry, defaults - to the global resource type. + :param transport: The transport class. It should be a subclass + of :class:`.Transport`. If unspecified, + :class:`.BackgroundThreadTransport` will be used. """ - DEFAULT_LOGGER_NAME = 'app' - def __init__(self, client, transport=BackgroundThreadTransport): - super(AppEngineHandler, self).__init__(client, name=self.DEFAULT_LOGGER_NAME, - transport=transport, resource=self.gae_resource) + super(AppEngineHandler, self).__init__( + client, + name=_DEFAULT_GAE_LOGGER_NAME, + transport=transport, + resource=self.get_gae_resource()) + + def get_gae_resource(self): + """Return the GAE resource using the environment variables. + + :rtype: :class:`~google.cloud.logging.resource.Resource` + :returns: Monitored resource for GAE. + """ - @property - def gae_resource(self): gae_resource = Resource( type='gae_app', labels={ diff --git a/logging/google/cloud/logging/handlers/transports/background_thread.py b/logging/google/cloud/logging/handlers/transports/background_thread.py index 6c1af4838bc5..010c06b36bc9 100644 --- a/logging/google/cloud/logging/handlers/transports/background_thread.py +++ b/logging/google/cloud/logging/handlers/transports/background_thread.py @@ -212,7 +212,7 @@ def enqueue(self, record, message, resource=None): :type message: str :param message: The message from the ``LogRecord`` after being formatted by the associated log formatters. - + :type resource: :class:`~google.cloud.logging.resource.Resource` :param resource: (Optional) Monitored resource of the entry """ @@ -268,8 +268,7 @@ def send(self, record, message, resource=None): formatted by the associated log formatters. :type resource: :class:`~google.cloud.logging.resource.Resource` - :param resource: Monitored resource of the entry, defaults - to the global resource type. + :param resource: (Optional) Monitored resource of the entry. """ self.worker.enqueue(record, message, resource=resource) diff --git a/logging/google/cloud/logging/handlers/transports/base.py b/logging/google/cloud/logging/handlers/transports/base.py index da27e60d809d..21957021793f 100644 --- a/logging/google/cloud/logging/handlers/transports/base.py +++ b/logging/google/cloud/logging/handlers/transports/base.py @@ -33,8 +33,7 @@ def send(self, record, message, resource=None): formatted by the associated log formatters. :type resource: :class:`~google.cloud.logging.resource.Resource` - :param resource: Monitored resource of the entry, defaults - to the global resource type. + :param resource: (Optional) Monitored resource of the entry. """ raise NotImplementedError diff --git a/logging/google/cloud/logging/handlers/transports/sync.py b/logging/google/cloud/logging/handlers/transports/sync.py index 7233ec891529..0dd6e0bd7e24 100644 --- a/logging/google/cloud/logging/handlers/transports/sync.py +++ b/logging/google/cloud/logging/handlers/transports/sync.py @@ -18,7 +18,6 @@ """ from google.cloud.logging.handlers.transports.base import Transport -from google.cloud.logging.resource import Resource class SyncTransport(Transport): @@ -41,4 +40,6 @@ def send(self, record, message, resource=None): formatted by the associated log formatters. """ info = {'message': message, 'python_logger': record.name} - self.logger.log_struct(info, severity=record.levelname, resource=resource) + self.logger.log_struct(info, + severity=record.levelname, + resource=resource) diff --git a/logging/tests/unit/handlers/test_app_engine.py b/logging/tests/unit/handlers/test_app_engine.py index 7c9772dad350..3fed0e315252 100644 --- a/logging/tests/unit/handlers/test_app_engine.py +++ b/logging/tests/unit/handlers/test_app_engine.py @@ -17,7 +17,6 @@ class TestAppEngineHandlerHandler(unittest.TestCase): - PROJECT = 'PROJECT' def _get_target_class(self): @@ -28,26 +27,29 @@ def _get_target_class(self): def _make_one(self, *args, **kw): return self._get_target_class()(*args, **kw) - def test_ctor(self): - import os - from google.cloud._testing import _Monkey - from google.cloud.logging.handlers.app_engine import _GAE_PROJECT_ENV, _GAE_SERVICE_ENV, _GAE_VERSION_ENV + def test_constructor(self): + import mock + from google.cloud.logging.handlers.app_engine import _GAE_PROJECT_ENV + from google.cloud.logging.handlers.app_engine import _GAE_SERVICE_ENV + from google.cloud.logging.handlers.app_engine import _GAE_VERSION_ENV - client = _Client(self.PROJECT) - with _Monkey(os, environ={_GAE_PROJECT_ENV: 'test_project', - _GAE_SERVICE_ENV: 'test_service', - _GAE_VERSION_ENV: 'test_version'}): + client = mock.Mock(project=self.PROJECT, spec=['project']) + with mock.patch('os.environ', new={_GAE_PROJECT_ENV: 'test_project', + _GAE_SERVICE_ENV: 'test_service', + _GAE_VERSION_ENV: 'test_version'}): handler = self._make_one(client, transport=_Transport) - self.assertEqual(handler.client, client) + self.assertIs(handler.client, client) self.assertEqual(handler.resource.type, 'gae_app') self.assertEqual(handler.resource.labels['project_id'], 'test_project') self.assertEqual(handler.resource.labels['module_id'], 'test_service') self.assertEqual(handler.resource.labels['version_id'], 'test_version') def test_emit(self): - client = _Client(self.PROJECT) + import mock + + client = mock.Mock(project=self.PROJECT, spec=['project']) handler = self._make_one(client, transport=_Transport) - gae_resource = handler.gae_resource + gae_resource = handler.get_gae_resource() logname = 'loggername' message = 'hello world' record = logging.LogRecord(logname, logging, None, None, message, @@ -57,12 +59,6 @@ def test_emit(self): self.assertEqual(handler.transport.send_called_with, (record, message, gae_resource)) -class _Client(object): - - def __init__(self, project): - self.project = project - - class _Transport(object): def __init__(self, client, name): From 1b3d91e03e1a613356e244efbfb42db809de7627 Mon Sep 17 00:00:00 2001 From: Angela Li Date: Wed, 17 May 2017 13:34:25 -0700 Subject: [PATCH 6/6] fix style --- logging/google/cloud/logging/handlers/app_engine.py | 1 - logging/google/cloud/logging/handlers/handlers.py | 3 ++- logging/tests/unit/handlers/test_app_engine.py | 7 +++++-- .../unit/handlers/transports/test_background_thread.py | 8 ++++++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/logging/google/cloud/logging/handlers/app_engine.py b/logging/google/cloud/logging/handlers/app_engine.py index 08b2a883b521..c7394f32262d 100644 --- a/logging/google/cloud/logging/handlers/app_engine.py +++ b/logging/google/cloud/logging/handlers/app_engine.py @@ -58,7 +58,6 @@ def get_gae_resource(self): :rtype: :class:`~google.cloud.logging.resource.Resource` :returns: Monitored resource for GAE. """ - gae_resource = Resource( type='gae_app', labels={ diff --git a/logging/google/cloud/logging/handlers/handlers.py b/logging/google/cloud/logging/handlers/handlers.py index dfedc556c8b0..2269c2858f33 100644 --- a/logging/google/cloud/logging/handlers/handlers.py +++ b/logging/google/cloud/logging/handlers/handlers.py @@ -54,7 +54,8 @@ class CloudLoggingHandler(logging.StreamHandler): option is :class:`.SyncTransport`. :type resource: :class:`~google.cloud.logging.resource.Resource` - :param resource: (Optional) Monitored resource of the entry + :param resource: (Optional) Monitored resource of the entry, defaults + to the global resource type. Example: diff --git a/logging/tests/unit/handlers/test_app_engine.py b/logging/tests/unit/handlers/test_app_engine.py index 3fed0e315252..c39328593f7a 100644 --- a/logging/tests/unit/handlers/test_app_engine.py +++ b/logging/tests/unit/handlers/test_app_engine.py @@ -50,19 +50,22 @@ def test_emit(self): client = mock.Mock(project=self.PROJECT, spec=['project']) handler = self._make_one(client, transport=_Transport) gae_resource = handler.get_gae_resource() - logname = 'loggername' + logname = 'app' message = 'hello world' record = logging.LogRecord(logname, logging, None, None, message, None, None) handler.emit(record) + self.assertIs(handler.transport.client, client) + self.assertEqual(handler.transport.name, logname) self.assertEqual(handler.transport.send_called_with, (record, message, gae_resource)) class _Transport(object): def __init__(self, client, name): - pass + self.client = client + self.name = name def send(self, record, message, resource): self.send_called_with = (record, message, resource) diff --git a/logging/tests/unit/handlers/transports/test_background_thread.py b/logging/tests/unit/handlers/transports/test_background_thread.py index 149c37c8cde0..ccc244fa65c8 100644 --- a/logging/tests/unit/handlers/transports/test_background_thread.py +++ b/logging/tests/unit/handlers/transports/test_background_thread.py @@ -281,14 +281,18 @@ def join(self, timeout=None): class _Batch(object): - from google.cloud.logging.logger import _GLOBAL_RESOURCE def __init__(self): self.entries = [] self.commit_called = False self.commit_count = None - def log_struct(self, info, severity=logging.INFO, resource=_GLOBAL_RESOURCE): + def log_struct(self, info, severity=logging.INFO, resource=None): + from google.cloud.logging.logger import _GLOBAL_RESOURCE + + if resource is None: + resource = _GLOBAL_RESOURCE + self.log_struct_called_with = (info, severity, resource) self.entries.append(info)