

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# OpenTelemetry 0.7.0 格式的 CloudWatch 指標串流輸出
<a name="CloudWatch-metric-streams-formats-opentelemetry"></a>

OpenTelemetry 是工具、API 和開發套件的集合。您可以使用它來檢測、產生、收集和匯出遙測資料 (指標、日誌和追蹤) 以進行分析。OpenTelemetry 隸屬於雲端原生運算基金會 (Cloud Native Computing Foundation)。如需詳細資訊，請參閱 [OpenTelemetry](https://opentelemetry.io/)。

如需完整的 OpenTelemetry 0.7.0 規格的資訊，請參閱 [v0.7.0 版](https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v0.7.0)。

Kinesis 記錄可包含一個或多個 `ExportMetricsServiceRequest` OpenTelemetry 資料結構。每個資料結構都以具有 `UnsignedVarInt32` 的標題為開頭，該標題可指示記錄長度 (以位元組為單位)。每個 `ExportMetricsServiceRequest` 可能一次包含來自多個指標的資料。

以下是 `ExportMetricsServiceRequest` OpenTelemetry 資料結構的訊息的字串表示法。OpenRelemetry 會序列化 Google 協定緩衝區二進位協定，且此結果人類不可讀取。

```
resource_metrics {
  resource {
    attributes {
      key: "cloud.provider"
      value {
        string_value: "aws"
      }
    }
    attributes {
      key: "cloud.account.id"
      value {
        string_value: "2345678901"
      }
    }
    attributes {
      key: "cloud.region"
      value {
        string_value: "us-east-1"
      }
    }
    attributes {
      key: "aws.exporter.arn"
      value {
        string_value: "arn:aws:cloudwatch:us-east-1:123456789012:metric-stream/MyMetricStream"
      }
    }
  }
  instrumentation_library_metrics {
    metrics {
      name: "amazonaws.com/AWS/DynamoDB/ConsumedReadCapacityUnits"
      unit: "1"
      double_summary {
        data_points {
          labels {
            key: "Namespace"
            value: "AWS/DynamoDB"
          }
          labels {
            key: "MetricName"
            value: "ConsumedReadCapacityUnits"
          }
          labels {
            key: "TableName"
            value: "MyTable"
          }
          start_time_unix_nano: 1604948400000000000
          time_unix_nano: 1604948460000000000
          count: 1
          sum: 1.0
          quantile_values {
            quantile: 0.0
            value: 1.0
          }
          quantile_values {
            quantile: 0.95
            value: 1.0
          }          
          quantile_values {
            quantile: 0.99
            value: 1.0
          }
          quantile_values {
            quantile: 1.0
            value: 1.0
          }
        }
        data_points {
          labels {
            key: "Namespace"
            value: "AWS/DynamoDB"
          }
          labels {
            key: "MetricName"
            value: "ConsumedReadCapacityUnits"
          }
          labels {
            key: "TableName"
            value: "MyTable"
          }
          start_time_unix_nano: 1604948460000000000
          time_unix_nano: 1604948520000000000
          count: 2
          sum: 5.0
          quantile_values {
            quantile: 0.0
            value: 2.0
          }
          quantile_values {
            quantile: 1.0
            value: 3.0
          }
        }
      }
    }
  }
}
```

**序列化 OpenTelemetry 指標資料的最上層物件**

`ExportMetricsServiceRequest` 是用於序列化 OpenTelemetry 匯出工具酬載的最上層包裝函式。它包含一個或多個 `ResourceMetrics`。

```
message ExportMetricsServiceRequest {
  // An array of ResourceMetrics.
  // For data coming from a single resource this array will typically contain one
  // element. Intermediary nodes (such as OpenTelemetry Collector) that receive
  // data from multiple origins typically batch the data before forwarding further and
  // in that case this array will contain multiple elements.
  repeated opentelemetry.proto.metrics.v1.ResourceMetrics resource_metrics = 1;
}
```

`ResourceMetrics` 是表示 MetricData 物件的最上層物件。

```
// A collection of InstrumentationLibraryMetrics from a Resource.
message ResourceMetrics {
  // The resource for the metrics in this message.
  // If this field is not set then no resource info is known.
  opentelemetry.proto.resource.v1.Resource resource = 1;
  
  // A list of metrics that originate from a resource.
  repeated InstrumentationLibraryMetrics instrumentation_library_metrics = 2;
}
```

**資源物件**

`Resource` 物件是值對物件，其中包含有關產生指標之資源的一些資訊。對於由 AWS建立的指標，資料結構包含與指標相關的資源的 Amazon Resource Name (ARN)，例如 EC2 執行個體或 S3 儲存貯體。

`Resource` 物件包含稱為 `attributes` 的屬性，其中會存放鍵/值對的清單。
+ `cloud.account.id` 包含帳戶 ID
+ `cloud.region` 包含區域
+ `aws.exporter.arn` 包含指標串流 ARN
+ `cloud.provider` 始終是 `aws`。

```
// Resource information.
message Resource {
  // Set of labels that describe the resource.
  repeated opentelemetry.proto.common.v1.KeyValue attributes = 1;
  
  // dropped_attributes_count is the number of dropped attributes. If the value is 0,
  // no attributes were dropped.
  uint32 dropped_attributes_count = 2;
}
```

**InstrumentationLibraryMetrics 物件**

instrumentation\$1library 欄位將不會被填充。我們將只填寫我們正在匯出的指標欄位。

```
// A collection of Metrics produced by an InstrumentationLibrary.
message InstrumentationLibraryMetrics {
  // The instrumentation library information for the metrics in this message.
  // If this field is not set then no library info is known.
  opentelemetry.proto.common.v1.InstrumentationLibrary instrumentation_library = 1;
  // A list of metrics that originate from an instrumentation library.
  repeated Metric metrics = 2;
}
```

**指標物件**

指標物件包含 `DoubleSummary` 資料欄位，其中包含 `DoubleSummaryDataPoint` 的清單。

```
message Metric {
  // name of the metric, including its DNS name prefix. It must be unique.
  string name = 1;

  // description of the metric, which can be used in documentation.
  string description = 2;

  // unit in which the metric value is reported. Follows the format
  // described by http://unitsofmeasure.org/ucum.html.
  string unit = 3;

  oneof data {
    IntGauge int_gauge = 4;
    DoubleGauge double_gauge = 5;
    IntSum int_sum = 6;
    DoubleSum double_sum = 7;
    IntHistogram int_histogram = 8;
    DoubleHistogram double_histogram = 9;
    DoubleSummary double_summary = 11;
  }
}

message DoubleSummary {
  repeated DoubleSummaryDataPoint data_points = 1;
}
```

**MetricDescriptor 物件**

MetricDescriptor 物件包含中繼資料。如需詳細資訊，請參閱 GitHub 上的 [metrics.proto](https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto#L110)。

針對指標串流，MetricDescriptor 具有下列內容：
+ `name` 將為 `amazonaws.com/metric_namespace/metric_name`
+ `description` 將為空白。
+ `unit` 可藉由將指標基準的單位映射至統一計量單位代碼的變體 (區分大小寫) 來進行填充。如需詳細資訊，請參閱 [CloudWatch 中 OpenTelemetry 0.7.0 格式的轉換](CloudWatch-metric-streams-formats-opentelemetry-translation.md) 和[統一計量單位代碼](https://ucum.org/ucum.html)。
+ `type` 將為 `SUMMARY`。

**DoubleSummaryDataPoint 物件**

DoubleSummaryDataPoint 物件包含 DoubleSummary 指標中的時間序列的單一資料點的值。

```
// DoubleSummaryDataPoint is a single data point in a timeseries that describes the
// time-varying values of a Summary metric.
message DoubleSummaryDataPoint {
  // The set of labels that uniquely identify this timeseries.
  repeated opentelemetry.proto.common.v1.StringKeyValue labels = 1;

  // start_time_unix_nano is the last time when the aggregation value was reset
  // to "zero". For some metric types this is ignored, see data types for more
  // details.
  //
  // The aggregation value is over the time interval (start_time_unix_nano,
  // time_unix_nano].
  //
  // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
  // 1970.
  //
  // Value of 0 indicates that the timestamp is unspecified. In that case the
  // timestamp may be decided by the backend.
  fixed64 start_time_unix_nano = 2;

  // time_unix_nano is the moment when this aggregation value was reported.
  //
  // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
  // 1970.
  fixed64 time_unix_nano = 3;

  // count is the number of values in the population. Must be non-negative.
  fixed64 count = 4;

  // sum of the values in the population. If count is zero then this field
  // must be zero.
  double sum = 5;

  // Represents the value at a given quantile of a distribution.
  //
  // To record Min and Max values following conventions are used:
  // - The 1.0 quantile is equivalent to the maximum value observed.
  // - The 0.0 quantile is equivalent to the minimum value observed.
  message ValueAtQuantile {
    // The quantile of a distribution. Must be in the interval
    // [0.0, 1.0].
    double quantile = 1;

    // The value at the given quantile of a distribution.
    double value = 2;
  }

  // (Optional) list of values at different quantiles of the distribution calculated
  // from the current snapshot. The quantiles must be strictly increasing.
  repeated ValueAtQuantile quantile_values = 6;
}
```

如需詳細資訊，請參閱[CloudWatch 中 OpenTelemetry 0.7.0 格式的轉換](CloudWatch-metric-streams-formats-opentelemetry-translation.md)。

# CloudWatch 中 OpenTelemetry 0.7.0 格式的轉換
<a name="CloudWatch-metric-streams-formats-opentelemetry-translation"></a>

CloudWatch 執行一些轉換，將 CloudWatch 資料轉換為 OpenTelemetry 格式。

**轉換命名空間、指標名稱和維度**

這些屬性是在映射中編碼的鍵值對。
+ 一對包含指標的命名空間
+ 一對包含指標的名稱
+ 對於每個維度，CloudWatch 會存放下列配對：`metricDatum.Dimensions[i].Name, metricDatum.Dimensions[i].Value`

**轉換平均值、總和、樣本計數、最小值和最大值**

摘要資料點可讓 CloudWatch 使用一個資料點匯出所有這些統計資料。
+ `startTimeUnixNano` 包含 CloudWatch `startTime`
+ `timeUnixNano` 包含 CloudWatch `endTime`
+ `sum` 包含總和統計資料。
+ `count` 包含 SampleCount 統計資料。
+ `quantile_values` 包含兩個 `valueAtQuantile.value` 物件：
  + `valueAtQuantile.quantile = 0.0` 取代為 `valueAtQuantile.value = Min value`
  + `valueAtQuantile.quantile = 0.99` 取代為 `valueAtQuantile.value = p99 value`
  + `valueAtQuantile.quantile = 0.999` 取代為 `valueAtQuantile.value = p99.9 value`
  + `valueAtQuantile.quantile = 1.0` 取代為 `valueAtQuantile.value = Max value`

消耗指標串流的資源可以將「平均」統計數字計算為 **Sum/SampleCount**。

**轉換單位**

CloudWatch 單位可映射至統一計量單位代碼的變體 (區分大小寫)，如下表所示。如需詳細資訊，請參閱[統一計量單位代碼](https://ucum.org/ucum.html)。


| CloudWatch | OpenTelemetry | 
| --- | --- | 
|  秒 |  s | 
|  秒或秒 |  s | 
|  微秒 |  us | 
|  毫秒 |  ms | 
|  位元組 |  By | 
|  KB |  kBy | 
|  MB |  MBy | 
|  GB |  GBy | 
|  TB |  TBy | 
|  位元 |  bit | 
|  千位元數 |  kbit | 
|  百萬位元數 |  MBit | 
|  十億位元數 |  GBit | 
|  兆位元數 |  Tbit | 
|  百分比 |  % | 
|  計數 |  \$1Count\$1 | 
|  無 |  1 | 

透過套用兩個單位的 OpenTelemetry 轉換來映射與斜線結合的單位。例如，位元組/秒映射為 By/s。

# 如何剖析 OpenTelemetry 0.7.0 訊息
<a name="CloudWatch-metric-streams-formats-opentelemetry-parse"></a>

本節提供資訊，可協助您開始剖析 OpenTelemetry 0.7.0.。

首先，您應該取得特定語言的連結，讓您能夠以偏好的語言剖析 OpenTelemetry 0.7.0 訊息。

**若要取得特定語言的連結**
+ 步驟取決於您偏好的語言。
  + 若要使用 Java，請將下列 Maven 相依性新增到您的 Java 專案： [OpenTelemetry Java >> 0.14.1](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-proto/0.14.1)。
  + 若要使用任何其他語言，請依照下列步驟執行：

    1. 確定已支援您的語言，方法是檢查[產生您的類別](https://developers.google.com/protocol-buffers/docs/proto3#generating)的清單。

    1. 依照[下載協定緩衝區](https://developers.google.com/protocol-buffers/docs/downloads)上的步驟安裝 Protobuf 編譯器。

    1. 下載 [v0.7.0 版](https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v0.7.0) OpenTelemetry 0.7.0 ProtoBuf 定義。

    1. 確認您位於已下載 OpenTelemetry 0.7.0 ProtoBuf 定義的根資料夾中。隨後依序建立 `src` 資料夾，並執行命令以產生特定語言的綁定。如需詳細資訊，請參閱[產生您的類別](https://developers.google.com/protocol-buffers/docs/proto3#generating)。

       下列是如何產生 Javascript 連結的範例。

       ```
       protoc --proto_path=./ --js_out=import_style=commonjs,binary:src \
       opentelemetry/proto/common/v1/common.proto \
       opentelemetry/proto/resource/v1/resource.proto \
       opentelemetry/proto/metrics/v1/metrics.proto \
       opentelemetry/proto/collector/metrics/v1/metrics_service.proto
       ```

下列章節包含使用特定語言的連結的範例，您可以依照先前指示建置相關連結。

**Java**

```
package com.example;

import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class MyOpenTelemetryParser {

    public List<ExportMetricsServiceRequest> parse(InputStream inputStream) throws IOException {
        List<ExportMetricsServiceRequest> result = new ArrayList<>();

        ExportMetricsServiceRequest request;
        /* A Kinesis record can contain multiple `ExportMetricsServiceRequest`
           records, each of them starting with a header with an
           UnsignedVarInt32 indicating the record length in bytes:
            ------ --------------------------- ------ -----------------------
           |UINT32|ExportMetricsServiceRequest|UINT32|pExportMetricsService...
            ------ --------------------------- ------ -----------------------
         */
        while ((request = ExportMetricsServiceRequest.parseDelimitedFrom(inputStream)) != null) {
            // Do whatever we want with the parsed message
            result.add(request);
        }

        return result;
    }
}
```

**Javascript**

此範例假設已產生連結的根資料夾為 `./`

函數的資料引數 `parseRecord` 可為下列其中一種類型：
+ `Uint8Array` 這是最佳的
+ `Buffer` 在節點下最佳
+ `Array.number` 8 位元整數

```
const pb = require('google-protobuf')
const pbMetrics =
    require('./opentelemetry/proto/collector/metrics/v1/metrics_service_pb')

function parseRecord(data) {
    const result = []

    // Loop until we've read all the data from the buffer
    while (data.length) {
        /* A Kinesis record can contain multiple `ExportMetricsServiceRequest`
           records, each of them starting with a header with an
           UnsignedVarInt32 indicating the record length in bytes:
            ------ --------------------------- ------ -----------------------
           |UINT32|ExportMetricsServiceRequest|UINT32|ExportMetricsService...
            ------ --------------------------- ------ -----------------------
         */
        const reader = new pb.BinaryReader(data)
        const messageLength = reader.decoder_.readUnsignedVarint32()
        const messageFrom = reader.decoder_.cursor_
        const messageTo = messageFrom + messageLength

        // Extract the current `ExportMetricsServiceRequest` message to parse
        const message = data.subarray(messageFrom, messageTo)

        // Parse the current message using the ProtoBuf library
        const parsed =
            pbMetrics.ExportMetricsServiceRequest.deserializeBinary(message)

        // Do whatever we want with the parsed message
        result.push(parsed.toObject())

        // Shrink the remaining buffer, removing the already parsed data
        data = data.subarray(messageTo)
    }

    return result
}
```

**Python**

您必須自行閱讀 `var-int` 分隔符或使用內部方法 `_VarintBytes(size)` 和 `_DecodeVarint32(buffer, position)`。這些傳回緩衝區中的位置恰好在大小位元組之後。讀取端可構造一個新的緩衝區，且僅限於讀取訊息的位元組。

```
size = my_metric.ByteSize()
f.write(_VarintBytes(size))
f.write(my_metric.SerializeToString())
msg_len, new_pos = _DecodeVarint32(buf, 0)
msg_buf = buf[new_pos:new_pos+msg_len]
request = metrics_service_pb.ExportMetricsServiceRequest()
request.ParseFromString(msg_buf)
```

**Go**

請使用 `Buffer.DecodeMessage()`。

**C\$1**

請使用 `CodedInputStream`。該列表可以讀取以大小分隔的訊息。

**C\$1\$1**

`google/protobuf/util/delimited_message_util.h` 中描述的函數可以讀取以大小分隔的訊息。

**其他語言**

如需其他語言，請參閱[下載協定緩衝區](https://developers.google.com/protocol-buffers/docs/downloads)。

實作剖析器時，請考慮 Kinesis 記錄可以包含多個 `ExportMetricsServiceRequest` 協定緩衝區訊息，每個訊息都以具有 `UnsignedVarInt32` 的標題為開頭，而該標題可指示記錄長度 (以位元組為單位)。