Reading Metric Data

This page explains how to read metric data, also called time-series data, using the timeSeries.list method in the Monitoring API. There are several ways to use this method:

  • To run the list method without writing any code, the examples in the PROTOCOL tabs on this page use the forms-based API Explorer. (See API Explorer for more information on this tool.)

  • To learn how to use the list method from selected programming languages, see the runnable code samples on this page.

  • To browse your time series data and see it charted for you, see Resources > Metrics Explorer in the Stackdriver Monitoring section of the Google Cloud Platform Console. Metrics Explorer calls the API methods for you.

    Go to the Metrics Explorer page

For an introduction to metrics and time series, see Metrics, Time Series, and Resources.

Overview

Each call of the timeSeries.list method can return any number of time series from a single metric type. For example, if you are using Google Compute Engine, then the compute.googleapis.com/instance/cpu/usage_time metric type has a separate time series for each of your VM instances.

You specify which time series data you want by supplying the following:

  • A filter expression that specifies the metric type. Optionally, the filter selects a subset of the metric's time series by specifying the resources producing the time series or specifying values for certain labels in the time series.
  • A time interval that limits how much data is returned.
  • Optionally, a specification of how to combine multiple time series to produce an aggregate summary of the data. For more information, see Aggregating data for some examples.

Time series filters

You specify which time series to retrieve by passing a time series filter to the list method. Following are the commonly-provided filter components:

  • The filter must specify a single metric type. For example:

    metric.type = "compute.googleapis.com/instance/cpu/usage_time"
    

    To retrieve custom metrics, change the metric.type prefix in the filter to custom.googleapis.com or another prefix if used; external.googleapis.com is frequently used.

  • The filter can specify values for the metric's dimension labels. The metric type determines which labels are present. For example:

    (metric.label.instance_name = "your-instance-id" OR
      metric.label.instance_name = "your-other-instance-id")
    

    Note that label is correct, although the actual metric object uses labels as its key.

  • The filter can limit the time series to those that contain a specific monitored resource type:

    resource.type = "gae_app"
    

The filter components can be combined into a single time series filter, such as the following:

metric.type = "compute.googleapis.com/instance/cpu/usage_time"
AND (metric.label.instance_name = "your-instance-id" OR
  metric.label.instance_name = "your-other-instance-id")

If you do not specify values for all the metric labels, then the list method returns a time series for each combination of values in the unspecified label(s). The method returns only time series that have data.

Time intervals

You must specify interval.startTime and interval.endTime when calling the timeSeries.list method. The resulting time period includes the end time but not the start time, unless they are both the same time. This can be confusing. For example, consider these examples of (start, end] intervals:

(T, T+1]
This interval does not contain T.
(T-1, T]
This interval does contain T.
(T, T]
As a special and unusual case, this interval includes only the time T. If you omit the start time, this is the interval you get.

Values in time intervals

Start and end times must be specified as strings in RFC 3339 format. For example:

2018-05-11T12:34:56+04:00
2018-05-11T12:34:56.992Z

The date -Iseconds command on Linux is useful for generating timestamps.

Ranges in time intervals

A time interval is specified by a start and end time, but the start time is not required by the API. If a start time is not specified, it defaults to the end time. This makes semantic sense only for GAUGE metrics, which measure points in time.

If your metric is CUMULATIVE or DELTA, then it measures an accumulation or change over time. For “over time” metrics, the start and end times of the interval must both be supplied, and the start time must be less than the end time.

See Kinds of metrics for more information.

Basic list operations

The timeSeries.list method can be used to return simple, raw data, or it can be used to return highly processed data. This section illustrates some basic uses.

Example: Listing available time series

This example shows how to list only the names and descriptions of the time series that match a filter, rather than returning all the available data:

Protocol

Here are the sample parameters to timeSeries.list:

  • name: projects/[PROJECT_ID]
  • filter: metric.type = "compute.googleapis.com/instance/cpu/utilization"
  • interval.start_time: 2018-05-11T00:00:00Z
  • interval.end_time: 2018-05-11T00:20:00Z
  • fields: timeSeries.metric

Try It!

Before clicking the Execute button, change [PROJECT_ID] to your ID of your project.

The sample output shows time series for two different VM instances:

{
  "timeSeries": [
    {
      "metric": {
        "labels": {
          "instance_name": "your-first-instance"
        },
        "type": "compute.googleapis.com/instance/cpu/utilization"
      },
    },
    {
      "metric": {
        "labels": {
          "instance_name": "your-second-instance"
        },
        "type": "compute.googleapis.com/instance/cpu/utilization"
      },
    }
  ]
}

C#

public static object ReadTimeSeriesFields(string projectId,
    string metricType = "compute.googleapis.com/instance/cpu/utilization")
{
    Console.WriteLine($"metricType{ metricType}");
    // Create client.
    MetricServiceClient metricServiceClient = MetricServiceClient.Create();
    // Initialize request argument(s).
    string filter = $"metric.type=\"{metricType}\"";
    ListTimeSeriesRequest request = new ListTimeSeriesRequest
    {
        ProjectName = new ProjectName(projectId),
        Filter = filter,
        Interval = new TimeInterval(),
        View = ListTimeSeriesRequest.Types.TimeSeriesView.Headers,
    };
    // Create timestamp for current time formatted in seconds.
    long timeStamp = (long)(DateTime.UtcNow - s_unixEpoch).TotalSeconds;
    Timestamp startTimeStamp = new Timestamp();
    // Set startTime to limit results to the last 20 minutes.
    startTimeStamp.Seconds = timeStamp - (60 * 20);
    Timestamp endTimeStamp = new Timestamp();
    // Set endTime to current time.
    endTimeStamp.Seconds = timeStamp;
    TimeInterval interval = new TimeInterval();
    interval.StartTime = startTimeStamp;
    interval.EndTime = endTimeStamp;
    request.Interval = interval;
    // Make the request.
    PagedEnumerable<ListTimeSeriesResponse, TimeSeries> response =
        metricServiceClient.ListTimeSeries(request);
    // Iterate over all response items, lazily performing RPCs as required.
    Console.Write("Found data points for the following instances:");
    foreach (var item in response)
    {
        Console.WriteLine(JObject.Parse($"{item}").ToString());
    }
    return 0;
}

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	monitoring "cloud.google.com/go/monitoring/apiv3"
	"github.com/golang/protobuf/ptypes/timestamp"
	"google.golang.org/api/iterator"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)

// readTimeSeriesFields reads the last 20 minutes of the given metric, aligns
// everything on 10 minute intervals, and combines values from different
// instances.
func readTimeSeriesFields(w io.Writer, projectID string) error {
	ctx := context.Background()
	client, err := monitoring.NewMetricClient(ctx)
	if err != nil {
		return fmt.Errorf("NewMetricClient: %v", err)
	}
	startTime := time.Now().UTC().Add(time.Minute * -20)
	endTime := time.Now().UTC()
	req := &monitoringpb.ListTimeSeriesRequest{
		Name:   "projects/" + projectID,
		Filter: `metric.type="compute.googleapis.com/instance/cpu/utilization"`,
		Interval: &monitoringpb.TimeInterval{
			StartTime: &timestamp.Timestamp{
				Seconds: startTime.Unix(),
			},
			EndTime: &timestamp.Timestamp{
				Seconds: endTime.Unix(),
			},
		},
		View: monitoringpb.ListTimeSeriesRequest_HEADERS,
	}
	fmt.Fprintln(w, "Found data points for the following instances:")
	it := client.ListTimeSeries(ctx, req)
	for {
		resp, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("could not read time series value: %v", err)
		}
		fmt.Fprintf(w, "\t%v\n", resp.GetMetric().GetLabels()["instance_name"])
	}
	fmt.Fprintln(w, "Done")
	return nil
}

Java

MetricServiceClient metricServiceClient = MetricServiceClient.create();
String projectId = System.getProperty("projectId");
ProjectName name = ProjectName.of(projectId);

// Restrict time to last 20 minutes
long startMillis = System.currentTimeMillis() - ((60 * 20) * 1000);
TimeInterval interval = TimeInterval.newBuilder()
    .setStartTime(Timestamps.fromMillis(startMillis))
    .setEndTime(Timestamps.fromMillis(System.currentTimeMillis()))
    .build();

ListTimeSeriesRequest.Builder requestBuilder = ListTimeSeriesRequest.newBuilder()
    .setName(name.toString())
    .setFilter("metric.type=\"compute.googleapis.com/instance/cpu/utilization\"")
    .setInterval(interval)
    .setView(ListTimeSeriesRequest.TimeSeriesView.HEADERS);

ListTimeSeriesRequest request = requestBuilder.build();

ListTimeSeriesPagedResponse response = metricServiceClient.listTimeSeries(request);

System.out.println("Got timeseries headers: ");
for (TimeSeries ts : response.iterateAll()) {
  System.out.println(ts);
}

Node.js

// Imports the Google Cloud client library
const monitoring = require('@google-cloud/monitoring');

// Creates a client
const client = new monitoring.MetricServiceClient();

/**
 * TODO(developer): Uncomment and edit the following lines of code.
 */
// const projectId = 'YOUR_PROJECT_ID';

const request = {
  name: client.projectPath(projectId),
  filter: 'metric.type="compute.googleapis.com/instance/cpu/utilization"',
  interval: {
    startTime: {
      // Limit results to the last 20 minutes
      seconds: Date.now() / 1000 - 60 * 20,
    },
    endTime: {
      seconds: Date.now() / 1000,
    },
  },
  // Don't return time series data, instead just return information about
  // the metrics that match the filter
  view: 'HEADERS',
};

// Writes time series data
client
  .listTimeSeries(request)
  .then(results => {
    const timeSeries = results[0];

    console.log('Found data points for the following instances:');
    timeSeries.forEach(data => {
      console.log(data.metric.labels.instance_name);
    });
  })
  .catch(err => {
    console.error('ERROR:', err);
  });

PHP

use Google\Cloud\Monitoring\V3\MetricServiceClient;
use Google\Cloud\Monitoring\V3\TimeInterval;
use Google\Cloud\Monitoring\V3\ListTimeSeriesRequest_TimeSeriesView;
use Google\Protobuf\Timestamp;

/**
 * Example:
 * ```
 * read_timeseries_fields($projectId);
 * ```
 *
 * @param string $projectId Your project ID
 */
function read_timeseries_fields($projectId, $minutesAgo = 20)
{
    $metrics = new MetricServiceClient([
        'projectId' => $projectId,
    ]);

    $projectName = $metrics->projectName($projectId);
    $filter = 'metric.type="compute.googleapis.com/instance/cpu/utilization"';

    $startTime = new Timestamp();
    $startTime->setSeconds(time() - (60 * $minutesAgo));
    $endTime = new Timestamp();
    $endTime->setSeconds(time());

    $interval = new TimeInterval();
    $interval->setStartTime($startTime);
    $interval->setEndTime($endTime);

    $view = ListTimeSeriesRequest_TimeSeriesView::HEADERS;

    $result = $metrics->listTimeSeries(
        $projectName,
        $filter,
        $interval,
        $view);

    printf('Found data points for the following instances:' . PHP_EOL);
    foreach ($result->iterateAllElements() as $timeSeries) {
        printf($timeSeries->getMetric()->getLabels()['instance_name'] . PHP_EOL);
    }
}

Python

client = monitoring_v3.MetricServiceClient()
project_name = client.project_path(project_id)
interval = monitoring_v3.types.TimeInterval()
now = time.time()
interval.end_time.seconds = int(now)
interval.end_time.nanos = int(
    (now - interval.end_time.seconds) * 10**9)
interval.start_time.seconds = int(now - 300)
interval.start_time.nanos = interval.end_time.nanos
results = client.list_time_series(
    project_name,
    'metric.type = "compute.googleapis.com/instance/cpu/utilization"',
    interval,
    monitoring_v3.enums.ListTimeSeriesRequest.TimeSeriesView.HEADERS)
for result in results:
    print(result)

See Troubleshooting API calls if you have difficulty.

Example: Getting time series data

This example returns all the information available to the timeSeries.list request, including the metric data, from Compute Engine instances for the last 20 minutes.

Protocol

The protocol example further limits the output, to make the returned data more manageable in the response box. This example uses different field values:

  • The filter value now limits the time series to a single VM instance.
  • The fields value now specifies only the time and value of the measurements.

These limit the amount of time series data returned in the result.

Here are the sample parameters to timeSeries.list:

  • name: projects/[PROJECT_ID]
  • filter: metric.type = "compute.googleapis.com/instance/cpu/utilization" AND metric.label.instance_name = "[YOUR_INSTANCE_NAME]"
  • interval.start_time: 2018-05-11T00:00:00Z
  • interval.end_time: 2018-05-11T00:20:00Z
  • fields: timeSeries.points.interval.endTime,timeSeries.points.value

Try It!

Before clicking the Execute button, change [PROJECT_ID] and [YOUR_INSTANCE_NAME] to values in your project, and set the end time to something recent and the start time to 20 minutes earlier.

The request returns a result like the following:

{
 "timeSeries": [
  {
   "points": [
    {
     "interval": {
      "endTime": "2018-05-T00:19:01Z"
     },
     "value": {
      "doubleValue": 0.06763074536575005
     }
    },
    {
     "interval": {
      "endTime": "2018-05-11T00:18:01Z"
     },
     "value": {
      "doubleValue": 0.06886174467702706
     }
    },
    ...
    {
     "interval": {
      "endTime": "2018-05-11T00:17:01Z"
     },
     "value": {
      "doubleValue": 0.06929610064253211
     }
    }
   ]
  }
 ]
}

C#

public static object ReadTimeSeriesData(string projectId,
    string metricType = "compute.googleapis.com/instance/cpu/utilization")
{
    // Create client.
    MetricServiceClient metricServiceClient = MetricServiceClient.Create();
    // Initialize request argument(s).
    string filter = $"metric.type=\"{metricType}\"";
    ListTimeSeriesRequest request = new ListTimeSeriesRequest
    {
        ProjectName = new ProjectName(projectId),
        Filter = filter,
        Interval = new TimeInterval(),
        View = ListTimeSeriesRequest.Types.TimeSeriesView.Full,
    };
    // Create timestamp for current time formatted in seconds.
    long timeStamp = (long)(DateTime.UtcNow - s_unixEpoch).TotalSeconds;
    Timestamp startTimeStamp = new Timestamp();
    // Set startTime to limit results to the last 20 minutes.
    startTimeStamp.Seconds = timeStamp - (60 * 20);
    Timestamp endTimeStamp = new Timestamp();
    // Set endTime to current time.
    endTimeStamp.Seconds = timeStamp;
    TimeInterval interval = new TimeInterval();
    interval.StartTime = startTimeStamp;
    interval.EndTime = endTimeStamp;
    request.Interval = interval;
    // Make the request.
    PagedEnumerable<ListTimeSeriesResponse, TimeSeries> response =
        metricServiceClient.ListTimeSeries(request);
    // Iterate over all response items, lazily performing RPCs as required.
    foreach (TimeSeries item in response)
    {
        Console.WriteLine(JObject.Parse($"{item}").ToString());
    }
    return 0;
}

Go

// readTimeSeriesValue reads the TimeSeries for the value specified by metric type in a time window from the last 5 minutes.
func readTimeSeriesValue(projectID, metricType string) error {
	ctx := context.Background()
	c, err := monitoring.NewMetricClient(ctx)
	if err != nil {
		return err
	}
	startTime := time.Now().UTC().Add(time.Minute * -5).Unix()
	endTime := time.Now().UTC().Unix()

	req := &monitoringpb.ListTimeSeriesRequest{
		Name:   projectResource(projectID),
		Filter: fmt.Sprintf("metric.type=\"%s\"", metricType),
		Interval: &monitoringpb.TimeInterval{
			StartTime: &timestamp.Timestamp{Seconds: startTime},
			EndTime:   &timestamp.Timestamp{Seconds: endTime},
		},
	}
	iter := c.ListTimeSeries(ctx, req)

	var series []*monitoringpb.TimeSeries
	for {
		resp, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("could not read time series value, %v ", err)
		}
		series = append(series, resp)
	}

	log.Printf("readTimeseriesValue: %s\n", formatResource(series))
	return nil
}

Java

MetricServiceClient metricServiceClient = MetricServiceClient.create();
String projectId = System.getProperty("projectId");
ProjectName name = ProjectName.of(projectId);

// Restrict time to last 20 minutes
long startMillis = System.currentTimeMillis() - ((60 * 20) * 1000);
TimeInterval interval = TimeInterval.newBuilder()
    .setStartTime(Timestamps.fromMillis(startMillis))
    .setEndTime(Timestamps.fromMillis(System.currentTimeMillis()))
    .build();

ListTimeSeriesRequest.Builder requestBuilder = ListTimeSeriesRequest.newBuilder()
    .setName(name.toString())
    .setFilter(filter)
    .setInterval(interval);

ListTimeSeriesRequest request = requestBuilder.build();

ListTimeSeriesPagedResponse response = metricServiceClient.listTimeSeries(request);

System.out.println("Got timeseries: ");
for (TimeSeries ts : response.iterateAll()) {
  System.out.println(ts);
}

Node.js

// Imports the Google Cloud client library
const monitoring = require('@google-cloud/monitoring');

// Creates a client
const client = new monitoring.MetricServiceClient();

/**
 * TODO(developer): Uncomment and edit the following lines of code.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const filter = 'metric.type="compute.googleapis.com/instance/cpu/utilization"';

const request = {
  name: client.projectPath(projectId),
  filter: filter,
  interval: {
    startTime: {
      // Limit results to the last 20 minutes
      seconds: Date.now() / 1000 - 60 * 20,
    },
    endTime: {
      seconds: Date.now() / 1000,
    },
  },
};

// Writes time series data
client
  .listTimeSeries(request)
  .then(results => {
    const timeSeries = results[0];

    timeSeries.forEach(data => {
      console.log(`${data.metric.labels.instance_name}:`);
      data.points.forEach(point => {
        console.log(JSON.stringify(point.value));
      });
    });
  })
  .catch(err => {
    console.error('ERROR:', err);
  });

PHP

use Google\Cloud\Monitoring\V3\MetricServiceClient;
use Google\Cloud\Monitoring\V3\TimeInterval;
use Google\Cloud\Monitoring\V3\ListTimeSeriesRequest_TimeSeriesView;
use Google\Protobuf\Timestamp;

/**
 * Example:
 * ```
 * read_timeseries_simple($projectId);
 * ```
 *
 * @param string $projectId Your project ID
 */
function read_timeseries_simple($projectId, $minutesAgo = 20)
{
    $metrics = new MetricServiceClient([
        'projectId' => $projectId,
    ]);

    $projectName = $metrics->projectName($projectId);
    $filter = 'metric.type="compute.googleapis.com/instance/cpu/utilization"';

    // Limit results to the last 20 minutes
    $startTime = new Timestamp();
    $startTime->setSeconds(time() - (60 * $minutesAgo));
    $endTime = new Timestamp();
    $endTime->setSeconds(time());

    $interval = new TimeInterval();
    $interval->setStartTime($startTime);
    $interval->setEndTime($endTime);

    $view = ListTimeSeriesRequest_TimeSeriesView::FULL;

    $result = $metrics->listTimeSeries(
        $projectName,
        $filter,
        $interval,
        $view);

    printf('CPU utilization:' . PHP_EOL);
    foreach ($result->iterateAllElements() as $timeSeries) {
        $instanceName = $timeSeries->getMetric()->getLabels()['instance_name'];
        printf($instanceName . ':' . PHP_EOL);
        foreach ($timeSeries->getPoints() as $point) {
            printf('  ' . $point->getValue()->getDoubleValue() . PHP_EOL);
        }
    }
}

Python

client = monitoring_v3.MetricServiceClient()
project_name = client.project_path(project_id)
interval = monitoring_v3.types.TimeInterval()
now = time.time()
interval.end_time.seconds = int(now)
interval.end_time.nanos = int(
    (now - interval.end_time.seconds) * 10**9)
interval.start_time.seconds = int(now - 300)
interval.start_time.nanos = interval.end_time.nanos
results = client.list_time_series(
    project_name,
    'metric.type = "compute.googleapis.com/instance/cpu/utilization"',
    interval,
    monitoring_v3.enums.ListTimeSeriesRequest.TimeSeriesView.FULL)
for result in results:
    print(result)

The returned data includes 20 data points in each time series over the 20-minute period, because Compute Engine metrics are collected every minute. For more information, see Latency of metric data. The API returns the data points in each time series in reverse time order; there is no override for this point ordering.

See Troubleshooting API calls if you have difficulty.

Aggregating data

The timeSeries.list method can perform statistical aggregations and reductions on the returned time series data. The following sections demonstrate two examples; see the method's documentation for more options.

Example: Aligning time series

This example reduces the 20 individual utilization measurements in each time series to just two measurements: the mean utilization for the two 10-minute periods within the 20-minute interval. The data from each time series is first aligned into 10-minute (600-second) periods, and then the values in each 10-minute period are averaged.

This example turns the twenty measurements per time series into two per time series. This operation has two advantages: it smooths out the data, and it aligns the data from all of the time series on exact 10-minute boundaries. The data can then be processed further.

Protocol

Here are the sample parameters to timeSeries.list:

  • name: projects/[PROJECT_ID]
  • aggregation.alignmentPeriod: 600s
  • aggregation.perSeriesAligner: ALIGN_MEAN
  • filter: metric.type = "compute.googleapis.com/instance/cpu/utilization"
  • interval.start_time: 2018-05-11T00:00:00Z
  • interval.end_time: 2018-05-11T00:20:00Z
  • fields: timeSeries.metric,timeSeries.points

The filter for a single instance shown in the previous example is removed: this query returns much less data, so there is less need to restrict it to one VM instance.

Try It!

Before clicking the Execute button, change [PROJECT_ID] to the ID for your project, and adjust the end time to something recent and the start time to 20 minutes earlier.

The following sample result has a time series for each of three VM instances. Each time series has two data points, the mean utilization for the 10-minute alignment periods:

{
 "timeSeries": [
  {
   "metric": {
    "labels": {"instance_name": "your-first-instance"},
    "type": "compute.googleapis.com/instance/cpu/utilization"
   },
   "points": [
    {
     "interval": {
      "startTime": "2018-05-04T14:00:00.000Z",
      "endTime": "2018-05-04T14:00:00.000Z"
     },
     "value": { "doubleValue": 0.06688481346044381 }
    },
    {
     "interval": {
      "startTime": "2018-05-04T13:50:00.000Z",
      "endTime": "2018-05-04T13:50:00.000Z"
     },
     "value": {"doubleValue": 0.06786652821310177 }
    }
   ]
  },
  {
   "metric": {
    "labels": { "instance_name": "your-second-instance" },
    "type": "compute.googleapis.com/instance/cpu/utilization"
   },
   "points": [
    {
     "interval": {
      "startTime": "2018-05-04T14:00:00.000Z",
      "endTime": "2018-05-04T14:00:00.000Z"
     },
     "value": { "doubleValue": 0.04144239874207415 }
    },
    {
     "interval": {
      "startTime": "2018-05-04T13:50:00.000Z",
      "endTime": "2018-05-04T13:50:00.000Z"
     },
     "value": { "doubleValue": 0.04045793689050091 }
    }
   ]
  },
  {
   "metric": {
    "labels": { "instance_name": "your-third-instance" },
    "type": "compute.googleapis.com/instance/cpu/utilization"
   },
   "points": [
    {
     "interval": {
      "startTime": "2018-05-04T14:00:00.000Z",
      "endTime": "2018-05-04T14:00:00.000Z"
     },
     "value": { "doubleValue": 0.029650046587339607 }
    },
    {
     "interval": {
      "startTime": "2018-05-04T13:50:00.000Z",
      "endTime": "2018-05-04T13:50:00.000Z"
     },
     "value": { "doubleValue": 0.03053874224715402 }
    }
   ]
  }
 ]
}

C#

public static object ReadTimeSeriesAggregate(string projectId,
    string metricType = "compute.googleapis.com/instance/cpu/utilization")
{
    // Create client.
    MetricServiceClient metricServiceClient = MetricServiceClient.Create();
    // Initialize request argument(s).
    string filter = $"metric.type=\"{metricType}\"";
    ListTimeSeriesRequest request = new ListTimeSeriesRequest
    {
        ProjectName = new ProjectName(projectId),
        Filter = filter,
        Interval = new TimeInterval(),
    };
    // Create timestamp for current time formatted in seconds.
    long timeStamp = (long)(DateTime.UtcNow - s_unixEpoch).TotalSeconds;
    Timestamp startTimeStamp = new Timestamp();
    // Set startTime to limit results to the last 20 minutes.
    startTimeStamp.Seconds = timeStamp - (60 * 20);
    Timestamp endTimeStamp = new Timestamp();
    // Set endTime to current time.
    endTimeStamp.Seconds = timeStamp;
    TimeInterval interval = new TimeInterval();
    interval.StartTime = startTimeStamp;
    interval.EndTime = endTimeStamp;
    request.Interval = interval;
    // Aggregate results per matching instance
    Aggregation aggregation = new Aggregation();
    Duration alignmentPeriod = new Duration();
    alignmentPeriod.Seconds = 600;
    aggregation.AlignmentPeriod = alignmentPeriod;
    aggregation.PerSeriesAligner = Aggregation.Types.Aligner.AlignMean;
    // Add the aggregation to the request.
    request.Aggregation = aggregation;
    // Make the request.
    PagedEnumerable<ListTimeSeriesResponse, TimeSeries> response =
        metricServiceClient.ListTimeSeries(request);
    // Iterate over all response items, lazily performing RPCs as required.
    Console.WriteLine($"{projectId} CPU utilization:");
    foreach (var item in response)
    {
        var points = item.Points;
        var labels = item.Metric.Labels;
        Console.WriteLine($"{labels.Values.FirstOrDefault()}");
        if (points.Count > 0)
        {
            Console.WriteLine($"  Now: {points[0].Value.DoubleValue}");
        }
        if (points.Count > 1)
        {
            Console.WriteLine($"  10 min ago: {points[1].Value.DoubleValue}");
        }
    }
    return 0;
}

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	monitoring "cloud.google.com/go/monitoring/apiv3"
	"github.com/golang/protobuf/ptypes/duration"
	"github.com/golang/protobuf/ptypes/timestamp"
	"google.golang.org/api/iterator"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)

// readTimeSeriesAlign reads the last 20 minutes of the given metric and aligns
// everything on 10 minute intervals.
func readTimeSeriesAlign(w io.Writer, projectID string) error {
	ctx := context.Background()
	client, err := monitoring.NewMetricClient(ctx)
	if err != nil {
		return fmt.Errorf("NewMetricClient: %v", err)
	}
	startTime := time.Now().UTC().Add(time.Minute * -20)
	endTime := time.Now().UTC()
	req := &monitoringpb.ListTimeSeriesRequest{
		Name:   "projects/" + projectID,
		Filter: `metric.type="compute.googleapis.com/instance/cpu/utilization"`,
		Interval: &monitoringpb.TimeInterval{
			StartTime: &timestamp.Timestamp{
				Seconds: startTime.Unix(),
			},
			EndTime: &timestamp.Timestamp{
				Seconds: endTime.Unix(),
			},
		},
		Aggregation: &monitoringpb.Aggregation{
			PerSeriesAligner: monitoringpb.Aggregation_ALIGN_MEAN,
			AlignmentPeriod: &duration.Duration{
				Seconds: 600,
			},
		},
	}
	it := client.ListTimeSeries(ctx, req)
	for {
		resp, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("could not read time series value: %v", err)
		}
		fmt.Fprintln(w, resp.GetMetric().GetLabels()["instance_name"])
		fmt.Fprintf(w, "\tNow: %.4f\n", resp.GetPoints()[0].GetValue().GetDoubleValue())
		fmt.Fprintf(w, "\t10 minutes ago: %.4f\n", resp.GetPoints()[1].GetValue().GetDoubleValue())
	}
	fmt.Fprintln(w, "Done")
	return nil
}

Java

MetricServiceClient metricServiceClient = MetricServiceClient.create();
String projectId = System.getProperty("projectId");
ProjectName name = ProjectName.of(projectId);

// Restrict time to last 20 minutes
long startMillis = System.currentTimeMillis() - ((60 * 20) * 1000);
TimeInterval interval = TimeInterval.newBuilder()
    .setStartTime(Timestamps.fromMillis(startMillis))
    .setEndTime(Timestamps.fromMillis(System.currentTimeMillis()))
    .build();

Aggregation aggregation = Aggregation.newBuilder()
    .setAlignmentPeriod(Duration.newBuilder().setSeconds(600).build())
    .setPerSeriesAligner(Aggregation.Aligner.ALIGN_MEAN)
    .build();

ListTimeSeriesRequest.Builder requestBuilder = ListTimeSeriesRequest.newBuilder()
    .setName(name.toString())
    .setFilter("metric.type=\"compute.googleapis.com/instance/cpu/utilization\"")
    .setInterval(interval)
    .setAggregation(aggregation);

ListTimeSeriesRequest request = requestBuilder.build();

ListTimeSeriesPagedResponse response = metricServiceClient.listTimeSeries(request);

System.out.println("Got timeseries: ");
for (TimeSeries ts : response.iterateAll()) {
  System.out.println(ts);
}

Node.js

// Imports the Google Cloud client library
const monitoring = require('@google-cloud/monitoring');

// Creates a client
const client = new monitoring.MetricServiceClient();

/**
 * TODO(developer): Uncomment and edit the following lines of code.
 */
// const projectId = 'YOUR_PROJECT_ID';

const request = {
  name: client.projectPath(projectId),
  filter: 'metric.type="compute.googleapis.com/instance/cpu/utilization"',
  interval: {
    startTime: {
      // Limit results to the last 20 minutes
      seconds: Date.now() / 1000 - 60 * 20,
    },
    endTime: {
      seconds: Date.now() / 1000,
    },
  },
  // Aggregate results per matching instance
  aggregation: {
    alignmentPeriod: {
      seconds: 600,
    },
    perSeriesAligner: 'ALIGN_MEAN',
  },
};

// Writes time series data
client
  .listTimeSeries(request)
  .then(results => {
    const timeSeries = results[0];

    console.log('CPU utilization:');
    timeSeries.forEach(data => {
      console.log(data.metric.labels.instance_name);
      console.log(`  Now: ${data.points[0].value.doubleValue}`);
      console.log(`  10 min ago: ${data.points[1].value.doubleValue}`);
    });
  })
  .catch(err => {
    console.error('ERROR:', err);
  });

PHP

use Google\Cloud\Monitoring\V3\MetricServiceClient;
use Google\Cloud\Monitoring\V3\Aggregation_Aligner;
use Google\Cloud\Monitoring\V3\Aggregation;
use Google\Cloud\Monitoring\V3\TimeInterval;
use Google\Cloud\Monitoring\V3\ListTimeSeriesRequest_TimeSeriesView;
use Google\Protobuf\Duration;
use Google\Protobuf\Timestamp;

/**
 * Example:
 * ```
 * read_timeseries_align($projectId);
 * ```
 *
 * @param string $projectId Your project ID
 */
function read_timeseries_align($projectId, $minutesAgo = 20)
{
    $metrics = new MetricServiceClient([
        'projectId' => $projectId,
    ]);

    $projectName = $metrics->projectName($projectId);
    $filter = 'metric.type="compute.googleapis.com/instance/cpu/utilization"';

    $startTime = new Timestamp();
    $startTime->setSeconds(time() - (60 * $minutesAgo));
    $endTime = new Timestamp();
    $endTime->setSeconds(time());

    $interval = new TimeInterval();
    $interval->setStartTime($startTime);
    $interval->setEndTime($endTime);

    $alignmentPeriod = new Duration();
    $alignmentPeriod->setSeconds(600);
    $aggregation = new Aggregation();
    $aggregation->setAlignmentPeriod($alignmentPeriod);
    $aggregation->setPerSeriesAligner(Aggregation_Aligner::ALIGN_MEAN);

    $view = ListTimeSeriesRequest_TimeSeriesView::FULL;

    $result = $metrics->listTimeSeries(
        $projectName,
        $filter,
        $interval,
        $view,
        ['aggregation' => $aggregation]);

    printf('CPU utilization:' . PHP_EOL);
    foreach ($result->iterateAllElements() as $timeSeries) {
        printf($timeSeries->getMetric()->getLabels()['instance_name'] . PHP_EOL);
        printf('  Now: ');
        printf($timeSeries->getPoints()[0]->getValue()->getDoubleValue() . PHP_EOL);
        if (count($timeSeries->getPoints()) > 1) {
            printf('  10 minutes ago: ');
            printf($timeSeries->getPoints()[1]->getValue()->getDoubleValue() . PHP_EOL);
        }
    }
}

Python

client = monitoring_v3.MetricServiceClient()
project_name = client.project_path(project_id)
interval = monitoring_v3.types.TimeInterval()
now = time.time()
interval.end_time.seconds = int(now)
interval.end_time.nanos = int(
    (now - interval.end_time.seconds) * 10**9)
interval.start_time.seconds = int(now - 3600)
interval.start_time.nanos = interval.end_time.nanos
aggregation = monitoring_v3.types.Aggregation()
aggregation.alignment_period.seconds = 300  # 5 minutes
aggregation.per_series_aligner = (
    monitoring_v3.enums.Aggregation.Aligner.ALIGN_MEAN)

results = client.list_time_series(
    project_name,
    'metric.type = "compute.googleapis.com/instance/cpu/utilization"',
    interval,
    monitoring_v3.enums.ListTimeSeriesRequest.TimeSeriesView.FULL,
    aggregation)
for result in results:
    print(result)

See Troubleshooting API calls if you have difficulty.

Example: Reducing across time series

This example extends the previous example by combining the aligned time series from the three VM instances into a single time series that measures the average utilization of all instances.

Protocol

Following are the sample parameters to timeSeries.list, which differ from the previous example only in the inclusion of aggregation.crossSeriesReducer:

  • name: projects/[PROJECT_ID]
  • aggregation.alignmentPeriod: 600s
  • aggregation.crossSeriesReducer: REDUCE_MEAN
  • aggregation.perSeriesAligner: ALIGN_MEAN
  • filter: metric.type = "compute.googleapis.com/instance/cpu/utilization"
  • interval.start_time: 2018-05-11T00:00:00Z
  • interval.end_time: 2018-05-11T00:20:00Z
  • fields: timeSeries.metric,timeSeries.points

Try It!

Before clicking the Execute button, change [PROJECT_ID] to the ID for your project, and adjust the end time to something recent and the start time to 20 minutes earlier.

The following sample result has only one time series and two data points. Each point is the average of the utilization among the three VM instances during the time period:

{
 "timeSeries": [
  {
   "metric": {
    "type": "compute.googleapis.com/instance/cpu/utilization"
   },
   "points": [
    {
     "interval": {
      "startTime": "2018-05-04T14:00:00.000Z",
      "endTime": "2018-05-04T14:00:00.000Z"
     },
     "value": {
      "doubleValue": 0.045992419596619184
     }
    },
    {
     "interval": {
      "startTime": "2018-05-04T13:50:00.000Z",
      "endTime": "2018-05-04T13:50:00.000Z"
     },
     "value": {
      "doubleValue": 0.04628773578358556
     }
    }
   ]
  }
 ]
}

C#

public static object ReadTimeSeriesReduce(string projectId,
    string metricType = "compute.googleapis.com/instance/cpu/utilization")
{
    // Create client.
    MetricServiceClient metricServiceClient = MetricServiceClient.Create();
    // Initialize request argument(s).
    string filter = $"metric.type=\"{metricType}\"";
    ListTimeSeriesRequest request = new ListTimeSeriesRequest
    {
        ProjectName = new ProjectName(projectId),
        Filter = filter,
        Interval = new TimeInterval(),
    };
    // Create timestamp for current time formatted in seconds.
    long timeStamp = (long)(DateTime.UtcNow - s_unixEpoch).TotalSeconds;
    Timestamp startTimeStamp = new Timestamp();
    // Set startTime to limit results to the last 20 minutes.
    startTimeStamp.Seconds = timeStamp - (60 * 20);
    Timestamp endTimeStamp = new Timestamp();
    // Set endTime to current time.
    endTimeStamp.Seconds = timeStamp;
    TimeInterval interval = new TimeInterval();
    interval.StartTime = startTimeStamp;
    interval.EndTime = endTimeStamp;
    request.Interval = interval;
    // Aggregate results per matching instance.
    Aggregation aggregation = new Aggregation();
    Duration alignmentPeriod = new Duration();
    alignmentPeriod.Seconds = 600;
    aggregation.AlignmentPeriod = alignmentPeriod;
    aggregation.CrossSeriesReducer = Aggregation.Types.Reducer.ReduceMean;
    aggregation.PerSeriesAligner = Aggregation.Types.Aligner.AlignMean;
    // Add the aggregation to the request.
    request.Aggregation = aggregation;
    // Make the request.
    PagedEnumerable<ListTimeSeriesResponse, TimeSeries> response =
        metricServiceClient.ListTimeSeries(request);
    // Iterate over all response items, lazily performing RPCs as required.
    Console.WriteLine("CPU utilization:");
    foreach (var item in response)
    {
        var points = item.Points;
        Console.WriteLine("Average CPU utilization across all GCE instances:");
        Console.WriteLine($"  Last 10 min: {points[0].Value.DoubleValue}");
        Console.WriteLine($"  Last 10-20 min ago: {points[1].Value.DoubleValue}");
    }
    return 0;
}

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	monitoring "cloud.google.com/go/monitoring/apiv3"
	"github.com/golang/protobuf/ptypes/duration"
	"github.com/golang/protobuf/ptypes/timestamp"
	"google.golang.org/api/iterator"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)

// readTimeSeriesReduce reads the last 20 minutes of the given metric, aligns
// everything on 10 minute intervals, and combines values from different
// instances.
func readTimeSeriesReduce(w io.Writer, projectID string) error {
	ctx := context.Background()
	client, err := monitoring.NewMetricClient(ctx)
	if err != nil {
		return fmt.Errorf("NewMetricClient: %v", err)
	}
	startTime := time.Now().UTC().Add(time.Minute * -20)
	endTime := time.Now().UTC()
	req := &monitoringpb.ListTimeSeriesRequest{
		Name:   "projects/" + projectID,
		Filter: `metric.type="compute.googleapis.com/instance/cpu/utilization"`,
		Interval: &monitoringpb.TimeInterval{
			StartTime: &timestamp.Timestamp{
				Seconds: startTime.Unix(),
			},
			EndTime: &timestamp.Timestamp{
				Seconds: endTime.Unix(),
			},
		},
		Aggregation: &monitoringpb.Aggregation{
			CrossSeriesReducer: monitoringpb.Aggregation_REDUCE_MEAN,
			PerSeriesAligner:   monitoringpb.Aggregation_ALIGN_MEAN,
			AlignmentPeriod: &duration.Duration{
				Seconds: 600,
			},
		},
	}
	it := client.ListTimeSeries(ctx, req)
	for {
		resp, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("could not read time series value: %v", err)
		}
		fmt.Fprintln(w, "Average CPU utilization across all GCE instances:")
		fmt.Fprintf(w, "\tNow: %.4f\n", resp.GetPoints()[0].GetValue().GetDoubleValue())
		fmt.Fprintf(w, "\t10 minutes ago: %.4f\n", resp.GetPoints()[1].GetValue().GetDoubleValue())
	}
	fmt.Fprintln(w, "Done")
	return nil
}

Java

MetricServiceClient metricServiceClient = MetricServiceClient.create();
String projectId = System.getProperty("projectId");
ProjectName name = ProjectName.of(projectId);

// Restrict time to last 20 minutes
long startMillis = System.currentTimeMillis() - ((60 * 20) * 1000);
TimeInterval interval = TimeInterval.newBuilder()
    .setStartTime(Timestamps.fromMillis(startMillis))
    .setEndTime(Timestamps.fromMillis(System.currentTimeMillis()))
    .build();

Aggregation aggregation = Aggregation.newBuilder()
    .setAlignmentPeriod(Duration.newBuilder().setSeconds(600).build())
    .setPerSeriesAligner(Aggregation.Aligner.ALIGN_MEAN)
    .setCrossSeriesReducer(Aggregation.Reducer.REDUCE_MEAN)
    .build();

ListTimeSeriesRequest.Builder requestBuilder = ListTimeSeriesRequest.newBuilder()
    .setName(name.toString())
    .setFilter("metric.type=\"compute.googleapis.com/instance/cpu/utilization\"")
    .setInterval(interval)
    .setAggregation(aggregation);

ListTimeSeriesRequest request = requestBuilder.build();

ListTimeSeriesPagedResponse response = metricServiceClient.listTimeSeries(request);

System.out.println("Got timeseries: ");
for (TimeSeries ts : response.iterateAll()) {
  System.out.println(ts);
}

Node.js

// Imports the Google Cloud client library
const monitoring = require('@google-cloud/monitoring');

// Creates a client
const client = new monitoring.MetricServiceClient();

/**
 * TODO(developer): Uncomment and edit the following lines of code.
 */
// const projectId = 'YOUR_PROJECT_ID';

const request = {
  name: client.projectPath(projectId),
  filter: 'metric.type="compute.googleapis.com/instance/cpu/utilization"',
  interval: {
    startTime: {
      // Limit results to the last 20 minutes
      seconds: Date.now() / 1000 - 60 * 20,
    },
    endTime: {
      seconds: Date.now() / 1000,
    },
  },
  // Aggregate results per matching instance
  aggregation: {
    alignmentPeriod: {
      seconds: 600,
    },
    crossSeriesReducer: 'REDUCE_MEAN',
    perSeriesAligner: 'ALIGN_MEAN',
  },
};

// Writes time series data
client
  .listTimeSeries(request)
  .then(results => {
    if (results[0].length === 0) {
      console.log('No data');
      return;
    }
    const reductions = results[0][0].points;

    console.log('Average CPU utilization across all GCE instances:');
    console.log(`  Last 10 min: ${reductions[0].value.doubleValue}`);
    console.log(`  10-20 min ago: ${reductions[0].value.doubleValue}`);
  })
  .catch(err => {
    console.error('ERROR:', err);
  });

PHP

use Google\Cloud\Monitoring\V3\MetricServiceClient;
use Google\Cloud\Monitoring\V3\Aggregation_Aligner;
use Google\Cloud\Monitoring\V3\Aggregation_Reducer;
use Google\Cloud\Monitoring\V3\Aggregation;
use Google\Cloud\Monitoring\V3\TimeInterval;
use Google\Cloud\Monitoring\V3\ListTimeSeriesRequest_TimeSeriesView;
use Google\Protobuf\Duration;
use Google\Protobuf\Timestamp;

/**
 * Example:
 * ```
 * read_timeseries_reduce($projectId);
 * ```
 *
 * @param string $projectId Your project ID
 */
function read_timeseries_reduce($projectId, $minutesAgo = 20)
{
    $metrics = new MetricServiceClient([
        'projectId' => $projectId,
    ]);

    $projectName = $metrics->projectName($projectId);
    $filter = 'metric.type="compute.googleapis.com/instance/cpu/utilization"';

    $startTime = new Timestamp();
    $startTime->setSeconds(time() - (60 * $minutesAgo));
    $endTime = new Timestamp();
    $endTime->setSeconds(time());

    $interval = new TimeInterval();
    $interval->setStartTime($startTime);
    $interval->setEndTime($endTime);

    $alignmentPeriod = new Duration();
    $alignmentPeriod->setSeconds(600);
    $aggregation = new Aggregation();
    $aggregation->setAlignmentPeriod($alignmentPeriod);
    $aggregation->setCrossSeriesReducer(Aggregation_Reducer::REDUCE_MEAN);
    $aggregation->setPerSeriesAligner(Aggregation_Aligner::ALIGN_MEAN);

    $view = ListTimeSeriesRequest_TimeSeriesView::FULL;

    $result = $metrics->listTimeSeries(
        $projectName,
        $filter,
        $interval,
        $view,
        ['aggregation' => $aggregation]);

    printf('Average CPU utilization across all GCE instances:' . PHP_EOL);
    if ($timeSeries = $result->iterateAllElements()->current()) {
        $reductions = $timeSeries->getPoints();
        printf('  Last 10 minutes: ');
        printf($reductions[0]->getValue()->getDoubleValue() . PHP_EOL);
        if (count($reductions) > 1) {
            printf('  10-20 minutes ago: ');
            printf($reductions[1]->getValue()->getDoubleValue() . PHP_EOL);
        }
    }
}

Python

client = monitoring_v3.MetricServiceClient()
project_name = client.project_path(project_id)
interval = monitoring_v3.types.TimeInterval()
now = time.time()
interval.end_time.seconds = int(now)
interval.end_time.nanos = int(
    (now - interval.end_time.seconds) * 10**9)
interval.start_time.seconds = int(now - 3600)
interval.start_time.nanos = interval.end_time.nanos
aggregation = monitoring_v3.types.Aggregation()
aggregation.alignment_period.seconds = 300  # 5 minutes
aggregation.per_series_aligner = (
    monitoring_v3.enums.Aggregation.Aligner.ALIGN_MEAN)
aggregation.cross_series_reducer = (
    monitoring_v3.enums.Aggregation.Reducer.REDUCE_MEAN)
aggregation.group_by_fields.append('resource.zone')

results = client.list_time_series(
    project_name,
    'metric.type = "compute.googleapis.com/instance/cpu/utilization"',
    interval,
    monitoring_v3.enums.ListTimeSeriesRequest.TimeSeriesView.FULL,
    aggregation)
for result in results:
    print(result)

See Troubleshooting API calls if you have difficulty.

Was this page helpful? Let us know how we did:

Send feedback about...

Stackdriver Monitoring