Skip to content

Monitoring: Write Timeseries Values Usage Plan #1867

@waprin

Description

@waprin

Currently the Monitoring client does not support writing timeseries values, though that's probably the canonical use case of the API.

@rimey is planning on adding it, I was hoping to add some samples sooner so he said I could start to spec it out, and whoever gets to it first will do the PR, but either way we should come to some consensus on the usage patterns first.

I know he was also concerned about #1732 since datetimes are pretty important in monitoring, but I'm not sure yet what's actionable. We should definitely minimize needs for user to play with timestamps.

Anyway high level overview of Monitoring API from my understanding

MetricDescriptor - This object describes a type of Metric, can be parametrized with LabelDescriptors
MonitoredResourceDescriptor - This object describes a type of thing to be monitored, can be parametrized with LabelDescriptors

Metric - A MetricDescriptor parametrized with labels
Resource - A ResourceDescriptor paramettrized with labels

TimeSeries - Metric + Resource + points. The points have intervals, although for GAUGE metrics (one of the MetricKind) that interval will have the same start and end time and usually be the current time. CUMULATIVE metrics will have a separate start and end time, with the end time usually being the current time. DELTA metrics can not be used for custom metrics, so I think can be ignored for the purpose of writing timeseries, because I think you only ever write custom metrics (non-custom metrics are the default ones written for you).

See the current usage docs for more context.

I think the most common use case will be to write a custom GAUGE metric for the current time.

from gcloud import monitoring
client = monitoring.Client() 

# Create a Metric by its MetricDescriptor type name, assign labels as a dict
# Possibly doesn't exist but we won't check yet, unless they reload()
gauge_metric = client.metric('custom.googleapis.com/my_metric', labels={'response_code': 404})

# Create a Resource by its resource name, assign labels as dict
resource = client.resource('gce_instance', labels={'instance_id': 'my-instance', 'zone': 'us-central1-f'})

# Create and save the timeseries resource
client.write_timeseries(metric=metric, resource=resource, points=[1,2,3]) # API call

# GAUGE metrics should only specify end_time if now is not correct, start_time will default to end_time
client.write_timeseries(metric=metric, resource=resource, points=[4,5], end_time=get_a_time())

cumulative_metric = client.metric('custom.googleapis.com/my_cumulative_metric')

# end time always defaults to now
cilent.write_timeseries(metric=cumulative_metric, resource=resource, points=[7, 8, 9], start_time=get_start_time()) # API call

I was originally thinking something like

# Abandoned pattern
# Add 3 time series points, all default to interval of start/end at now
timeseries = monitoring.TimeSeries(metric=metric, resource=resource)
timeseries.add_points([1, 2, 3])
# Write the 3 time series values
timeseries.save() # API call

The disadvantage is that when you want to add more points to the same Metric+Resource, you either have to create a new TimeSeries object anyway, or have strange semantics where you add points to an object you already created, even though really a new object is being created. So I think it's better if TimeSeries are immutable client-side and you just create them directly with the call on the client.

Another small point is the start_time and end_time defaults. The idea is that end_time always defaults to now, unless specified, and start_time always defaults to end_time, unless specified. This makes sense, though it might look slightly strange that sometimes we are only explicitly setting start_time (to indicate when a CUMULATIV metric starts) and other times only explicitly setting end_time (to change the entire interval for a GAUGE metric). I think it's ok though.

One of the big questions is how much client-side validation do we want to do. For example given a GAUGE metric descriptor, we know that startTime needs to equal endTime. However if we want to enforce this client-side, we have to pull down the metric descriptor first, introducing an extra API call. So it's probably best to just leave most of the validation server side.

Do we need an actual Label class or are dicts good enough? I think dicts are good enough.

cc / @sharbison3

Metadata

Metadata

Labels

api: monitoringIssues related to the Cloud Monitoring API.priority: p2Moderately-important priority. Fix may not be included in next release.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions