// Copyright (c) 2021 The Jaeger Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Based on: https://github.com/open-telemetry/opentelemetry-proto/blob/v0.8.0/opentelemetry/proto/metrics/v1/metrics.proto

syntax="proto3";

package jaeger.api_v2.metrics;

import "gogoproto/gogo.proto";

option go_package = "metrics";
option java_package = "io.jaegertracing.api_v2.metrics";

// Enable gogoprotobuf extensions (https://github.com/gogo/protobuf/blob/master/extensions.md).
// Enable custom Marshal method.
option (gogoproto.marshaler_all) = true;
// Enable custom Unmarshal method.
option (gogoproto.unmarshaler_all) = true;
// Enable custom Size method (Required by Marshal and Unmarshal).
option (gogoproto.sizer_all) = true;

// StringKeyValue is a pair of key/value strings. This is the simpler (and faster) version
// of KeyValue that only supports string values.
message StringKeyValue {
  string key = 1;
  string value = 2;
}

// Defines a Metric which has one or more timeseries.
//
// The data model and relation between entities is shown in the
// diagram below. Here, "DataPoint" is the term used to refer to any
// one of the specific data point value types, and "points" is the term used
// to refer to any one of the lists of points contained in the Metric.
//
// - Metric is composed of a metadata and data.
// - Metadata part contains a name, description, unit.
// - Data is one of the possible types (Gauge, Sum, Histogram, etc.).
// - DataPoint contains timestamps, labels, and one of the possible value type
//   fields.
//
//     Metric
//  +------------+
//  |name        |
//  |description |
//  |unit        |     +------------------------------------+
//  |data        |---> |Gauge, Sum, Histogram, Summary, ... |
//  +------------+     +------------------------------------+
//
//    Data [One of Gauge, Sum, Histogram, Summary, ...]
//  +-----------+
//  |...        |  // Metadata about the Data.
//  |points     |--+
//  +-----------+  |
//                 |      +---------------------------+
//                 |      |DataPoint 1                |
//                 v      |+------+------+   +------+ |
//              +-----+   ||label |label |...|label | |
//              |  1  |-->||value1|value2|...|valueN| |
//              +-----+   |+------+------+   +------+ |
//              |  .  |   |+-----+                    |
//              |  .  |   ||value|                    |
//              |  .  |   |+-----+                    |
//              |  .  |   +---------------------------+
//              |  .  |                   .
//              |  .  |                   .
//              |  .  |                   .
//              |  .  |   +---------------------------+
//              |  .  |   |DataPoint M                |
//              +-----+   |+------+------+   +------+ |
//              |  M  |-->||label |label |...|label | |
//              +-----+   ||value1|value2|...|valueN| |
//                        |+------+------+   +------+ |
//                        |+-----+                    |
//                        ||value|                    |
//                        |+-----+                    |
//                        +---------------------------+
//
// All DataPoint types have three common fields:
// - Labels zero or more key-value pairs associated with the data point.
// - StartTimeUnixNano MUST be set to the start of the interval when the data's
//   type includes an AggregationTemporality. This field is not set otherwise.
// - TimeUnixNano MUST be set to:
//   - the moment when an aggregation is reported (independent of the
//     aggregation temporality).
//   - the instantaneous time of the event.
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;

  // TODO: Decide if support for RawMeasurements (measurements recorded using
  // the synchronous instruments) is necessary. It can be used to delegate the
  // aggregation from the application to the agent/collector. See
  // https://github.com/open-telemetry/opentelemetry-specification/issues/617

  // Data determines the aggregation type (if any) of the metric, what is the
  // reported value type for the data points, as well as the relationship to
  // the time interval over which they are reported.
  oneof data {
    // IntGauge and IntSum are deprecated and will be removed soon.
    // 1. Old senders and receivers that are not aware of this change will
    // continue using the `int_gauge` and `int_sum` fields.
    // 2. New senders, which are aware of this change MUST send only `gauge`
    // and `sum` fields.
    // 3. New receivers, which are aware of this change MUST convert these into
    // `gauge` and `sum` by using the provided as_int field in the oneof values.
    // This field will be removed in ~3 months, on July 1, 2021.
    IntGauge int_gauge = 4 [deprecated = true];
    Gauge gauge = 5;
    // This field will be removed in ~3 months, on July 1, 2021.
    IntSum int_sum = 6 [deprecated = true];
    Sum sum = 7;

    // IntHistogram is deprecated and will be removed soon.
    // 1. Old senders and receivers that are not aware of this change will
    // continue using the `int_histogram` field.
    // 2. New senders, which are aware of this change MUST send only `histogram`.
    // 3. New receivers, which are aware of this change MUST convert this into
    // `histogram` by simply converting all int64 values into float.
    // This field will be removed in ~3 months, on July 1, 2021.
    IntHistogram int_histogram = 8 [deprecated = true];
    Histogram histogram = 9;
    Summary summary = 11;
  }
}

// IntGauge is deprecated.  Use Gauge with an integer value in NumberDataPoint.
//
// IntGauge represents the type of a int scalar metric that always exports the
// "current value" for every data point. It should be used for an "unknown"
// aggregation.
//
// A Gauge does not support different aggregation temporalities. Given the
// aggregation is unknown, points cannot be combined using the same
// aggregation, regardless of aggregation temporalities. Therefore,
// AggregationTemporality is not included. Consequently, this also means
// "StartTimeUnixNano" is ignored for all data points.
message IntGauge {
  option deprecated = true;

  repeated IntDataPoint data_points = 1;
}

// Gauge represents the type of a double scalar metric that always exports the
// "current value" for every data point. It should be used for an "unknown"
// aggregation.
//
// A Gauge does not support different aggregation temporalities. Given the
// aggregation is unknown, points cannot be combined using the same
// aggregation, regardless of aggregation temporalities. Therefore,
// AggregationTemporality is not included. Consequently, this also means
// "StartTimeUnixNano" is ignored for all data points.
message Gauge {
  repeated NumberDataPoint data_points = 1;
}

// IntSum is deprecated.  Use Sum with an integer value in NumberDataPoint.
//
// IntSum represents the type of a numeric int scalar metric that is calculated as
// a sum of all reported measurements over a time interval.
message IntSum {
  option deprecated = true;

  repeated IntDataPoint data_points = 1;

  // aggregation_temporality describes if the aggregator reports delta changes
  // since last report time, or cumulative changes since a fixed start time.
  AggregationTemporality aggregation_temporality = 2;

  // If "true" means that the sum is monotonic.
  bool is_monotonic = 3;
}

// Sum represents the type of a numeric double scalar metric that is calculated
// as a sum of all reported measurements over a time interval.
message Sum {
  repeated NumberDataPoint data_points = 1;

  // aggregation_temporality describes if the aggregator reports delta changes
  // since last report time, or cumulative changes since a fixed start time.
  AggregationTemporality aggregation_temporality = 2;

  // If "true" means that the sum is monotonic.
  bool is_monotonic = 3;
}

// IntHistogram is deprecated, replaced by Histogram points using double-
// valued exemplars.
//
// This represents the type of a metric that is calculated by aggregating as a
// Histogram of all reported int measurements over a time interval.
message IntHistogram {
  option deprecated = true;

  repeated IntHistogramDataPoint data_points = 1;

  // aggregation_temporality describes if the aggregator reports delta changes
  // since last report time, or cumulative changes since a fixed start time.
  AggregationTemporality aggregation_temporality = 2;
}

// Histogram represents the type of a metric that is calculated by aggregating as a
// Histogram of all reported double measurements over a time interval.
message Histogram {
  repeated HistogramDataPoint data_points = 1;

  // aggregation_temporality describes if the aggregator reports delta changes
  // since last report time, or cumulative changes since a fixed start time.
  AggregationTemporality aggregation_temporality = 2;
}

// Summary metric data are used to convey quantile summaries,
// a Prometheus (see: https://prometheus.io/docs/concepts/metric_types/#summary)
// and OpenMetrics (see: https://github.com/OpenObservability/OpenMetrics/blob/4dbf6075567ab43296eed941037c12951faafb92/protos/prometheus.proto#L45)
// data type. These data points cannot always be merged in a meaningful way.
// While they can be useful in some applications, histogram data points are
// recommended for new applications.
message Summary {
  repeated SummaryDataPoint data_points = 1;
}

// AggregationTemporality defines how a metric aggregator reports aggregated
// values. It describes how those values relate to the time interval over
// which they are aggregated.
enum AggregationTemporality {
  // UNSPECIFIED is the default AggregationTemporality, it MUST not be used.
  AGGREGATION_TEMPORALITY_UNSPECIFIED = 0;

  // DELTA is an AggregationTemporality for a metric aggregator which reports
  // changes since last report time. Successive metrics contain aggregation of
  // values from continuous and non-overlapping intervals.
  //
  // The values for a DELTA metric are based only on the time interval
  // associated with one measurement cycle. There is no dependency on
  // previous measurements like is the case for CUMULATIVE metrics.
  //
  // For example, consider a system measuring the number of requests that
  // it receives and reports the sum of these requests every second as a
  // DELTA metric:
  //
  //   1. The system starts receiving at time=t_0.
  //   2. A request is received, the system measures 1 request.
  //   3. A request is received, the system measures 1 request.
  //   4. A request is received, the system measures 1 request.
  //   5. The 1 second collection cycle ends. A metric is exported for the
  //      number of requests received over the interval of time t_0 to
  //      t_0+1 with a value of 3.
  //   6. A request is received, the system measures 1 request.
  //   7. A request is received, the system measures 1 request.
  //   8. The 1 second collection cycle ends. A metric is exported for the
  //      number of requests received over the interval of time t_0+1 to
  //      t_0+2 with a value of 2.
  AGGREGATION_TEMPORALITY_DELTA = 1;

  // CUMULATIVE is an AggregationTemporality for a metric aggregator which
  // reports changes since a fixed start time. This means that current values
  // of a CUMULATIVE metric depend on all previous measurements since the
  // start time. Because of this, the sender is required to retain this state
  // in some form. If this state is lost or invalidated, the CUMULATIVE metric
  // values MUST be reset and a new fixed start time following the last
  // reported measurement time sent MUST be used.
  //
  // For example, consider a system measuring the number of requests that
  // it receives and reports the sum of these requests every second as a
  // CUMULATIVE metric:
  //
  //   1. The system starts receiving at time=t_0.
  //   2. A request is received, the system measures 1 request.
  //   3. A request is received, the system measures 1 request.
  //   4. A request is received, the system measures 1 request.
  //   5. The 1 second collection cycle ends. A metric is exported for the
  //      number of requests received over the interval of time t_0 to
  //      t_0+1 with a value of 3.
  //   6. A request is received, the system measures 1 request.
  //   7. A request is received, the system measures 1 request.
  //   8. The 1 second collection cycle ends. A metric is exported for the
  //      number of requests received over the interval of time t_0 to
  //      t_0+2 with a value of 5.
  //   9. The system experiences a fault and loses state.
  //   10. The system recovers and resumes receiving at time=t_1.
  //   11. A request is received, the system measures 1 request.
  //   12. The 1 second collection cycle ends. A metric is exported for the
  //      number of requests received over the interval of time t_1 to
  //      t_0+1 with a value of 1.
  //
  // Note: Even though, when reporting changes since last report time, using
  // CUMULATIVE is valid, it is not recommended. This may cause problems for
  // systems that do not use start_time to determine when the aggregation
  // value was reset (e.g. Prometheus).
  AGGREGATION_TEMPORALITY_CUMULATIVE = 2;
}

// IntDataPoint is a single data point in a timeseries that describes the
// time-varying values of a int64 metric.
message IntDataPoint {
  option deprecated = true;

  // The set of labels that uniquely identify this timeseries.
  repeated 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;

  // value itself.
  sfixed64 value = 4;

  // (Optional) List of exemplars collected from
  // measurements that were used to form the data point
  repeated IntExemplar exemplars = 5;
}

// NumberDataPoint is a single data point in a timeseries that describes the
// time-varying value of a double metric.
message NumberDataPoint {
  // The set of labels that uniquely identify this timeseries.
  repeated 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;

  // The value itself.  A point is considered invalid when one of the recognized
  // value fields is not present inside this oneof.
  oneof value {
    double as_double = 4;
    sfixed64 as_int = 6;
  }

  // (Optional) List of exemplars collected from
  // measurements that were used to form the data point
  repeated Exemplar exemplars = 5;
}

// IntHistogramDataPoint is deprecated; use HistogramDataPoint.
//
// This is a single data point in a timeseries that describes
// the time-varying values of a Histogram of int values. A Histogram contains
// summary statistics for a population of values, it may optionally contain
// the distribution of those values across a set of buckets.
//
// If the histogram contains the distribution of values, then both
// "explicit_bounds" and "bucket counts" fields must be defined.
// If the histogram does not contain the distribution of values, then both
// "explicit_bounds" and "bucket_counts" must be omitted and only "count" and
// "sum" are known.
message IntHistogramDataPoint {
  option deprecated = true;

  // The set of labels that uniquely identify this timeseries.
  repeated 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. This
  // value must be equal to the sum of the "count" fields in buckets if a
  // histogram is provided.
  fixed64 count = 4;

  // sum of the values in the population. If count is zero then this field
  // must be zero. This value must be equal to the sum of the "sum" fields in
  // buckets if a histogram is provided.
  sfixed64 sum = 5;

  // bucket_counts is an optional field contains the count values of histogram
  // for each bucket.
  //
  // The sum of the bucket_counts must equal the value in the count field.
  //
  // The number of elements in bucket_counts array must be by one greater than
  // the number of elements in explicit_bounds array.
  repeated fixed64 bucket_counts = 6;

  // explicit_bounds specifies buckets with explicitly defined bounds for values.
  //
  // This defines size(explicit_bounds) + 1 (= N) buckets. The boundaries for
  // bucket at index i are:
  //
  // (-infinity, explicit_bounds[i]] for i == 0
  // (explicit_bounds[i-1], explicit_bounds[i]] for 0 < i < N-1
  // (explicit_bounds[i], +infinity) for i == N-1
  //
  // The values in the explicit_bounds array must be strictly increasing.
  //
  // Histogram buckets are inclusive of their upper boundary, except the last
  // bucket where the boundary is at infinity. This format is intentionally
  // compatible with the OpenMetrics histogram definition.
  repeated double explicit_bounds = 7;

  // (Optional) List of exemplars collected from
  // measurements that were used to form the data point
  repeated IntExemplar exemplars = 8;
}

// HistogramDataPoint is a single data point in a timeseries that describes the
// time-varying values of a Histogram of double values. A Histogram contains
// summary statistics for a population of values, it may optionally contain the
// distribution of those values across a set of buckets.
//
// If the histogram contains the distribution of values, then both
// "explicit_bounds" and "bucket counts" fields must be defined.
// If the histogram does not contain the distribution of values, then both
// "explicit_bounds" and "bucket_counts" must be omitted and only "count" and
// "sum" are known.
message HistogramDataPoint {
  // The set of labels that uniquely identify this timeseries.
  repeated 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. This
  // value must be equal to the sum of the "count" fields in buckets if a
  // histogram is provided.
  fixed64 count = 4;

  // sum of the values in the population. If count is zero then this field
  // must be zero. This value must be equal to the sum of the "sum" fields in
  // buckets if a histogram is provided.
  double sum = 5;

  // bucket_counts is an optional field contains the count values of histogram
  // for each bucket.
  //
  // The sum of the bucket_counts must equal the value in the count field.
  //
  // The number of elements in bucket_counts array must be by one greater than
  // the number of elements in explicit_bounds array.
  repeated fixed64 bucket_counts = 6;

  // explicit_bounds specifies buckets with explicitly defined bounds for values.
  //
  // This defines size(explicit_bounds) + 1 (= N) buckets. The boundaries for
  // bucket at index i are:
  //
  // (-infinity, explicit_bounds[i]] for i == 0
  // (explicit_bounds[i-1], explicit_bounds[i]] for 0 < i < N-1
  // (explicit_bounds[i], +infinity) for i == N-1
  //
  // The values in the explicit_bounds array must be strictly increasing.
  //
  // Histogram buckets are inclusive of their upper boundary, except the last
  // bucket where the boundary is at infinity. This format is intentionally
  // compatible with the OpenMetrics histogram definition.
  repeated double explicit_bounds = 7;

  // (Optional) List of exemplars collected from
  // measurements that were used to form the data point
  repeated Exemplar exemplars = 8;
}

// SummaryDataPoint is a single data point in a timeseries that describes the
// time-varying values of a Summary metric.
message SummaryDataPoint {
  // The set of labels that uniquely identify this timeseries.
  repeated 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.
  //
  // See the following issue for more context:
  // https://github.com/open-telemetry/opentelemetry-proto/issues/125
  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;
}

// A representation of an exemplar, which is a sample input int measurement.
// Exemplars also hold information about the environment when the measurement
// was recorded, for example the span and trace ID of the active span when the
// exemplar was recorded.
message IntExemplar {
  option deprecated = true;

  // The set of labels that were filtered out by the aggregator, but recorded
  // alongside the original measurement. Only labels that were filtered out
  // by the aggregator should be included
  repeated StringKeyValue filtered_labels = 1;

  // time_unix_nano is the exact time when this exemplar was recorded
  //
  // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
  // 1970.
  fixed64 time_unix_nano = 2;

  // Numerical int value of the measurement that was recorded.
  sfixed64 value = 3;

  // (Optional) Span ID of the exemplar trace.
  // span_id may be missing if the measurement is not recorded inside a trace
  // or if the trace is not sampled.
  bytes span_id = 4;

  // (Optional) Trace ID of the exemplar trace.
  // trace_id may be missing if the measurement is not recorded inside a trace
  // or if the trace is not sampled.
  bytes trace_id = 5;
}

// A representation of an exemplar, which is a sample input measurement.
// Exemplars also hold information about the environment when the measurement
// was recorded, for example the span and trace ID of the active span when the
// exemplar was recorded.
message Exemplar {
  // The set of labels that were filtered out by the aggregator, but recorded
  // alongside the original measurement. Only labels that were filtered out
  // by the aggregator should be included
  repeated StringKeyValue filtered_labels = 1;

  // time_unix_nano is the exact time when this exemplar was recorded
  //
  // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
  // 1970.
  fixed64 time_unix_nano = 2;

  // Numerical value of the measurement that was recorded. An exemplar is
  // considered invalid when one of the recognized value fields is not present
  // inside this oneof.
  oneof value {
    double as_double = 3;
    sfixed64 as_int = 6;
  }

  // (Optional) Span ID of the exemplar trace.
  // span_id may be missing if the measurement is not recorded inside a trace
  // or if the trace is not sampled.
  bytes span_id = 4;

  // (Optional) Trace ID of the exemplar trace.
  // trace_id may be missing if the measurement is not recorded inside a trace
  // or if the trace is not sampled.
  bytes trace_id = 5;
}