-
Notifications
You must be signed in to change notification settings - Fork 6.4k
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 Monitoring v3 Samples #223
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Cloud Monitoring v3 Sample | ||
|
||
Sample command-line programs for retrieving Google Monitoring API V3 data. | ||
|
||
`list_resources.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://pypi.python.org/pypi/pip) | ||
|
||
Go to the [Google Cloud Console](https://console.cloud.google.com). | ||
|
||
* Go to API Manager -> Credentials | ||
* Click 'New Credentials', and create a Service Account or [click here](https://console.cloud.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_resources.py --project_id=<YOUR-PROJECT-ID> | ||
python custom_metric.py --project_id=<YOUR-PROJECT-ID | ||
|
||
|
||
## Contributing changes | ||
|
||
* See [CONTRIBUTING.md](CONTRIBUTING.md) | ||
|
||
## Licensing | ||
|
||
* See [LICENSE](LICENSE) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
#!/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> | ||
""" | ||
|
||
# [START all] | ||
import argparse | ||
import datetime | ||
import pprint | ||
import random | ||
import time | ||
|
||
import list_resources | ||
|
||
|
||
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 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 = list_resources.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. 3 seconds should be enough to make sure our read call picks up the | ||
# write | ||
time.sleep(3) | ||
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#!/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 random | ||
import time | ||
|
||
from custom_metric import create_custom_metric, get_custom_metric | ||
from custom_metric import read_timeseries, write_timeseries_value | ||
import list_resources | ||
|
||
""" Change this to run against other prjoects | ||
GOOGLE_APPLICATION_CREDENTIALS must be the service account for this project | ||
""" | ||
|
||
# temporarily hard code to whitelisted project | ||
TEST_PROJECT_ID = 'cloud-monitoring-dev' | ||
# TEST_PROJECT_ID = os.getenv("GCLOUD_PROJECT", 'cloud-monitoring-dev') | ||
|
||
""" Custom metric domain for all cusotm metrics""" | ||
CUSTOM_METRIC_DOMAIN = "custom.googleapis.com" | ||
|
||
PROJECT_RESOURCE = "projects/{}".format(TEST_PROJECT_ID) | ||
|
||
METRIC = 'compute.googleapis.com/instance/cpu/usage_time' | ||
METRIC_NAME = ''.join( | ||
random.choice('0123456789ABCDEF') for i in range(16)) | ||
METRIC_RESOURCE = "{}/{}".format( | ||
CUSTOM_METRIC_DOMAIN, METRIC_NAME) | ||
|
||
|
||
def test_custom_metric(): | ||
client = list_resources.get_client() | ||
# Use a constant seed so psuedo random number is known ahead of time | ||
random.seed(1) | ||
pseudo_random_value = random.randint(0, 10) | ||
# Reseed it | ||
random.seed(1) | ||
|
||
INSTANCE_ID = "test_instance" | ||
METRIC_KIND = "GAUGE" | ||
|
||
create_custom_metric( | ||
client, PROJECT_RESOURCE, 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, PROJECT_RESOURCE, METRIC_RESOURCE) | ||
|
||
write_timeseries_value(client, PROJECT_RESOURCE, | ||
METRIC_RESOURCE, INSTANCE_ID, | ||
METRIC_KIND) | ||
# Sometimes on new metric descriptors, writes have a delay in being | ||
# read back. 3 seconds should be enough to make sure our read call | ||
# picks up the write | ||
time.sleep(3) | ||
response = read_timeseries(client, PROJECT_RESOURCE, METRIC_RESOURCE) | ||
value = int( | ||
response['timeSeries'][0]['points'][0]['value']['int64Value']) | ||
# using seed of 1 will create a value of 1 | ||
assert value == pseudo_random_value |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind converting these over to py.test? Should be relatively easy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done