Skip to content

Commit 422d465

Browse files
committed
Merge pull request #223 from GoogleCloudPlatform/monitoringv3
Add Monitoring v3 Samples
2 parents 1733e48 + 395a0d3 commit 422d465

14 files changed

+528
-0
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

monitoring/api/v3/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Cloud Monitoring v3 Sample
2+
3+
Sample command-line programs for retrieving Google Monitoring API V3 data.
4+
5+
`list_resources.py` is a simple command-line program to demonstrate connecting to the Google
6+
Monitoring API to retrieve API data and print out some of the resources.
7+
8+
`custom_metric.py` demonstrates how to create a custom metric and write a TimeSeries
9+
value to it.
10+
11+
## Prerequisites to run locally:
12+
13+
* [pip](https://pypi.python.org/pypi/pip)
14+
15+
Go to the [Google Cloud Console](https://console.cloud.google.com).
16+
17+
* Go to API Manager -> Credentials
18+
* Click 'New Credentials', and create a Service Account or [click here](https://console.cloud.google
19+
.com/project/_/apiui/credential/serviceaccount)
20+
Download the JSON for this service account, and set the `GOOGLE_APPLICATION_CREDENTIALS`
21+
environment variable to point to the file containing the JSON credentials.
22+
23+
24+
export GOOGLE_APPLICATION_CREDENTIALS=~/Downloads/<project-id>-0123456789abcdef.json
25+
26+
27+
# Set Up Your Local Dev Environment
28+
To install, run the following commands. If you want to use [virtualenv](https://virtualenv.readthedocs.org/en/latest/)
29+
(recommended), run the commands within a virtualenv.
30+
31+
* pip install -r requirements.txt
32+
33+
To run locally:
34+
35+
python list_resources.py --project_id=<YOUR-PROJECT-ID>
36+
python custom_metric.py --project_id=<YOUR-PROJECT-ID
37+
38+
39+
## Contributing changes
40+
41+
* See [CONTRIBUTING.md](CONTRIBUTING.md)
42+
43+
## Licensing
44+
45+
* See [LICENSE](LICENSE)
46+
47+

monitoring/api/v3/custom_metric.py

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#!/usr/bin/env python
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
""" Sample command-line program for writing and reading Google Monitoring API
15+
V3 custom metrics.
16+
17+
Simple command-line program to demonstrate connecting to the Google
18+
Monitoring API to write custom metrics and read them back.
19+
20+
See README.md for instructions on setting up your development environment.
21+
22+
This example creates a custom metric based on a hypothetical GAUGE measurement.
23+
24+
To run locally:
25+
26+
python custom_metric.py --project_id=<YOUR-PROJECT-ID>
27+
28+
"""
29+
30+
# [START all]
31+
import argparse
32+
import datetime
33+
import pprint
34+
import random
35+
import time
36+
37+
import list_resources
38+
39+
40+
def format_rfc3339(datetime_instance=None):
41+
"""Formats a datetime per RFC 3339.
42+
:param datetime_instance: Datetime instanec to format, defaults to utcnow
43+
"""
44+
return datetime_instance.isoformat("T") + "Z"
45+
46+
47+
def get_start_time():
48+
# Return now- 5 minutes
49+
start_time = datetime.datetime.utcnow() - datetime.timedelta(minutes=5)
50+
return format_rfc3339(start_time)
51+
52+
53+
def get_now_rfc3339():
54+
# Return now
55+
return format_rfc3339(datetime.datetime.utcnow())
56+
57+
58+
def create_custom_metric(client, project_id,
59+
custom_metric_name, metric_kind):
60+
"""Create custom metric descriptor"""
61+
metrics_descriptor = {
62+
"name": "projects/{}/metricDescriptors/{}".format(
63+
project_id, custom_metric_name),
64+
"type": custom_metric_name,
65+
"labels": [
66+
{
67+
"key": "environment",
68+
"valueType": "STRING",
69+
"description": "An abritrary measurement"
70+
}
71+
],
72+
"metricKind": metric_kind,
73+
"valueType": "INT64",
74+
"unit": "items",
75+
"description": "An arbitrary measurement.",
76+
"displayName": "Custom Metric"
77+
}
78+
79+
client.projects().metricDescriptors().create(
80+
name=project_id, body=metrics_descriptor).execute()
81+
82+
83+
def get_custom_metric(client, project_id, custom_metric_name):
84+
"""Retrieve the custom metric we created"""
85+
request = client.projects().metricDescriptors().list(
86+
name=project_id,
87+
filter='metric.type=starts_with("{}")'.format(custom_metric_name))
88+
response = request.execute()
89+
print('ListCustomMetrics response:')
90+
pprint.pprint(response)
91+
try:
92+
return response['metricDescriptors']
93+
except KeyError:
94+
return None
95+
96+
97+
def get_custom_data_point():
98+
"""Dummy method to return a mock measurement for demonstration purposes.
99+
Returns a random number between 0 and 10"""
100+
length = random.randint(0, 10)
101+
print("reporting timeseries value {}".format(str(length)))
102+
return length
103+
104+
105+
def write_timeseries_value(client, project_resource,
106+
custom_metric_name, instance_id, metric_kind):
107+
"""Write the custom metric obtained by get_custom_data_point at a point in
108+
time."""
109+
# Specify a new data point for the time series.
110+
now = get_now_rfc3339()
111+
timeseries_data = {
112+
"metric": {
113+
"type": custom_metric_name,
114+
"labels": {
115+
"environment": "STAGING"
116+
}
117+
},
118+
"resource": {
119+
"type": 'gce_instance',
120+
"labels": {
121+
'instance_id': instance_id,
122+
'zone': 'us-central1-f'
123+
}
124+
},
125+
"metricKind": metric_kind,
126+
"valueType": "INT64",
127+
"points": [
128+
{
129+
"interval": {
130+
"startTime": now,
131+
"endTime": now
132+
},
133+
"value": {
134+
"int64Value": get_custom_data_point()
135+
}
136+
}
137+
]
138+
}
139+
140+
request = client.projects().timeSeries().create(
141+
name=project_resource, body={"timeSeries": [timeseries_data]})
142+
request.execute()
143+
144+
145+
def read_timeseries(client, project_resource, custom_metric_name):
146+
"""Reads all of the CUSTOM_METRICS that we have written between START_TIME
147+
and END_TIME
148+
:param project_resource: Resource of the project to read the timeseries
149+
from.
150+
:param custom_metric_name: The name of the timeseries we want to read.
151+
"""
152+
request = client.projects().timeSeries().list(
153+
name=project_resource,
154+
filter='metric.type="{0}"'.format(custom_metric_name),
155+
pageSize=3,
156+
interval_startTime=get_start_time(),
157+
interval_endTime=get_now_rfc3339())
158+
response = request.execute()
159+
return response
160+
161+
162+
def main(project_id):
163+
# This is the namespace for all custom metrics
164+
CUSTOM_METRIC_DOMAIN = "custom.googleapis.com"
165+
# This is our specific metric name
166+
CUSTOM_METRIC_NAME = "{}/custom_measurement".format(CUSTOM_METRIC_DOMAIN)
167+
INSTANCE_ID = "test_instance"
168+
METRIC_KIND = "GAUGE"
169+
170+
project_resource = "projects/{0}".format(project_id)
171+
client = list_resources.get_client()
172+
create_custom_metric(client, project_resource,
173+
CUSTOM_METRIC_NAME, METRIC_KIND)
174+
custom_metric = None
175+
while not custom_metric:
176+
# wait until it's created
177+
time.sleep(1)
178+
custom_metric = get_custom_metric(
179+
client, project_resource, CUSTOM_METRIC_NAME)
180+
181+
write_timeseries_value(client, project_resource,
182+
CUSTOM_METRIC_NAME, INSTANCE_ID, METRIC_KIND)
183+
# Sometimes on new metric descriptors, writes have a delay in being read
184+
# back. 3 seconds should be enough to make sure our read call picks up the
185+
# write
186+
time.sleep(3)
187+
timeseries = read_timeseries(client, project_resource, CUSTOM_METRIC_NAME)
188+
print('read_timeseries response:\n{}'.format(pprint.pformat(timeseries)))
189+
190+
191+
if __name__ == '__main__':
192+
parser = argparse.ArgumentParser(
193+
description=__doc__,
194+
formatter_class=argparse.RawDescriptionHelpFormatter
195+
)
196+
parser.add_argument(
197+
'--project_id', help='Project ID you want to access.', required=True)
198+
199+
args = parser.parse_args()
200+
main(args.project_id)
201+
202+
# [END all]
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env python
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
""" Integration test for custom_metric.py
15+
16+
GOOGLE_APPLICATION_CREDENTIALS must be set to a Service Account for a project
17+
that has enabled the Monitoring API.
18+
19+
Currently the TEST_PROJECT_ID is hard-coded to run using the project created
20+
for this test, but it could be changed to a different project.
21+
"""
22+
23+
import random
24+
import time
25+
26+
from custom_metric import create_custom_metric, get_custom_metric
27+
from custom_metric import read_timeseries, write_timeseries_value
28+
import list_resources
29+
30+
""" Change this to run against other prjoects
31+
GOOGLE_APPLICATION_CREDENTIALS must be the service account for this project
32+
"""
33+
34+
# temporarily hard code to whitelisted project
35+
TEST_PROJECT_ID = 'cloud-monitoring-dev'
36+
# TEST_PROJECT_ID = os.getenv("GCLOUD_PROJECT", 'cloud-monitoring-dev')
37+
38+
""" Custom metric domain for all cusotm metrics"""
39+
CUSTOM_METRIC_DOMAIN = "custom.googleapis.com"
40+
41+
PROJECT_RESOURCE = "projects/{}".format(TEST_PROJECT_ID)
42+
43+
METRIC = 'compute.googleapis.com/instance/cpu/usage_time'
44+
METRIC_NAME = ''.join(
45+
random.choice('0123456789ABCDEF') for i in range(16))
46+
METRIC_RESOURCE = "{}/{}".format(
47+
CUSTOM_METRIC_DOMAIN, METRIC_NAME)
48+
49+
50+
def test_custom_metric():
51+
client = list_resources.get_client()
52+
# Use a constant seed so psuedo random number is known ahead of time
53+
random.seed(1)
54+
pseudo_random_value = random.randint(0, 10)
55+
# Reseed it
56+
random.seed(1)
57+
58+
INSTANCE_ID = "test_instance"
59+
METRIC_KIND = "GAUGE"
60+
61+
create_custom_metric(
62+
client, PROJECT_RESOURCE, METRIC_RESOURCE, METRIC_KIND)
63+
custom_metric = None
64+
# wait until metric has been created, use the get call to wait until
65+
# a response comes back with the new metric
66+
while not custom_metric:
67+
time.sleep(1)
68+
custom_metric = get_custom_metric(
69+
client, PROJECT_RESOURCE, METRIC_RESOURCE)
70+
71+
write_timeseries_value(client, PROJECT_RESOURCE,
72+
METRIC_RESOURCE, INSTANCE_ID,
73+
METRIC_KIND)
74+
# Sometimes on new metric descriptors, writes have a delay in being
75+
# read back. 3 seconds should be enough to make sure our read call
76+
# picks up the write
77+
time.sleep(3)
78+
response = read_timeseries(client, PROJECT_RESOURCE, METRIC_RESOURCE)
79+
value = int(
80+
response['timeSeries'][0]['points'][0]['value']['int64Value'])
81+
# using seed of 1 will create a value of 1
82+
assert value == pseudo_random_value

0 commit comments

Comments
 (0)