利用 OpenCensus 获取自定义指标

Stackdriver Monitoring 会自动从众多受监控资源列表中收集超过一千种内置指标。但这些指标无法捕获应用特有数据或客户端系统数据。通过这些指标,您可以了解有关后端延迟时间或磁盘使用情况的信息,但无法获知您的应用衍生了多少个后台例程。

应用特有指标是指您为捕获那些无法通过内置 Stackdriver Monitoring 指标采集的信息而定义和收集的指标。您可以利用一个由库提供的 API 来检测 (instrumentation) 代码并由此捕获此类指标,然后将捕获到的指标发送到 Stackdriver Monitoring 等后端应用。

在 Stackdriver Monitoring 中,应用特有指标通常称为“自定义指标”。这些术语可以相互换用。它们也被称为“用户定义的指标”。

在 Stackdriver Monitoring 中,自定义指标可以像内置指标一样使用。您可以为自定义指标绘制图表、设置提醒,也可以监控它们。但不同的是,自定义指标由您定义和写入数据,并且您可以删除这些指标。而对于内置指标,您不能执行这些操作。

您可以通过许多方式来捕获自定义指标,例如,使用原生 Stackdriver Monitoring API。Stackdriver 建议您使用 OpenCensus 来检测代码,由此收集自定义指标。

什么是 OpenCensus?

OpenCensus 是一个免费的开源项目,该项目的库具有以下特点:

  • 可为收集各种语言的指标和跟踪数据提供不限定供应商的支持。
  • 可将收集的数据导出到各种后端应用(包括 Stackdriver)。

如需受支持语言的最新列表,请参阅语言支持。如需可使用导出器的后端应用的最新列表,请参阅导出器

为什么选择 OpenCensus?

虽然 Stackdriver Monitoring 会提供一个支持定义和收集自定义指标的 API,但这是一个低层级的专有 API。OpenCensus 不但会提供一个更加符合惯例的 API,而且还会提供一个导出器,该导出器可通过 Monitoring API 为您将指标数据发送到 Stackdriver Monitoring。

此外,OpenCensus 是一个开源项目。您可以使用一个不限定供应商的库来导出收集的数据,而无需专有库。

OpenCensus 还对应用跟踪提供了良好的支持。如需大致了解这项支持,请参阅 OpenCensus 跟踪。Stackdriver 建议使用 OpenCensus 进行跟踪检测。您可以利用只有单一发行版的库从各项服务中收集指标和跟踪数据。如需了解如何将 OpenCensus 与 Stackdriver Trace 配合使用,请参阅适用于 Trace 的客户端库

准备工作

要使用 Stackdriver Monitoring,您必须拥有一个启用了结算功能的 GCP 项目。该项目还必须具有关联的 Stackdriver 工作区。Stackdriver Monitoring 使用工作区来整理受监控的 GCP 项目。

如果您还没有 GCP 项目,请执行以下操作:

  1. 登录您的 Google 帐号。

    如果您还没有 Google 帐号,请注册新帐号

  2. 在 GCP Console 的项目选择器页面上,选择或创建 GCP 项目。

    转到项目选择器页面

  3. 确保您的 Google Cloud Platform 项目已启用结算功能。 了解如何确认您的项目已启用结算功能

要将您的项目关联至一个工作区,请参阅工作区

自定义指标是 Stackdriver Monitoring 的一项付费功能,因此您可能需要为指标的提取付费。如需详细了解价格,请参阅 Stackdriver 价格

安装 OpenCensus

要使用 OpenCensus,您必须准备好指标库和 Stackdriver 导出器。

Go

要使用 OpenCensus,需要安装 Go 1.11 版本或更高版本。系统会自动为您处理依赖项。

Java

对于 Maven,请将以下内容添加到 pom.xml 文件中的 dependencies 元素:
<dependency>
  <groupId>io.opencensus</groupId>
  <artifactId>opencensus-api</artifactId>
  <version>${opencensus.version}</version>
</dependency>
<dependency>
  <groupId>io.opencensus</groupId>
  <artifactId>opencensus-impl</artifactId>
  <version>${opencensus.version}</version>
</dependency>
<dependency>
  <groupId>io.opencensus</groupId>
  <artifactId>opencensus-exporter-stats-stackdriver</artifactId>
  <version>${opencensus.version}</version>
</dependency>

Node.js

  1. 在安装 OpenCensus 核心和导出器库之前,请确保已准备好 Node.js 开发环境
  2. 安装 OpenCensus 的最简单方法是使用 npm
    npm install @opencensus/core
    npm install @opencensus/exporter-stackdriver
  3. 将如下所示的 require 语句添加到应用主脚本的顶部或任何其他代码开头的入口点处:
const {globalStats, MeasureUnit, AggregationType} = require('@opencensus/core');
const {StackdriverStatsExporter} = require('@opencensus/exporter-stackdriver');

Python

使用以下命令安装 OpenCensus 核心和 Stackdriver 导出器库:

pip install -r opencensus/requirements.txt

使用 OpenCensus 获取指标

要使用 OpenCensus 获取指标,您大致需要执行以下三个步骤来检测代码:

  1. 导入 OpenCensus 统计信息和 OpenCensus Stackdriver 导出器包。
  2. 初始化 Stackdriver 导出器。
  3. 使用 OpenCensus API 来检测代码。

基本示例

以下是能够演示上述步骤的最精简程序。该程序运行一个循环并收集延迟时间指标;当循环结束时,它会将统计信息导出到 Stackdriver Monitoring 并退出运行:

Go

// metrics_quickstart is an example of exporting a custom metric from
// OpenCensus to Stackdriver.
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"contrib.go.opencensus.io/exporter/stackdriver"
	"go.opencensus.io/stats"
	"go.opencensus.io/stats/view"
	"golang.org/x/exp/rand"
)

var (
	// The task latency in milliseconds.
	latencyMs = stats.Float64("task_latency", "The task latency in milliseconds", "ms")
)

func main() {
	ctx := context.Background()

	// Register the view. It is imperative that this step exists,
	// otherwise recorded metrics will be dropped and never exported.
	v := &view.View{
		Name:        "task_latency_distribution",
		Measure:     latencyMs,
		Description: "The distribution of the task latencies",

		// Latency in buckets:
		// [>=0ms, >=100ms, >=200ms, >=400ms, >=1s, >=2s, >=4s]
		Aggregation: view.Distribution(0, 100, 200, 400, 1000, 2000, 4000),
	}
	if err := view.Register(v); err != nil {
		log.Fatalf("Failed to register the view: %v", err)
	}

	// Enable OpenCensus exporters to export metrics
	// to Stackdriver Monitoring.
	// Exporters use Application Default Credentials to authenticate.
	// See https://developers.google.com/identity/protocols/application-default-credentials
	// for more details.
	exporter, err := stackdriver.NewExporter(stackdriver.Options{})
	if err != nil {
		log.Fatal(err)
	}
	// Flush must be called before main() exits to ensure metrics are recorded.
	defer exporter.Flush()

	if err := exporter.StartMetricsExporter(); err != nil {
		log.Fatalf("Error starting metric exporter: %v", err)
	}
	defer exporter.StopMetricsExporter()

	// Record 100 fake latency values between 0 and 5 seconds.
	for i := 0; i < 100; i++ {
		ms := float64(5*time.Second/time.Millisecond) * rand.Float64()
		fmt.Printf("Latency %d: %f\n", i, ms)
		stats.Record(ctx, latencyMs.M(ms))
		time.Sleep(1 * time.Second)
	}

	fmt.Println("Done recording metrics")
}

Java

import com.google.common.collect.Lists;

import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
import io.opencensus.stats.Aggregation;
import io.opencensus.stats.BucketBoundaries;
import io.opencensus.stats.Measure.MeasureLong;
import io.opencensus.stats.Stats;
import io.opencensus.stats.StatsRecorder;
import io.opencensus.stats.View;
import io.opencensus.stats.View.Name;
import io.opencensus.stats.ViewManager;

import java.io.IOException;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.TimeUnit;

public class Quickstart {
  private static final int EXPORT_INTERVAL = 70;
  private static final MeasureLong LATENCY_MS = MeasureLong.create(
      "task_latency",
      "The task latency in milliseconds",
      "ms");
  // Latency in buckets:
  // [>=0ms, >=100ms, >=200ms, >=400ms, >=1s, >=2s, >=4s]
  private static final BucketBoundaries LATENCY_BOUNDARIES = BucketBoundaries.create(
      Lists.newArrayList(0d, 100d, 200d, 400d, 1000d, 2000d, 4000d));
  private static final StatsRecorder STATS_RECORDER = Stats.getStatsRecorder();

  public static void main(String[] args) throws IOException, InterruptedException {
    // Register the view. It is imperative that this step exists,
    // otherwise recorded metrics will be dropped and never exported.
    View view = View.create(
        Name.create("task_latency_distribution"),
        "The distribution of the task latencies.",
        LATENCY_MS,
        Aggregation.Distribution.create(LATENCY_BOUNDARIES),
        Collections.emptyList());

    ViewManager viewManager = Stats.getViewManager();
    viewManager.registerView(view);

    // Enable OpenCensus exporters to export metrics to Stackdriver Monitoring.
    // Exporters use Application Default Credentials to authenticate.
    // See https://developers.google.com/identity/protocols/application-default-credentials
    // for more details.
    StackdriverStatsExporter.createAndRegister();

    // Record 100 fake latency values between 0 and 5 seconds.
    Random rand = new Random();
    for (int i = 0; i < 100; i++) {
      long ms = (long) (TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS) * rand.nextDouble());
      System.out.println(String.format("Latency %d: %d", i, ms));
      STATS_RECORDER.newMeasureMap().put(LATENCY_MS, ms).record();
    }

    // The default export interval is 60 seconds. The thread with the StackdriverStatsExporter must
    // live for at least the interval past any metrics that must be collected, or some risk being
    // lost if they are recorded after the last export.

    System.out.println(String.format(
        "Sleeping %d seconds before shutdown to ensure all records are flushed.", EXPORT_INTERVAL));
    Thread.sleep(TimeUnit.MILLISECONDS.convert(EXPORT_INTERVAL, TimeUnit.SECONDS));
  }
}

Node.js

'use strict';

const {globalStats, MeasureUnit, AggregationType} = require('@opencensus/core');
const {StackdriverStatsExporter} = require('@opencensus/exporter-stackdriver');

const EXPORT_INTERVAL = 60;
const LATENCY_MS = globalStats.createMeasureInt64(
  'task_latency',
  MeasureUnit.MS,
  'The task latency in milliseconds'
);

// Register the view. It is imperative that this step exists,
// otherwise recorded metrics will be dropped and never exported.
const view = globalStats.createView(
  'task_latency_distribution',
  LATENCY_MS,
  AggregationType.DISTRIBUTION,
  [],
  'The distribution of the task latencies.',
  // Latency in buckets:
  // [>=0ms, >=100ms, >=200ms, >=400ms, >=1s, >=2s, >=4s]
  [0, 100, 200, 400, 1000, 2000, 4000]
);

// Then finally register the views
globalStats.registerView(view);

// Enable OpenCensus exporters to export metrics to Stackdriver Monitoring.
// Exporters use Application Default Credentials (ADCs) to authenticate.
// See https://developers.google.com/identity/protocols/application-default-credentials
// for more details.
// Expects ADCs to be provided through the environment as ${GOOGLE_APPLICATION_CREDENTIALS}
// A Stackdriver workspace is required and provided through the environment as ${GOOGLE_PROJECT_ID}
const projectId = process.env.GOOGLE_PROJECT_ID;

// GOOGLE_APPLICATION_CREDENTIALS are expected by a dependency of this code
// Not this code itself. Checking for existence here but not retaining (as not needed)
if (!projectId || !process.env.GOOGLE_APPLICATION_CREDENTIALS) {
  throw Error('Unable to proceed without a Project ID');
}

// The minimum reporting period for Stackdriver is 1 minute.
const exporter = new StackdriverStatsExporter({
  projectId: projectId,
  period: EXPORT_INTERVAL * 1000,
});

// Pass the created exporter to Stats
globalStats.registerExporter(exporter);

// Record 100 fake latency values between 0 and 5 seconds.
for (let i = 0; i < 100; i++) {
  const ms = Math.floor(Math.random() * 5);
  console.log(`Latency ${i}: ${ms}`);
  globalStats.record([
    {
      measure: LATENCY_MS,
      value: ms,
    },
  ]);
}

/**
 * The default export interval is 60 seconds. The thread with the
 * StackdriverStatsExporter must live for at least the interval past any
 * metrics that must be collected, or some risk being lost if they are recorded
 * after the last export.
 */
setTimeout(() => {
  console.log('Done recording metrics.');
}, EXPORT_INTERVAL * 1000);

Python

from random import random
import time

from opencensus.ext.stackdriver import stats_exporter
from opencensus.stats import aggregation
from opencensus.stats import measure
from opencensus.stats import stats
from opencensus.stats import view

# A measure that represents task latency in ms.
LATENCY_MS = measure.MeasureFloat(
    "task_latency",
    "The task latency in milliseconds",
    "ms")

# A view of the task latency measure that aggregates measurements according to
# a histogram with predefined bucket boundaries. This aggregate is periodically
# exported to Stackdriver Monitoring.
LATENCY_VIEW = view.View(
    "task_latency_distribution",
    "The distribution of the task latencies",
    [],
    LATENCY_MS,
    # Latency in buckets: [>=0ms, >=100ms, >=200ms, >=400ms, >=1s, >=2s, >=4s]
    aggregation.DistributionAggregation(
        [100.0, 200.0, 400.0, 1000.0, 2000.0, 4000.0]))

def main():
    # Register the view. Measurements are only aggregated and exported if
    # they're associated with a registered view.
    stats.stats.view_manager.register_view(LATENCY_VIEW)

    # Create the Stackdriver stats exporter and start exporting metrics in the
    # background, once every 60 seconds by default.
    exporter = stats_exporter.new_stats_exporter()
    print('Exporting stats to project "{}"'
          .format(exporter.options.project_id))

    # Record 100 fake latency values between 0 and 5 seconds.
    for num in range(100):
        ms = random() * 5 * 1000
        print("Latency {}: {}".format(num, ms))

        mmap = stats.stats.stats_recorder.new_measurement_map()
        mmap.measure_float_put(LATENCY_MS, ms)
        mmap.record()

    # Keep the thread alive long enough for the exporter to export at least
    # once.
    time.sleep(65)

if __name__ == '__main__':
    main()
此指标数据导出到 Stackdriver 后,您可以像使用其他任何数据一样使用这些数据。

该程序会创建一个名为 task_latency_distribution 的 OpenCensus 视图。当指标被导出到 Stackdriver Monitoring 时,该字符串会成为指标名称的一部分。如需了解如何以 Stackdriver Monitoring 指标描述符形式实现 OpenCensus 视图,请参阅检索指标描述符

因此,在选择要绘制成图表的指标时,您可以使用视图名称作为搜索字符串。例如,您可以在 Metrics Explorer 的查找资源类型和指标 (Find resource type and metric) 字段中输入该名称。以下屏幕截图显示了相关结果:

Stackdriver Monitoring 中的 OpenCensus 指标

热图中的每个条形代表程序的一次运行,而每个条形上的彩色部分代表延迟分布中的各个范围。如需详细了解图表背后的数据,请参阅 Stackdriver 中的 OpenCensus 指标

OpenCensus 文档

OpenCensus 提供了有关其 Metrics API 和 Stackdriver 导出器的权威参考文档。下表提供了这些参考文档的链接:

语言 API 参考文档 导出器文档 快速入门
Go Go API 统计信息和 Trace 导出器 指标
Java Java API 统计信息导出器 指标
NodeJS NodeJS API 统计信息导出器 指标
Python Python API 统计信息导出器 指标

映射模型

您可以使用原生 Stackdriver Monitoring API 来收集自定义指标;如需查看此 API 的用法,请参阅使用自定义指标。实际上,OpenCensus Stackdriver 导出器会为您使用此 API。

即使您不需要知道 Stackdriver Monitoring API 的具体用法,熟悉其结构和术语也依然有助于了解 Stackdriver Monitoring 的指标表示方式。本部分会介绍一些背景信息。

被提取到 Stackdriver 的指标存储在 Stackdriver Monitoring 结构中。例如,您可以检索自定义指标的指标描述符(Monitoring API 中的一种类型)。如需了解详情,请参阅 MetricDescriptor。例如,您会在为数据创建图表时遇到这些指标描述符。

术语和概念

OpenCensus API 使用的结构与 Stackdriver Monitoring 使用的结构不同,一些术语的使用也是如此。对于同一内容,在 Stackdriver Monitoring 中使用“指标”,而在 OpenCensus 中有时使用“统计信息”。例如,发送 Stackdriver 指标数据的 OpenCensus 组件称为“Stackdriver 统计信息导出器”。

如需简要了解 OpenCensus 指标模型,请参阅 OpenCensus 指标。

OpenCensus 统计信息数据模型与 Stackdriver Monitoring 指标数据模型之间并非整齐的一一对应。两种数据模型之间存在着许多相同概念,但这些概念不能直接相互换用。

  • OpenCensus 视图通常类似于 Monitoring API 中的 MetricDescriptor。该视图描述了如何收集和聚合各个测量结果。所有记录的测量结果会按标记细分。

  • OpenCensus 标记是一个键值对。该标记通常与 Monitoring API 中的 LabelDescriptor 相对应。您可以使用标记来捕获相关上下文信息,以便对指标进行过滤和分组

  • OpenCensus 度量描述了要记录的指标数据。OpenCensus 聚合是对数据应用的函数,用于汇总数据。系统在导出数据时会使用这两项内容来确定 Stackdriver 指标描述符中报告的 MetricKindValueType 和单位。

  • OpenCensus 测量结果是为度量而收集的数据点。测量结果必须聚合到视图中。否则,独立的测量结果将会被丢弃。这种结构与 Monitoring API 中的 Point 类似。测量结果聚合到视图中后,聚合数据将存储为视图数据,这类似于 Monitoring API 中的 TimeSeries

Stackdriver 中的 OpenCensus 指标

您可以在 Stackdriver Monitoring 中检查导出的指标。基本示例中的屏幕截图来自于 Metrics Explorer。如果您已运行该示例程序,则可以使用 Metrics Explorer 查看您的数据:

转到 Metrics Explorer 页面

在指定指标时,您可以通过提供 OpenCensus 视图的名称来限制搜索范围。如需了解详情,请参阅选择指标

检索指标描述符

您可以使用 Monitoring API 直接检索指标数据。要检索指标数据,您需要知道 OpenCensus 指标在导出时使用的 Stackdriver 名称。

获取该信息的一种方法是检索由导出器创建的指标描述符,并查找 type 字段的值。此值包含从中导出相应指标的 OpenCensus 视图的名称。如需详细了解指标描述符,请参阅 MetricDescriptor

要查看为导出的指标创建的指标描述符,您可以使用 metricDescriptors.list 方法参考页面上的 API Explorer(试用此 API)微件。要使用此工具检索 OpenCensus 指标的指标描述符,请执行以下操作:

  1. name 字段中输入项目的名称:projects/[PROJECT_ID] 本文档使用 ID 为 a-gcp-project 的项目。

  2. filter 字段中输入过滤条件。OpenCensus 视图的名称将成为指标名称的一部分,因此您可以提供如下过滤条件,以便使用该名称来限制列表内容:

    metric.type=has_substring("task_latency_distribution")

    任何项目中都有很多指标描述符。使用 OpenCensus 视图名称中的子字符串进行过滤可以排除其中的大多数描述符。

  3. 点击执行按钮。

返回的指标描述符如下所示:

{
  "metricDescriptors": [
    {
      "name": "projects/a-gcp-project/metricDescriptors/custom.googleapis.com/opencensus/task_latency_distribution",
      "labels": [
        {
          "key": "opencensus_task",
          "description": "Opencensus task identifier"
        }
      ],
      "metricKind": "CUMULATIVE",
      "valueType": "DISTRIBUTION",
      "unit": "ms",
      "description": "The distribution of the task latencies",
      "displayName": "OpenCensus/task_latency_distribution",
      "type": "custom.googleapis.com/opencensus/task_latency_distribution"
    }
  ]
}

指标描述符中的以下行指示 Stackdriver Monitoring 中的指标类型名称:

"type": "custom.googleapis.com/opencensus/task_latency_distribution"

利用此信息,您可以随后手动检索与此指标类型关联的数据。该数据也会显示在此指标的图表上。

检索指标数据

要手动检索某一指标类型的时间序列数据,您可以使用 timeSeries.list 方法参考页面上的试用此 API 工具:

  1. name 字段中输入项目的名称:projects/[PROJECT_ID]
  2. filter 字段中输入所需指标类型的过滤条件:metric.type="custom.googleapis.com/opencensus/task_latency_distribution"
    • metric.type 键是时间序列中嵌入的一个类型字段。如需了解详情,请参阅 TimeSeries
    • 该值是从指标描述符中提取的 type 值(请参阅检索指标描述符)。
  3. 指定以下字段的值,以输入检索的时间范围:
    • interval.endTime(一个时间戳,例如 2018-10-11T15:48:38-04:00
    • interval.startTime(必须早于 interval.endTime
  4. 点击执行按钮。

此类检索的结果如下所示:

{
  "timeSeries": [
    {
      "metric": {
        "labels": {
          "opencensus_task": "java-3424@docbuild"
        },
        "type": "custom.googleapis.com/opencensus/task_latency_distribution"
      },
      "resource": {
        "type": "gce_instance",
        "labels": {
          "instance_id": "2455918024984027105",
          "zone": "us-east1-b",
          "project_id": "a-gcp-project"
        }
      },
      "metricKind": "CUMULATIVE",
      "valueType": "DISTRIBUTION",
      "points": [
        {
          "interval": {
            "startTime": "2019-04-04T17:49:34.163Z",
            "endTime": "2019-04-04T17:50:42.917Z"
          },
          "value": {
            "distributionValue": {
              "count": "100",
              "mean": 2610.11,
              "sumOfSquaredDeviation": 206029821.78999996,
              "bucketOptions": {
                "explicitBuckets": {
                  "bounds": [
                    0,
                    100,
                    200,
                    400,
                    1000,
                    2000,
                    4000
                  ]
                }
              },
              "bucketCounts": [
                "0",
                "0",
                "1",
                "6",
                "13",
                "15",
                "44",
                "21"
              ]
            }
          }
        }
      ]
    },
    [ ... data from additional program runs deleted ...]
  ]
}

此处返回的数据包括以下内容:

  • 所收集数据涉及的受监控资源的信息。OpenCensus 可以自动检测 gce_instancek8s_containeraws_ec2_instance 这些受监控的资源。此数据来自于 Compute Engine 实例上运行的程序。如需了解如何使用其他受监控的资源,请参阅为导出程序设置受监控的资源
  • 有关指标种类和值类型的说明。
  • 在请求的时间间隔内收集的实际数据点。
此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
Stackdriver Monitoring
需要帮助?请访问我们的支持页面