Como usar métricas do OpenCensus

Nesta página, você verá os conceitos básicos da criação de métricas do OpenCensus para SLIs de disponibilidade e latência. Você verá também exemplos de implementação de como definir SLOs usando métricas do OpenCensus.

Noções básicas do OpenCensus

O OpenCensus é uma única distribuição de código aberto de bibliotecas, disponível na página do OpenCensus no GitHub (em inglês), que coleta automaticamente os traces e as métricas e os envia para qualquer back-end. O OpenCensus pode ser usado para instrumentar os serviços para emitir métricas personalizadas que podem ser processadas no Cloud Monitoring. Use essas métricas como SLIs.

Para ver um exemplo de uso do OpenCensus para criar métricas de monitoramento que não sejam destinadas especificamente a SLIs, consulte Métricas personalizadas com OpenCensus.

Métrica

Para coletar dados de métrica do serviço usando o OpenCensus, você precisa usar os seguintes elementos do OpenCensus:

  • Measure, que representa o tipo de métrica a ser registrado, especificado com um nome de métrica. Um Measure pode registrar valores Int64 ou Float64.
  • Measurement: que registra um ponto de dados específico coletado e gravado por um Measure para um evento específico. Por exemplo, uma Measurement pode registrar a latência de uma resposta específica.
  • View, que especifica uma agregação aplicada a um Measure. O OpenCensus é compatível com os seguintes tipos de agregação:
    • Contagem: uma contagem do número de pontos de medição.
    • Distribuição: uma distribuição por histograma dos pontos de medição.
    • Soma: uma soma dos valores de medição.
    • LastValue: o último valor registrado pela medição.

Para mais informações, consulte Estatísticas/métricas do OpenCensus. Note que, no OpenCensus, geralmente as métricas são chamadas de estatísticas.

Instrumentação

As bibliotecas do OpenCensus estão disponíveis em diversas linguagens. Para informações específicas da linguagem sobre como instrumentar seu serviço para emitir métricas, consulte Compatibilidade com a linguagem do OpenCensus. Além disso, em Métricas personalizadas com OpenCensus, há exemplos de linguagens usadas com frequência com o Monitoring.

No caso básico, você precisa fazer o seguinte:

  • Instrumente seu serviço para registrar e exportar métricas.
  • Defina um exportador para receber as métricas.

Para cada métrica, é necessário definir um Measure para especificar o tipo de valor: Int64 ou Float64. Você também precisa definir e registrar o View para especificar o tipo de agregação (contagem, distribuição, soma ou último valor). Para usar o tipo de agregação de distribuição, você também precisa especificar explicitamente os limites do bucket de histograma. Também é possível especificar um nome para a métrica no View.

Exportador

Por fim, você precisa usar um exportador para coletar as métricas e gravá-las no Cloud Monitoring ou em outro back-end. Para informações sobre os exportadores específicos de linguagem disponíveis para o Monitoring, consulte Exportadores do OpenCensus (em inglês).

Você também pode escrever seu próprio exportador. Para mais informações, consulte Como escrever um exportador personalizado.

Como criar métricas para SLIs

O aplicativo precisa criar métricas do OpenCensus que podem ser usadas como SLIs no Cloud Monitoring:

  • Para SLIs de disponibilidade em contagens de solicitações e erros, use um Measure com agregação de contagem.
  • Para SLIs de latência, use um Measure com agregação de distribuição.

Métricas para SLIs de disponibilidade

Para expressar uma SLI de disponibilidade baseada em solicitação na API Cloud Monitoring, use a estrutura TimeSeriesRatio para configurar uma proporção de solicitações "boas" ou "ruins" para o total solicitações. Essa proporção é usada no campo goodTotalRatio de uma estrutura RequestBasedSli.

O aplicativo precisa criar métricas do OpenCensus que podem ser usadas para construir essa proporção. No aplicativo, é preciso criar pelo menos dois dos seguintes itens:

  1. Uma métrica que conta o total de eventos. Use essa métrica no totalServiceFilter da proporção.

    É possível criar uma métrica do OpenCensus do tipo Int64 com agregação de contagem, em que um valor de 1 é registrado para cada solicitação recebida.

  2. Uma métrica que conta eventos "ruins". Use essa métrica no badServiceFilter da proporção.

    É possível criar uma métrica do OpenCensus do tipo Int64 com agregação de contagem, em que um valor de 1 é registrado para cada erro ou solicitação com falha.

  3. Uma métrica que conta eventos "bons". Use essa métrica no goodServiceFilter da proporção.

    É possível criar uma métrica do OpenCensus do tipo Int64 com agregação de contagem, em que um valor de 1 é registrado para cada resposta bem-sucedida.

Métricas para SLIs de latência

Expresse um SLI de latência baseado em solicitação na API Cloud Monitoring usando uma estrutura DistributionCut. Essa estrutura é usada no campo distributionCut de uma estrutura RequestBasedSli.

É possível criar um Measure Int64 ou Float64 com um View usando o tipo de agregação de distribuição. Também é preciso definir explicitamente os limites do bucket. É fundamental definir os buckets de um modo que seja possível medir com precisão a porcentagem de solicitações que estão dentro do limite desejado. Para ver uma discussão sobre este tópico, consulte Como implementar SLOs na pasta de trabalho Engenharia de confiabilidade do site.

Exemplo de implementação

Nesta seção, apresentamos um exemplo que implementa métricas para SLIs de latência e disponibilidade básica usando o OpenCensus no Node.js.

Instrumentação

Para instrumentar o serviço para emitir métricas usando o OpenCensus, faça o seguinte:

  1. Inclua as bibliotecas necessárias:

    Go

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    import (
    	"flag"
    	"fmt"
    	"log"
    	"math/rand"
    	"net/http"
    	"time"
    
    	"contrib.go.opencensus.io/exporter/stackdriver"
    	"go.opencensus.io/stats"
    	"go.opencensus.io/stats/view"
    	"go.opencensus.io/tag"
    )
    

    Node.js

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

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

    Python

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    from flask import Flask
    from opencensus.ext.prometheus import stats_exporter as prometheus
    from opencensus.stats import aggregation as aggregation_module
    from opencensus.stats import measure as measure_module
    from opencensus.stats import stats as stats_module
    from opencensus.stats import view as view_module
    from opencensus.tags import tag_map as tag_map_module
    
    from prometheus_flask_exporter import PrometheusMetrics
    
  2. Defina e registre o exportador:

    Go

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    // Sets up Cloud Monitoring exporter.
    sd, err := stackdriver.NewExporter(stackdriver.Options{
    	ProjectID:         *projectID,
    	MetricPrefix:      "opencensus-demo",
    	ReportingInterval: 60 * time.Second,
    })
    if err != nil {
    	log.Fatalf("Failed to create the Cloud Monitoring exporter: %v", err)
    }
    defer sd.Flush()
    
    sd.StartMetricsExporter()
    defer sd.StopMetricsExporter()

    Node.js

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    // Stackdriver export interval is 60 seconds
    const EXPORT_INTERVAL = 60;
    const exporter = new StackdriverStatsExporter({
      projectId: projectId,
      period: EXPORT_INTERVAL * 1000,
    });
    globalStats.registerExporter(exporter);

    Python

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    def setup_openCensus_and_prometheus_exporter() -> None:
        stats = stats_module.stats
        view_manager = stats.view_manager
        exporter = prometheus.new_stats_exporter(prometheus.Options(namespace="oc_python"))
        view_manager.register_exporter(exporter)
        register_all_views(view_manager)
  3. Defina um Measure para cada métrica:

    Go

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    // Sets up metrics.
    var (
    	requestCount       = stats.Int64("oc_request_count", "total request count", "requests")
    	failedRequestCount = stats.Int64("oc_failed_request_count", "count of failed requests", "requests")
    	responseLatency    = stats.Float64("oc_latency_distribution", "distribution of response latencies", "s")
    )
    

    Node.js

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    const REQUEST_COUNT = globalStats.createMeasureInt64(
      'request_count',
      MeasureUnit.UNIT,
      'Number of requests to the server'
    );
    const ERROR_COUNT = globalStats.createMeasureInt64(
      'error_count',
      MeasureUnit.UNIT,
      'Number of failed requests to the server'
    );
    const RESPONSE_LATENCY = globalStats.createMeasureInt64(
      'response_latency',
      MeasureUnit.MS,
      'The server response latency in milliseconds'
    );

    Python

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    m_request_count = measure_module.MeasureInt(
        "python_request_count", "total requests", "requests"
    )
    m_failed_request_count = measure_module.MeasureInt(
        "python_failed_request_count", "failed requests", "requests"
    )
    m_response_latency = measure_module.MeasureFloat(
        "python_response_latency", "response latency", "s"
    )
  4. Defina e registre o View para cada Measure com o tipo de agregação apropriado e, para a latência de resposta, os limites do bucket:

    Go

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    // Sets up views.
    var (
    	requestCountView = &view.View{
    		Name:        "oc_request_count",
    		Measure:     requestCount,
    		Description: "total request count",
    		Aggregation: view.Count(),
    	}
    	failedRequestCountView = &view.View{
    		Name:        "oc_failed_request_count",
    		Measure:     failedRequestCount,
    		Description: "count of failed requests",
    		Aggregation: view.Count(),
    	}
    	responseLatencyView = &view.View{
    		Name:        "oc_response_latency",
    		Measure:     responseLatency,
    		Description: "The distribution of the latencies",
    		// Bucket definitions must be explicitly specified.
    		Aggregation: view.Distribution(0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
    	}
    )
    
    	// Register the views.
    	if err := view.Register(requestCountView, failedRequestCountView, responseLatencyView); err != nil {
    		log.Fatalf("Failed to register the views: %v", err)
    	}

    Node.js

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    const request_count_metric = globalStats.createView(
      'request_count_metric',
      REQUEST_COUNT,
      AggregationType.COUNT
    );
    globalStats.registerView(request_count_metric);
    const error_count_metric = globalStats.createView(
      'error_count_metric',
      ERROR_COUNT,
      AggregationType.COUNT
    );
    globalStats.registerView(error_count_metric);
    const latency_metric = globalStats.createView(
      'response_latency_metric',
      RESPONSE_LATENCY,
      AggregationType.DISTRIBUTION,
      [],
      'Server response latency distribution',
      // Latency in buckets:
      [0, 1000, 2000, 3000, 4000, 5000, 10000]
    );
    globalStats.registerView(latency_metric);

    Python

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    # set up views
    latency_view = view_module.View(
        "python_response_latency",
        "The distribution of the latencies",
        [],
        m_response_latency,
        aggregation_module.DistributionAggregation(
            [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000]
        ),
    )
    
    request_count_view = view_module.View(
        "python_request_count",
        "total requests",
        [],
        m_request_count,
        aggregation_module.CountAggregation(),
    )
    
    failed_request_count_view = view_module.View(
        "python_failed_request_count",
        "failed requests",
        [],
        m_failed_request_count,
        aggregation_module.CountAggregation(),
    )
    
    # register views
    def register_all_views(view_manager: stats_module.stats.view_manager) -> None:
        view_manager.register_view(latency_view)
        view_manager.register_view(request_count_view)
        view_manager.register_view(failed_request_count_view)
  5. Registre valores para as métricas de contagem de solicitações e de erros:

    Go

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    // Counts the request.
    stats.Record(ctx, requestCount.M(1))
    
    // Randomly fails 10% of the time.
    if rand.Intn(100) >= 90 {
    	// Counts the error.
    	stats.Record(ctx, failedRequestCount.M(1))

    Node.js

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    // record a request count for every request
    globalStats.record([
      {
        measure: REQUEST_COUNT,
        value: 1,
      },
    ]);
    
    // randomly throw an error 10% of the time
    const randomValue = Math.floor(Math.random() * 9 + 1);
    if (randomValue === 1) {
      // Record a failed request.
      globalStats.record([
        {
          measure: ERROR_COUNT,
          value: 1,
        },
      ]);

    Python

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    mmap = stats_recorder.new_measurement_map()
    # count request
    mmap.measure_int_put(m_request_count, 1)
    # fail 10% of the time
    if random.randint(0, 100) > 90:
        mmap.measure_int_put(m_failed_request_count, 1)
        tmap = tag_map_module.TagMap()
        mmap.record(tmap)
        return ("error!", 500)
  6. Valores de latência de registro:

    Go

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    requestReceived := time.Now()
    // Records latency for failure OR success.
    defer func() {
    	stats.Record(ctx, responseLatency.M(time.Since(requestReceived).Seconds()))
    }()

    Node.js

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    globalStats.record([
      {
        measure: RESPONSE_LATENCY,
        value: stopwatch.elapsedMilliseconds,
      },
    ]);

    Python

    Para autenticar no Monitoring, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

    start_time = time.perf_counter()
    mmap = stats_recorder.new_measurement_map()
    if random.randint(0, 100) > 90:
        response_latency = time.perf_counter() - start_time
        mmap.measure_float_put(m_response_latency, response_latency)
        tmap = tag_map_module.TagMap()
        mmap.record(tmap)

Métricas ingeridas

Quando suas métricas são exportadas para o Cloud Monitoring, elas aparecem como tipos de métricas com um prefixo que indica que elas foram originadas do OpenCensus. Por exemplo, o nome de cada View do OpenCensus na implementação do Node.js é mapeado da seguinte maneira:

  • request_count_sli torna-se custom.googleapis.com/opencensus/request_count_sli.
  • error_count_sli torna-se custom.googleapis.com/opencensus/error_count_sli.
  • response_latency_sli torna-se custom.googleapis.com/opencensus/response_latency_sli.

Depois que o serviço estiver em execução, confirme se as métricas estão sendo processadas no Monitoring pesquisando-as no Metrics Explorer.

SLIs de disponibilidade

No Cloud Monitoring, você expressa um SLI de disponibilidade baseado em solicitação usando uma estrutura TimeSeriesRatio. O exemplo a seguir mostra um SLO que usa as métricas OpenCensus ingeridas e espera que o serviço tenha uma disponibilidade de 98%, conforme calculado por uma proporção de error_count_sli para request_count_sli, em um período de 28 dias consecutivos:

{
  "serviceLevelIndicator": {
    "requestBased": {
      "goodTotalRatio": {
        "totalServiceFilter":
          "metric.type=\"custom.googleapis.com/opencensus/request_count_sli\",
       "badServiceFilter":
          "metric.type=\"custom.googleapis.com/opencensus/error_count_sli\"
      }
    }
  },
  "goal": 0.98,
  "rollingPeriod": "2419200s",
  "displayName": "98% Availability, rolling 28 days"
}

SLIs de latência

No Cloud Monitoring, você expressa um SLI de latência baseado em solicitação usando uma estrutura DistributionCut. Neste exemplo, mostramos um SLO que usa a métrica de latência ingerida do OpenCensus e que espera que 98% das solicitações sejam concluídas em menos de 1.000 ms em um período de um dia:

{
  "serviceLevelIndicator": {
    "requestBased": {
      "distributionCut": {
        "distributionFilter":
          "metric.type=\"custom.googleapis.com/opencensus/response_latency_sli\",
        "range": {
          "min": 0,
          "max": 1000
        }
      }
    }
  },
  "goal": 0.98,
  "rollingPeriod": "86400s",
  "displayName": "98% requests under 1000 ms"
}