Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MonitoredResource to interface #3386

Merged
merged 22 commits into from
May 11, 2017
23 changes: 19 additions & 4 deletions logging/google/cloud/logging/entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from google.protobuf import any_pb2
from google.protobuf.json_format import Parse

from google.cloud.logging.resource import Resource
from google.cloud._helpers import _name_from_project_path
from google.cloud._helpers import _rfc3339_nanos_to_datetime

Expand Down Expand Up @@ -72,16 +73,19 @@ class _BaseEntry(object):
:type http_request: dict
:param http_request: (optional) info about HTTP request associated with
the entry
:type resource: :class:`~google.cloud.logging.resource.Resource`

This comment was marked as spam.

:param resource: (Optional) Monitored resource of the entry
"""
def __init__(self, payload, logger, insert_id=None, timestamp=None,
labels=None, severity=None, http_request=None):
labels=None, severity=None, http_request=None, resource=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
self.resource = resource

@classmethod
def from_api_repr(cls, resource, client, loggers=None):
Expand Down Expand Up @@ -118,8 +122,15 @@ def from_api_repr(cls, resource, client, loggers=None):
labels = resource.get('labels')
severity = resource.get('severity')
http_request = resource.get('httpRequest')

monitored_resource_dict = resource.get('resource')
monitored_resource = None
if monitored_resource_dict is not None:
monitored_resource = Resource._from_dict(monitored_resource_dict)

return cls(payload, logger, insert_id=insert_id, timestamp=timestamp,
labels=labels, severity=severity, http_request=http_request)
labels=labels, severity=severity, http_request=http_request,
resource=monitored_resource)


class TextEntry(_BaseEntry):
Expand Down Expand Up @@ -170,14 +181,18 @@ class ProtobufEntry(_BaseEntry):
:type http_request: dict
:param http_request: (optional) info about HTTP request associated with
the entry

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: (Optional) Monitored resource of the entry
"""
_PAYLOAD_KEY = 'protoPayload'

def __init__(self, payload, logger, insert_id=None, timestamp=None,
labels=None, severity=None, http_request=None):
labels=None, severity=None, http_request=None, resource=None):
super(ProtobufEntry, self).__init__(
payload, logger, insert_id=insert_id, timestamp=timestamp,
labels=labels, severity=severity, http_request=http_request)
labels=labels, severity=severity, http_request=http_request,
resource=resource)
if isinstance(self.payload, any_pb2.Any):
self.payload_pb = self.payload
self.payload = None
Expand Down
96 changes: 69 additions & 27 deletions logging/google/cloud/logging/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

from google.protobuf.json_format import MessageToDict
from google.cloud._helpers import _datetime_to_rfc3339
from google.cloud.logging.resource import Resource


_GLOBAL_RESOURCE = Resource(type='global', labels={})

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.



class Logger(object):
Expand Down Expand Up @@ -91,7 +95,8 @@ def batch(self, client=None):

def _make_entry_resource(self, text=None, info=None, message=None,
labels=None, insert_id=None, severity=None,
http_request=None, timestamp=None):
http_request=None, timestamp=None,
resource=_GLOBAL_RESOURCE):

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

"""Return a log entry resource of the appropriate type.

Helper for :meth:`log_text`, :meth:`log_struct`, and :meth:`log_proto`.
Expand Down Expand Up @@ -123,19 +128,22 @@ def _make_entry_resource(self, text=None, info=None, message=None,
:type timestamp: :class:`datetime.datetime`
:param timestamp: (Optional) timestamp of event being logged.

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: (Optional) Monitored resource of the entry

:rtype: dict
:returns: The JSON resource created.
"""
resource = {
entry = {
'logName': self.full_name,
'resource': {'type': 'global'},
'resource': resource._to_dict(),
}

if text is not None:
resource['textPayload'] = text
entry['textPayload'] = text

if info is not None:
resource['jsonPayload'] = info
entry['jsonPayload'] = info

if message is not None:
# NOTE: If ``message`` contains an ``Any`` field with an
Expand All @@ -144,30 +152,31 @@ def _make_entry_resource(self, text=None, info=None, message=None,
# the assumption is that any types needed for the
# protobuf->JSON conversion will be known from already
# imported ``pb2`` modules.
resource['protoPayload'] = MessageToDict(message)
entry['protoPayload'] = MessageToDict(message)

if labels is None:
labels = self.labels

if labels is not None:
resource['labels'] = labels
entry['labels'] = labels

if insert_id is not None:
resource['insertId'] = insert_id
entry['insertId'] = insert_id

if severity is not None:
resource['severity'] = severity
entry['severity'] = severity

if http_request is not None:
resource['httpRequest'] = http_request
entry['httpRequest'] = http_request

if timestamp is not None:
resource['timestamp'] = _datetime_to_rfc3339(timestamp)
entry['timestamp'] = _datetime_to_rfc3339(timestamp)

return resource
return entry

def log_text(self, text, client=None, labels=None, insert_id=None,
severity=None, http_request=None, timestamp=None):
severity=None, http_request=None, timestamp=None,
resource=_GLOBAL_RESOURCE):
"""API call: log a text message via a POST request

See:
Expand All @@ -194,17 +203,22 @@ def log_text(self, text, client=None, labels=None, insert_id=None,
:param http_request: (optional) info about HTTP request associated with
the entry

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: Monitored resource of the entry, defaults
to the global resource type.

:type timestamp: :class:`datetime.datetime`
:param timestamp: (optional) timestamp of event being logged.
"""
client = self._require_client(client)
entry_resource = self._make_entry_resource(
text=text, labels=labels, insert_id=insert_id, severity=severity,
http_request=http_request, timestamp=timestamp)
http_request=http_request, timestamp=timestamp, resource=resource)
client.logging_api.write_entries([entry_resource])

def log_struct(self, info, client=None, labels=None, insert_id=None,
severity=None, http_request=None, timestamp=None):
severity=None, http_request=None, timestamp=None,
resource=_GLOBAL_RESOURCE):
"""API call: log a structured message via a POST request

See:
Expand All @@ -231,17 +245,22 @@ def log_struct(self, info, client=None, labels=None, insert_id=None,
:param http_request: (optional) info about HTTP request associated with
the entry.

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: Monitored resource of the entry, defaults
to the global resource type.

:type timestamp: :class:`datetime.datetime`
:param timestamp: (optional) timestamp of event being logged.
"""
client = self._require_client(client)
entry_resource = self._make_entry_resource(
info=info, labels=labels, insert_id=insert_id, severity=severity,
http_request=http_request, timestamp=timestamp)
http_request=http_request, timestamp=timestamp, resource=resource)
client.logging_api.write_entries([entry_resource])

def log_proto(self, message, client=None, labels=None, insert_id=None,
severity=None, http_request=None, timestamp=None):
severity=None, http_request=None, timestamp=None,
resource=_GLOBAL_RESOURCE):
"""API call: log a protobuf message via a POST request

See:
Expand All @@ -268,13 +287,17 @@ def log_proto(self, message, client=None, labels=None, insert_id=None,
:param http_request: (optional) info about HTTP request associated with
the entry.

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: Monitored resource of the entry

This comment was marked as spam.


:type timestamp: :class:`datetime.datetime`
:param timestamp: (optional) timestamp of event being logged.
"""
client = self._require_client(client)
entry_resource = self._make_entry_resource(
message=message, labels=labels, insert_id=insert_id,
severity=severity, http_request=http_request, timestamp=timestamp)
severity=severity, http_request=http_request, timestamp=timestamp,
resource=resource)
client.logging_api.write_entries([entry_resource])

def delete(self, client=None):
Expand Down Expand Up @@ -344,11 +367,15 @@ class Batch(object):

:type client: :class:`google.cloud.logging.client.Client`
:param client: The client to use.

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: (Optional) Monitored resource of the batch
"""
def __init__(self, logger, client):
def __init__(self, logger, client, resource=None):
self.logger = logger
self.entries = []
self.client = client
self.resource = resource

def __enter__(self):
return self
Expand All @@ -358,7 +385,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
self.commit()

def log_text(self, text, labels=None, insert_id=None, severity=None,
http_request=None, timestamp=None):
http_request=None, timestamp=None, resource=_GLOBAL_RESOURCE):
"""Add a text entry to be logged during :meth:`commit`.

:type text: str
Expand All @@ -379,13 +406,17 @@ def log_text(self, text, labels=None, insert_id=None, severity=None,

:type timestamp: :class:`datetime.datetime`
:param timestamp: (optional) timestamp of event being logged.

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: (Optional) Monitored resource of the entry

This comment was marked as spam.

"""
self.entries.append(
('text', text, labels, insert_id, severity, http_request,
timestamp))
timestamp, resource))

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.


def log_struct(self, info, labels=None, insert_id=None, severity=None,
http_request=None, timestamp=None):
http_request=None, timestamp=None,
resource=_GLOBAL_RESOURCE):
"""Add a struct entry to be logged during :meth:`commit`.

:type info: dict
Expand All @@ -406,13 +437,17 @@ def log_struct(self, info, labels=None, insert_id=None, severity=None,

:type timestamp: :class:`datetime.datetime`
:param timestamp: (optional) timestamp of event being logged.

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: (Optional) Monitored resource of the entry
"""
self.entries.append(
('struct', info, labels, insert_id, severity, http_request,
timestamp))
timestamp, resource))

This comment was marked as spam.


def log_proto(self, message, labels=None, insert_id=None, severity=None,
http_request=None, timestamp=None):
http_request=None, timestamp=None,
resource=_GLOBAL_RESOURCE):
"""Add a protobuf entry to be logged during :meth:`commit`.

:type message: protobuf message
Expand All @@ -433,10 +468,13 @@ def log_proto(self, message, labels=None, insert_id=None, severity=None,

:type timestamp: :class:`datetime.datetime`
:param timestamp: (optional) timestamp of event being logged.

:type resource: :class:`~google.cloud.logging.resource.Resource`
:param resource: (Optional) Monitored resource of the entry
"""
self.entries.append(
('proto', message, labels, insert_id, severity, http_request,
timestamp))
timestamp, resource))

This comment was marked as spam.


def commit(self, client=None):
"""Send saved log entries as a single API call.
Expand All @@ -451,14 +489,16 @@ def commit(self, client=None):

kwargs = {
'logger_name': self.logger.full_name,
'resource': {'type': 'global'},
}

if self.resource is not None:
kwargs['resource'] = self.resource._to_dict()
if self.logger.labels is not None:
kwargs['labels'] = self.logger.labels

entries = []
for (entry_type, entry, labels, iid, severity, http_req,
timestamp) in self.entries:
timestamp, resource) in self.entries:
if entry_type == 'text':
info = {'textPayload': entry}
elif entry_type == 'struct':
Expand All @@ -473,6 +513,8 @@ def commit(self, client=None):
info = {'protoPayload': MessageToDict(entry)}
else:
raise ValueError('Unknown entry type: %s' % (entry_type,))
if resource is not None:
info['resource'] = resource._to_dict()

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

if labels is not None:
info['labels'] = labels
if iid is not None:
Expand Down
58 changes: 58 additions & 0 deletions logging/google/cloud/logging/resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Monitored Resource for the Google Logging API V2."""

import collections


class Resource(collections.namedtuple('Resource', 'type labels')):

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

"""A monitored resource identified by specifying values for all labels.

:type type: str
:param type: The resource type name.

:type labels: dict
:param labels: A mapping from label names to values for all labels
enumerated in the associated :class:`ResourceDescriptor`.
"""
__slots__ = ()

@classmethod
def _from_dict(cls, info):
"""Construct a resource object from the parsed JSON representation.

:type info: dict
:param info:
A ``dict`` parsed from the JSON wire-format representation.

:rtype: :class:`Resource`
:returns: A resource object.
"""
return cls(
type=info['type'],
labels=info.get('labels', {}),
)

def _to_dict(self):
"""Build a dictionary ready to be serialized to the JSON format.

:rtype: dict
:returns: A dict representation of the object that can be written to
the API.
"""
return {
'type': self.type,
'labels': self.labels,
}
Loading