Skip to content

Commit 8e457f4

Browse files
author
Bill Prin
committed
Add Custom Metric Examples
1 parent fdbe26d commit 8e457f4

5 files changed

+385
-1
lines changed

monitoring/api/auth.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

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

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

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2015 Google Inc. All rights reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
"""Creates, writes, and reads a labeled custom metric.
19+
20+
This is an example of how to use the Google Cloud Monitoring API to create,
21+
write, and read a labeled custom metric.
22+
The metric has two labels: color and size, and the data points represent
23+
the number of shirts of the given color and size in inventory.
24+
25+
Prerequisites: To run locally, download a Service Account JSON file from
26+
your project and point GOOGLE_APPLICATION_CREDENTIALS to the file.
27+
28+
From App Engine or a GCE instance with the correct scope, the Service
29+
Account step is not required.
30+
31+
Typical usage: Run the following shell commands on the instance:
32+
python labeled_custom_metric.py --project_id <project_id> /
33+
--color yellow --size large --count 10
34+
"""
35+
36+
import argparse
37+
import datetime
38+
import time
39+
40+
from googleapiclient import discovery
41+
from oauth2client.client import GoogleCredentials
42+
43+
CUSTOM_METRIC_DOMAIN = "custom.cloudmonitoring.googleapis.com"
44+
CUSTOM_METRIC_NAME = "{}/shirt_inventory".format(CUSTOM_METRIC_DOMAIN)
45+
46+
47+
def format_rfc3339(datetime_instance=None):
48+
"""Formats a datetime per RFC 3339.
49+
:param datetime_instance: Datetime instance to format, defaults to utcnow
50+
"""
51+
return datetime_instance.isoformat("T") + "Z"
52+
53+
54+
def get_now_rfc3339():
55+
return format_rfc3339(datetime.datetime.utcnow())
56+
57+
58+
def create_custom_metric(client, project_id):
59+
"""Create metric descriptor for the custom metric and send it to the
60+
API."""
61+
# You need to execute this operation only once. The operation is
62+
# idempotent, so, for simplicity, this sample code calls it each time
63+
64+
# Create a label descriptor for each of the metric labels. The
65+
# "description" field should be more meaningful for your metrics.
66+
label_descriptors = []
67+
for label in ["color", "size", ]:
68+
label_descriptors.append({"key": "/{}".format(label),
69+
"description": "The {}.".format(label)})
70+
71+
# Create the metric descriptor for the custom metric.
72+
metric_descriptor = {
73+
"name": CUSTOM_METRIC_NAME,
74+
"project": project_id,
75+
"typeDescriptor": {
76+
"metricType": "gauge",
77+
"valueType": "int64",
78+
},
79+
"labels": label_descriptors,
80+
"description": "The size of my shirt inventory.",
81+
}
82+
# Submit the custom metric creation request.
83+
try:
84+
request = client.metricDescriptors().create(
85+
project=project_id, body=metric_descriptor)
86+
request.execute() # ignore the response
87+
except Exception as e:
88+
print("Failed to create custom metric: exception={})".format(e))
89+
raise
90+
91+
92+
def write_custom_metric(client, project_id, now_rfc3339, color, size, count):
93+
"""Write a data point to a single time series of the custom metric."""
94+
# Identify the particular time series to which to write the data by
95+
# specifying the metric and values for each label.
96+
timeseries_descriptor = {
97+
"project": project_id,
98+
"metric": CUSTOM_METRIC_NAME,
99+
"labels": {
100+
"{}/color".format(CUSTOM_METRIC_DOMAIN): color,
101+
"{}/size".format(CUSTOM_METRIC_DOMAIN): size,
102+
}
103+
}
104+
105+
# Specify a new data point for the time series.
106+
timeseries_data = {
107+
"timeseriesDesc": timeseries_descriptor,
108+
"point": {
109+
"start": now_rfc3339,
110+
"end": now_rfc3339,
111+
"int64Value": count,
112+
}
113+
}
114+
115+
# Submit the write request.
116+
request = client.timeseries().write(
117+
project=project_id, body={"timeseries": [timeseries_data, ]})
118+
try:
119+
request.execute() # ignore the response
120+
except Exception as e:
121+
print("Failed to write data to custom metric: exception={}".format(e))
122+
raise
123+
124+
125+
def read_custom_metric(client, project_id, now_rfc3339, color, size):
126+
"""Read all the timeseries data points for a given set of label values."""
127+
# To identify a time series, specify values for in label as a list.
128+
labels = ["{}/color=={}".format(CUSTOM_METRIC_DOMAIN, color),
129+
"{}/size=={}".format(CUSTOM_METRIC_DOMAIN, size), ]
130+
131+
# Submit the read request.
132+
request = client.timeseries().list(
133+
project=project_id,
134+
metric=CUSTOM_METRIC_NAME,
135+
youngest=now_rfc3339,
136+
labels=labels)
137+
138+
# When a custom metric is created, it may take a few seconds
139+
# to propagate throughout the system. Retry a few times.
140+
start = time.time()
141+
while True:
142+
try:
143+
response = request.execute()
144+
for point in response["timeseries"][0]["points"]:
145+
print("{}: {}".format(point["end"], point["int64Value"]))
146+
break
147+
except Exception as e:
148+
if time.time() < start + 20:
149+
print("Failed to read custom metric data, retrying...")
150+
time.sleep(3)
151+
else:
152+
print("Failed to read custom metric data, aborting: "
153+
"exception={}".format(e))
154+
raise
155+
156+
157+
def get_client():
158+
"""Builds an http client authenticated with the application default
159+
credentials."""
160+
credentials = GoogleCredentials.get_application_default()
161+
client = discovery.build(
162+
'cloudmonitoring', 'v2beta2',
163+
credentials=credentials)
164+
return client
165+
166+
167+
def main(project_id, color, size, count):
168+
now_rfc3339 = get_now_rfc3339()
169+
170+
client = get_client()
171+
172+
print ("Labels: color: {}, size: {}.".format(color, size))
173+
print ("Creating custom metric...")
174+
create_custom_metric(client, project_id)
175+
time.sleep(2)
176+
print ("Writing new data to custom metric timeseries...")
177+
write_custom_metric(client, project_id, now_rfc3339,
178+
color, size, count)
179+
print ("Reading data from custom metric timeseries...")
180+
write_custom_metric(client, project_id, now_rfc3339, color,
181+
size, count)
182+
183+
184+
if __name__ == '__main__':
185+
parser = argparse.ArgumentParser(
186+
description=__doc__,
187+
formatter_class=argparse.RawDescriptionHelpFormatter,
188+
)
189+
190+
parser.add_argument(
191+
'--project_id', help='Project ID you want to access.', required=True)
192+
parser.add_argument("--color", required=True)
193+
parser.add_argument("--size", required=True)
194+
parser.add_argument("--count", required=True)
195+
196+
args = parser.parse_args()
197+
main(args.project_id, args.color, args.size, args.count)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2015 Google Inc. All rights reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import re
18+
19+
import labeled_custom_metric
20+
21+
22+
def test_main(cloud_config, capsys):
23+
labeled_custom_metric.main(cloud_config.project, "yellow", "large", "10")
24+
output, _ = capsys.readouterr()
25+
26+
assert re.search(
27+
re.compile(
28+
r'.*Creating.*'
29+
r'Writing.*'
30+
r'Reading.*', flags=re.DOTALL),
31+
output)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2015 Google Inc. All rights reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
"""Writes and reads a lightweight custom metric.
19+
20+
This is an example of how to use the Google Cloud Monitoring API to write
21+
and read a lightweight custom metric. Lightweight custom metrics have no
22+
labels and you do not need to create a metric descriptor for them.
23+
24+
Prerequisites: To run locally, download a Service Account JSON file from
25+
your project and point GOOGLE_APPLICATION_CREDENTIALS to the file.
26+
27+
From App Engine or a GCE instance with the correct scope, the Service
28+
Account step is not required.
29+
30+
Typical usage: Run the following shell commands on the instance:
31+
32+
python lightweight_custom_metric.py --project_id=<YOUR-PROJECT-ID>
33+
"""
34+
35+
import argparse
36+
import datetime
37+
import os
38+
import time
39+
40+
from googleapiclient import discovery
41+
from oauth2client.client import GoogleCredentials
42+
43+
CUSTOM_METRIC_NAME = "custom.cloudmonitoring.googleapis.com/pid"
44+
45+
46+
def format_rfc3339(datetime_instance=None):
47+
"""Formats a datetime per RFC 3339.
48+
:param datetime_instance: Datetime instanec to format, defaults to utcnow
49+
"""
50+
return datetime_instance.isoformat("T") + "Z"
51+
52+
53+
def get_now_rfc3339():
54+
return format_rfc3339(datetime.datetime.utcnow())
55+
56+
57+
def get_client():
58+
"""Builds an http client authenticated with the service account
59+
credentials."""
60+
credentials = GoogleCredentials.get_application_default()
61+
client = discovery.build(
62+
'cloudmonitoring', 'v2beta2',
63+
credentials=credentials)
64+
return client
65+
66+
67+
def main(project_id):
68+
# Set up the write request.
69+
client = get_client()
70+
now = get_now_rfc3339()
71+
desc = {"project": project_id,
72+
"metric": CUSTOM_METRIC_NAME}
73+
point = {"start": now,
74+
"end": now,
75+
"doubleValue": os.getpid()}
76+
print("Writing {} at {}".format(point["doubleValue"], now))
77+
78+
# Write a new data point.
79+
try:
80+
write_request = client.timeseries().write(
81+
project=project_id,
82+
body={"timeseries": [{"timeseriesDesc": desc, "point": point}]})
83+
write_request.execute() # Ignore the response.
84+
except Exception as e:
85+
print("Failed to write custom metric data: exception={}".format(e))
86+
raise
87+
88+
# Read all data points from the time series.
89+
# When a custom metric is created, it may take a few seconds
90+
# to propagate throughout the system. Retry a few times.
91+
print("Reading data from custom metric timeseries...")
92+
read_request = client.timeseries().list(
93+
project=project_id,
94+
metric=CUSTOM_METRIC_NAME,
95+
youngest=now)
96+
start = time.time()
97+
while True:
98+
try:
99+
read_response = read_request.execute()
100+
for point in read_response["timeseries"][0]["points"]:
101+
print("Point: {}: {}".format(
102+
point["end"], point["doubleValue"]))
103+
break
104+
except Exception as e:
105+
if time.time() < start + 20:
106+
print("Failed to read custom metric data, retrying...")
107+
time.sleep(3)
108+
else:
109+
print("Failed to read custom metric data, aborting: "
110+
"exception={}".format(e))
111+
raise
112+
113+
114+
if __name__ == '__main__':
115+
parser = argparse.ArgumentParser(
116+
description=__doc__,
117+
formatter_class=argparse.RawDescriptionHelpFormatter
118+
)
119+
120+
parser.add_argument(
121+
'--project_id', help='Project ID you want to access.', required=True)
122+
123+
args = parser.parse_args()
124+
main(args.project_id)

0 commit comments

Comments
 (0)