Stackdriver Monitoring And Ruby

This week I have been learning how to access Stackdriver Monitoring with the google-cloud-monitoring gem. While Stackdriver Monitoring is a fully released product, the Ruby client library for monitoring is still at alpha level quality. I cannot in good conscience recommend that you use an alpha quality library for something as critical as monitoring. However, I know that some of you will do it anyway, so here are some tips for getting started.

Installation and Authentication

You install the gem, unsurprisingly, with gem install google-cloud-monitoring. The monitoring gem depends on grpc which requires C extensions. There are some open issues with installing this gem on some versions of Linux and with JRuby.

For the examples below I am authenticating via the credentials I set up with the gcloud SDK. There are several other methods of authenticating. The official documentation on authentication is here. My blog post on authentication goes into more detail on the how and why of the different authentication methods.

There’s some boilerplate setup you will need to do at the beginning of any script where you use the monitoring library.

require "google/cloud/monitoring/v3/metric_service_client"

client  = Google::Cloud::Monitoring::V3::MetricServiceClient.new
project = Google::Cloud::Monitoring::V3::MetricServiceClient.project_path(PROJECT_ID)

The line that sets the project variable just ensures that the project is formatted in the way the monitoring API expects.

Reading Metrics

Stackdriver Monitoring calls metric data a Time Series. To read metric data via the Ruby gem, you use the MetricServiceClient#list_time_series method. This method has four required parameters: name, filter, interval, and view.

Name is the formatted project name that I show in the boilerplate above. The view specifies which data should be returned. There are two possible values: FULL and HEADERS. Since I want the actual data, I am using TimeSeriesView::FULL. The filter parameter allows you to control what data is returned. There are many supported filters including project, group, and resource type. For this post, I am going to look at the memory usage of the App Engine cluster running “Tind-Purr”. You can look up the possible metrics with metrics explorer. Using metric explorer, I figured out that the metric I want to see is “appengine/system/memory/usage”. When using this metric with the monitoring API, I need to specify the full name of the metric by adding .googleapis.com to it giving me “appengine.googleapis.com/system/memory/usage”.

The last parameter is the time interval. Specifying the interval is a bit of a challenge. You need to know the start and end time in seconds since the Unix epoch. In Ruby the fastest way to get this is calling to_i on a time object. The code below creates an end time that is the current timestamp and a start time that is 10 minutes before the end time.

1
2
end_time = Time.now.to_i
start_time = end_time - (60 * 10) # 10 minutes

Once I have the start and end time, I create a new TimeInterval object and then create a Google::Protobuf::Timestamp object for the start and end time.

1
2
3
interval = Google::Monitoring::V3::TimeInterval.new
interval.start_time = Google::Protobuf::Timestamp.new(seconds: start_time)
interval.end_time   = Google::Protobuf::Timestamp.new(seconds: end_time)

Putting it all together, I get this code to read a metric time series.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require "google/cloud/monitoring/v3/metric_service_client"

client  = Google::Cloud::Monitoring::V3::MetricServiceClient.new
project = Google::Cloud::Monitoring::V3::MetricServiceClient.project_path(PROJECT_ID)

metric = "appengine.googleapis.com/system/memory/usage"

end_time = Time.now.to_i
start_time = end_time - (60 * 10) # 10 minutes

filter = "metric.type = \"#{metric}\""
interval = Google::Monitoring::V3::TimeInterval.new
interval.start_time = Google::Protobuf::Timestamp.new(seconds: start_time)
interval.end_time = Google::Protobuf::Timestamp.new(seconds: end_time)
view = Google::Monitoring::V3::ListTimeSeriesRequest::TimeSeriesView::FULL

time_series = client.list_time_series(project, filter, interval, view)

This call returns a Google::Monitoring::V3::TimeSeries object. This object has some metadata and an array of points. Each point is an instance of Google::Monitoring::V3::Point which has time information and a value object. To extract the value you need to know the type and call the appropriate method. The following code creates an array of all the integer values for a time series.

1
points = time_series.first.points.map { |p| p.value.int64_value }

This is the code you need to read a metric from Stackdriver Monitoring. In a future blog post, I will show you how to write a custom metrics to Stackdriver Monitoring from Ruby.