Skip to content

Commit

Permalink
Add Custom Metric Examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Bill Prin committed Feb 24, 2016
1 parent fdbe26d commit 8e457f4
Show file tree
Hide file tree
Showing 5 changed files with 385 additions and 1 deletion.
5 changes: 4 additions & 1 deletion monitoring/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

"""Sample command-line program for retrieving Google Cloud Monitoring API data.
Prerequisites: To run locally, download a Service Account JSON file from
your project and point GOOGLE_APPLICATION_CREDENTIALS to the file.
This sample is used on this page:
https://cloud.google.com/monitoring/api/authentication
Expand All @@ -30,7 +34,6 @@
from googleapiclient.discovery import build
from oauth2client.client import GoogleCredentials


METRIC = 'compute.googleapis.com/instance/disk/read_ops_count'
YOUNGEST = '2015-01-01T00:00:00Z'

Expand Down
197 changes: 197 additions & 0 deletions monitoring/api/labeled_custom_metric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#!/usr/bin/env python

# Copyright 2015 Google Inc. All rights reserved.
#
# 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.


"""Creates, writes, and reads a labeled custom metric.
This is an example of how to use the Google Cloud Monitoring API to create,
write, and read a labeled custom metric.
The metric has two labels: color and size, and the data points represent
the number of shirts of the given color and size in inventory.
Prerequisites: To run locally, download a Service Account JSON file from
your project and point GOOGLE_APPLICATION_CREDENTIALS to the file.
From App Engine or a GCE instance with the correct scope, the Service
Account step is not required.
Typical usage: Run the following shell commands on the instance:
python labeled_custom_metric.py --project_id <project_id> /
--color yellow --size large --count 10
"""

import argparse
import datetime
import time

from googleapiclient import discovery
from oauth2client.client import GoogleCredentials

CUSTOM_METRIC_DOMAIN = "custom.cloudmonitoring.googleapis.com"
CUSTOM_METRIC_NAME = "{}/shirt_inventory".format(CUSTOM_METRIC_DOMAIN)


def format_rfc3339(datetime_instance=None):
"""Formats a datetime per RFC 3339.
:param datetime_instance: Datetime instance to format, defaults to utcnow
"""
return datetime_instance.isoformat("T") + "Z"


def get_now_rfc3339():
return format_rfc3339(datetime.datetime.utcnow())


def create_custom_metric(client, project_id):
"""Create metric descriptor for the custom metric and send it to the
API."""
# You need to execute this operation only once. The operation is
# idempotent, so, for simplicity, this sample code calls it each time

# Create a label descriptor for each of the metric labels. The
# "description" field should be more meaningful for your metrics.
label_descriptors = []
for label in ["color", "size", ]:
label_descriptors.append({"key": "/{}".format(label),
"description": "The {}.".format(label)})

# Create the metric descriptor for the custom metric.
metric_descriptor = {
"name": CUSTOM_METRIC_NAME,
"project": project_id,
"typeDescriptor": {
"metricType": "gauge",
"valueType": "int64",
},
"labels": label_descriptors,
"description": "The size of my shirt inventory.",
}
# Submit the custom metric creation request.
try:
request = client.metricDescriptors().create(
project=project_id, body=metric_descriptor)
request.execute() # ignore the response
except Exception as e:
print("Failed to create custom metric: exception={})".format(e))
raise


def write_custom_metric(client, project_id, now_rfc3339, color, size, count):
"""Write a data point to a single time series of the custom metric."""
# Identify the particular time series to which to write the data by
# specifying the metric and values for each label.
timeseries_descriptor = {
"project": project_id,
"metric": CUSTOM_METRIC_NAME,
"labels": {
"{}/color".format(CUSTOM_METRIC_DOMAIN): color,
"{}/size".format(CUSTOM_METRIC_DOMAIN): size,
}
}

# Specify a new data point for the time series.
timeseries_data = {
"timeseriesDesc": timeseries_descriptor,
"point": {
"start": now_rfc3339,
"end": now_rfc3339,
"int64Value": count,
}
}

# Submit the write request.
request = client.timeseries().write(
project=project_id, body={"timeseries": [timeseries_data, ]})
try:
request.execute() # ignore the response
except Exception as e:
print("Failed to write data to custom metric: exception={}".format(e))
raise


def read_custom_metric(client, project_id, now_rfc3339, color, size):
"""Read all the timeseries data points for a given set of label values."""
# To identify a time series, specify values for in label as a list.
labels = ["{}/color=={}".format(CUSTOM_METRIC_DOMAIN, color),
"{}/size=={}".format(CUSTOM_METRIC_DOMAIN, size), ]

# Submit the read request.
request = client.timeseries().list(
project=project_id,
metric=CUSTOM_METRIC_NAME,
youngest=now_rfc3339,
labels=labels)

# When a custom metric is created, it may take a few seconds
# to propagate throughout the system. Retry a few times.
start = time.time()
while True:
try:
response = request.execute()
for point in response["timeseries"][0]["points"]:
print("{}: {}".format(point["end"], point["int64Value"]))
break
except Exception as e:
if time.time() < start + 20:
print("Failed to read custom metric data, retrying...")
time.sleep(3)
else:
print("Failed to read custom metric data, aborting: "
"exception={}".format(e))
raise


def get_client():
"""Builds an http client authenticated with the application default
credentials."""
credentials = GoogleCredentials.get_application_default()
client = discovery.build(
'cloudmonitoring', 'v2beta2',
credentials=credentials)
return client


def main(project_id, color, size, count):
now_rfc3339 = get_now_rfc3339()

client = get_client()

print ("Labels: color: {}, size: {}.".format(color, size))
print ("Creating custom metric...")
create_custom_metric(client, project_id)
time.sleep(2)
print ("Writing new data to custom metric timeseries...")
write_custom_metric(client, project_id, now_rfc3339,
color, size, count)
print ("Reading data from custom metric timeseries...")
write_custom_metric(client, project_id, now_rfc3339, color,
size, count)


if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
)

parser.add_argument(
'--project_id', help='Project ID you want to access.', required=True)
parser.add_argument("--color", required=True)
parser.add_argument("--size", required=True)
parser.add_argument("--count", required=True)

args = parser.parse_args()
main(args.project_id, args.color, args.size, args.count)
31 changes: 31 additions & 0 deletions monitoring/api/labeled_custom_metric_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env python

# Copyright 2015 Google Inc. All rights reserved.
#
# 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.

import re

import labeled_custom_metric


def test_main(cloud_config, capsys):
labeled_custom_metric.main(cloud_config.project, "yellow", "large", "10")
output, _ = capsys.readouterr()

assert re.search(
re.compile(
r'.*Creating.*'
r'Writing.*'
r'Reading.*', flags=re.DOTALL),
output)
124 changes: 124 additions & 0 deletions monitoring/api/lightweight_custom_metric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env python

# Copyright 2015 Google Inc. All rights reserved.
#
# 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.


"""Writes and reads a lightweight custom metric.
This is an example of how to use the Google Cloud Monitoring API to write
and read a lightweight custom metric. Lightweight custom metrics have no
labels and you do not need to create a metric descriptor for them.
Prerequisites: To run locally, download a Service Account JSON file from
your project and point GOOGLE_APPLICATION_CREDENTIALS to the file.
From App Engine or a GCE instance with the correct scope, the Service
Account step is not required.
Typical usage: Run the following shell commands on the instance:
python lightweight_custom_metric.py --project_id=<YOUR-PROJECT-ID>
"""

import argparse
import datetime
import os
import time

from googleapiclient import discovery
from oauth2client.client import GoogleCredentials

CUSTOM_METRIC_NAME = "custom.cloudmonitoring.googleapis.com/pid"


def format_rfc3339(datetime_instance=None):
"""Formats a datetime per RFC 3339.
:param datetime_instance: Datetime instanec to format, defaults to utcnow
"""
return datetime_instance.isoformat("T") + "Z"


def get_now_rfc3339():
return format_rfc3339(datetime.datetime.utcnow())


def get_client():
"""Builds an http client authenticated with the service account
credentials."""
credentials = GoogleCredentials.get_application_default()
client = discovery.build(
'cloudmonitoring', 'v2beta2',
credentials=credentials)
return client


def main(project_id):
# Set up the write request.
client = get_client()
now = get_now_rfc3339()
desc = {"project": project_id,
"metric": CUSTOM_METRIC_NAME}
point = {"start": now,
"end": now,
"doubleValue": os.getpid()}
print("Writing {} at {}".format(point["doubleValue"], now))

# Write a new data point.
try:
write_request = client.timeseries().write(
project=project_id,
body={"timeseries": [{"timeseriesDesc": desc, "point": point}]})
write_request.execute() # Ignore the response.
except Exception as e:
print("Failed to write custom metric data: exception={}".format(e))
raise

# Read all data points from the time series.
# When a custom metric is created, it may take a few seconds
# to propagate throughout the system. Retry a few times.
print("Reading data from custom metric timeseries...")
read_request = client.timeseries().list(
project=project_id,
metric=CUSTOM_METRIC_NAME,
youngest=now)
start = time.time()
while True:
try:
read_response = read_request.execute()
for point in read_response["timeseries"][0]["points"]:
print("Point: {}: {}".format(
point["end"], point["doubleValue"]))
break
except Exception as e:
if time.time() < start + 20:
print("Failed to read custom metric data, retrying...")
time.sleep(3)
else:
print("Failed to read custom metric data, aborting: "
"exception={}".format(e))
raise


if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)

parser.add_argument(
'--project_id', help='Project ID you want to access.', required=True)

args = parser.parse_args()
main(args.project_id)
Loading

0 comments on commit 8e457f4

Please sign in to comment.