Skip to content

Commit

Permalink
Add Monitoring v3 Samples
Browse files Browse the repository at this point in the history
Refactor v2 samples in to separate directory
Add v3 Samples
Renamed auth to list_env
  • Loading branch information
Bill Prin committed Mar 16, 2016
1 parent 1034b81 commit 0d9d947
Show file tree
Hide file tree
Showing 16 changed files with 2,253 additions and 0 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
56 changes: 56 additions & 0 deletions monitoring/api/v3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Cloud Monitoring v3 Sample

Sample command-line programs for retrieving Google Monitoring API V3 data.

`list_env.py` is a simple command-line program to demonstrate connecting to the Google
Monitoring API to retrieve API data and print out some of the resources.

`custom_metric.py` demonstrates how to create a custom metric and write a TimeSeries
value to it.

## Prerequisites to run locally:

* [pip](https://en.wikipedia.org/wiki/Pip_(package_manager))

Go to the [Google Developers Console](https://console.developer.google.com).

* Go to API Manager -> Credentials
* Click 'New Credentials', and create a Service Account or [click here](https://console.developers.google.com/project/_/apiui/credential/serviceaccount)
Download the JSON for this service account, and set the `GOOGLE_APPLICATION_CREDENTIALS`
environment variable to point to the file containing the JSON credentials.

```
export GOOGLE_APPLICATION_CREDENTIALS=~/Downloads/<project-id>-0123456789abcdef.json
```

# Set Up Your Local Dev Environment
To install, run the following commands. If you want to use [virtualenv](https://virtualenv.readthedocs.org/en/latest/)
(recommended), run the commands within a virtualenv.

* `pip install -r requirements.txt`

To run locally:

python list_env.py --project_id=<YOUR-PROJECT-ID>
python custom_metric.py --project_id=<YOUR-PROJECT-ID


# Testing

test_*.py contains integration tests. If you'd like to run them, change the TEST_PROJECT_ID, check
GOOGLE_APPLICATION_CREDENTIALS is set to the service account of that project, then run

# install the test dependencies
pip install -r requirements-dev.txt
# run the tests using nose
nosetests

## Contributing changes

* See [CONTRIBUTING.md](CONTRIBUTING.md)

## Licensing

* See [LICENSE](LICENSE)


213 changes: 213 additions & 0 deletions monitoring/api/v3/custom_metric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#!/usr/bin/env python
# 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.

""" Sample command-line program for writing and reading Google Monitoring API
V3 custom metrics.
Simple command-line program to demonstrate connecting to the Google
Monitoring API to write custom metrics and read them back.
See README.md for instructions on setting up your development environment.
This example creates a custom metric based on a hypothetical GAUGE measurement.
To run locally:
`python custom_metric.py --project_id=<YOUR-PROJECT-ID> --api_key=<YOUR-BROWSER-API-KEY>`
"""

# [START all]
import argparse
import datetime
import pprint
import random
import time

from googleapiclient import discovery
from oauth2client.client import GoogleCredentials


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_start_time():
# Return now- 5 minutes
start_time = datetime.datetime.utcnow() - datetime.timedelta(minutes=5)
return format_rfc3339(start_time)


def get_now_rfc3339():
# Return now
return format_rfc3339(datetime.datetime.utcnow())


def create_custom_metric(client, project_id,
custom_metric_name, metric_kind):
"""Create custom metric descriptor"""
metrics_descriptor = {
"name": "projects/{}/metricDescriptors/{}".format(
project_id, custom_metric_name),
"type": custom_metric_name,
"labels": [
{
"key": "environment",
"valueType": "STRING",
"description": "An abritrary measurement"
}
],
"metricKind": metric_kind,
"valueType": "INT64",
"unit": "items",
"description": "An arbitrary measurement.",
"displayName": "Custom Metric"
}

client.projects().metricDescriptors().create(
name=project_id, body=metrics_descriptor).execute()


def get_custom_metric(client, project_id, custom_metric_name):
"""Retrieve the custom metric we created"""
request = client.projects().metricDescriptors().list(
name=project_id,
filter='metric.type=starts_with("{}")'.format(custom_metric_name))
response = request.execute()
print('ListCustomMetrics response:')
pprint.pprint(response)
try:
return response['metricDescriptors']
except KeyError:
return None


def get_custom_data_point():
"""Dummy method to return a mock measurement for demonstration purposes.
Returns a random number between 0 and 10"""
length = random.randint(0, 10)
print "reporting timeseries value {}".format(str(length))
return length


def write_timeseries_value(client, project_resource,
custom_metric_name, instance_id, metric_kind):
"""Write the custom metric obtained by get_custom_data_point at a point in
time."""
# Specify a new data point for the time series.
now = get_now_rfc3339()
timeseries_data = {
"metric": {
"type": custom_metric_name,
"labels": {
"environment": "STAGING"
}
},
"resource": {
"type": 'gce_instance',
"labels": {
'instance_id': instance_id,
'zone': 'us-central1-f'
}
},
"metricKind": metric_kind,
"valueType": "INT64",
"points": [
{
"interval": {
"startTime": now,
"endTime": now
},
"value": {
"int64Value": get_custom_data_point()
}
}
]
}

request = client.projects().timeSeries().create(
name=project_resource, body={"timeSeries": [timeseries_data]})
request.execute()


def read_timeseries(client, project_resource, custom_metric_name):
"""Reads all of the CUSTOM_METRICS that we have written between START_TIME
and END_TIME
:param project_resource: Resource of the project to read the timeseries from
:param custom_metric_name: The name of the timeseries we want to read.
"""
request = client.projects().timeSeries().list(
name=project_resource,
filter='metric.type="{0}"'.format(custom_metric_name),
pageSize=3,
interval_startTime=get_start_time(),
interval_endTime=get_now_rfc3339())
response = request.execute()
return response


def get_client():
"""Builds an http client authenticated with the service account
credentials."""
credentials = GoogleCredentials.get_application_default()
client = discovery.build_from_document(
open('discovery.json').read(),
'monitoring', 'v3',
credentials=credentials)
return client


def main(project_id):
# This is the namespace for all custom metrics
CUSTOM_METRIC_DOMAIN = "custom.googleapis.com"
# This is our specific metric name
CUSTOM_METRIC_NAME = "{}/custom_measurement".format(CUSTOM_METRIC_DOMAIN)
INSTANCE_ID = "test_instance"
METRIC_KIND = "GAUGE"

project_resource = "projects/{0}".format(project_id)
client = get_client()
create_custom_metric(client, project_resource,
CUSTOM_METRIC_NAME, METRIC_KIND)
custom_metric = None
while not custom_metric:
# wait until it's created
time.sleep(1)
custom_metric = get_custom_metric(
client, project_resource, CUSTOM_METRIC_NAME)

write_timeseries_value(client, project_resource,
CUSTOM_METRIC_NAME, INSTANCE_ID, METRIC_KIND)
# Sometimes on new metric descriptors, writes have a delay in being read
# back. A second should be enough to make sure our read call picks up the
# write
time.sleep(1)
timeseries = read_timeseries(client, project_resource, CUSTOM_METRIC_NAME)
print('read_timeseries response:\n{}'.format(pprint.pformat(timeseries)))


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)

# [END all]
88 changes: 88 additions & 0 deletions monitoring/api/v3/custom_metric_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env python
# 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.

""" Integration test for custom_metric.py
GOOGLE_APPLICATION_CREDENTIALS must be set to a Service Account for a project
that has enabled the Monitoring API.
Currently the TEST_PROJECT_ID is hard-coded to run using the project created
for this test, but it could be changed to a different project.
"""

import auth
import os
import random
import time
import unittest

from custom_metric import get_client, create_custom_metric, get_custom_metric
from custom_metric import read_timeseries, write_timeseries_value

""" Change this to run against other prjoects
GOOGLE_APPLICATION_CREDENTIALS must be the service account for this project
"""

TEST_PROJECT_ID = os.getenv("GCLOUD_PROJECT", 'cloud-monitoring-dev')

""" Custom metric domain for all cusotm metrics"""
CUSTOM_METRIC_DOMAIN = "custom.googleapis.com"


class CustomMetricIntegration(unittest.TestCase):
"""This test generates a new custom metric id, creates it, waits for it
to be created, writes a time series values to it, then verifies the value
was written as expected. It uses a constant seed so that the random number
generated is expected."""

def setUp(self):
self.project_resource = "projects/{}".format(TEST_PROJECT_ID)
self.client = auth.get_client()
self.metric = 'compute.googleapis.com/instance/cpu/usage_time'
metric_name = ''.join(
random.choice('0123456789ABCDEF') for i in range(16))
self.metric_resource = "{}/{}".format(
CUSTOM_METRIC_DOMAIN, metric_name)

def testCustomMetric(self):
# Use a constant seed so psuedo random number is known ahead of time
random.seed(1)

INSTANCE_ID = "test_instance"
METRIC_KIND = "GAUGE"
client = get_client()

create_custom_metric(client, self.project_resource,
self.metric_resource,
METRIC_KIND)
custom_metric = None
# wait until metric has been created, use the get call to wait until
# a response comes back with the new metric
while not custom_metric:
time.sleep(1)
custom_metric = get_custom_metric(
client, self.project_resource, self.metric_resource)

write_timeseries_value(client, self.project_resource,
self.metric_resource, INSTANCE_ID,
METRIC_KIND)
# Sometimes on new metric descriptors, writes have a delay in being
# read back. A second should be enough to make sure our read call
# picks up the write
time.sleep(1)
response = read_timeseries(
client, self.project_resource, self.metric_resource)
value = int(
response['timeSeries'][0]['points'][0]['value']['int64Value'])
# using seed of 1 will create a value of 1
self.assertEquals(value, 1)
Loading

0 comments on commit 0d9d947

Please sign in to comment.