// Copyright 2019, OpenTelemetry 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.

syntax = "proto3";

package opentelemetry.proto.metrics.v1;

import "opentelemetry/proto/common/v1/common.proto";
import "opentelemetry/proto/resource/v1/resource.proto";

option java_multiple_files = true;
option java_package = "io.opentelemetry.proto.metrics.firehose.v0_7";
option java_outer_classname = "MetricsProto";
option go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1";

// 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;
}

// A collection of Metrics produced by an InstrumentationLibrary.
message InstrumentationLibraryMetrics {
  // The instrumentation library information for the metrics in this message.
  // Semantically when InstrumentationLibrary isn't set, it is equivalent with
  // an empty instrumentation library name (unknown).
  opentelemetry.proto.common.v1.InstrumentationLibrary instrumentation_library = 1;

  // A list of metrics that originate from an instrumentation library.
  repeated Metric metrics = 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 relatationship to
  // the time interval over which they are reported.
  //
  // TODO: Update table after the decision on:
  // https://github.com/open-telemetry/opentelemetry-specification/issues/731.
  // By default, metrics recording using the OpenTelemetry API are exported as
  // (the table does not include MeasurementValueType to avoid extra rows):
  //
  //   Instrument         Type
  //   ----------------------------------------------
  //   Counter            Sum(aggregation_temporality=delta;is_monotonic=true)
  //   UpDownCounter      Sum(aggregation_temporality=delta;is_monotonic=false)
  //   ValueRecorder      TBD
  //   SumObserver        Sum(aggregation_temporality=cumulative;is_monotonic=true)
  //   UpDownSumObserver  Sum(aggregation_temporality=cumulative;is_monotonic=false)
  //   ValueObserver      Gauge()
  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;
  }
}

// Gauge 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 {
  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 DoubleGauge {
  repeated DoubleDataPoint data_points = 1;
}

// Sum 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 {
  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 DoubleSum {
  repeated DoubleDataPoint 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;
}

// 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 {
  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;
}

// Represents the type of a metric that is calculated by aggregating as a
// Histogram of all reported double measurements over a time interval.
message DoubleHistogram {
  repeated DoubleHistogramDataPoint 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;
}

// DoubleSummary 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 DoubleSummary {
  repeated DoubleSummaryDataPoint 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 {
  // 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;

  // value itself.
  sfixed64 value = 4;

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

// DoubleDataPoint is a single data point in a timeseries that describes the
// time-varying value of a double metric.
message DoubleDataPoint {
  // 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;

  // value itself.
  double value = 4;

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

// IntHistogramDataPoint 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.
message IntHistogramDataPoint {
  // 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. 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;

  // A histogram may optionally contain the distribution of the values in the population.
  // In that case one of the option fields below and "buckets" field both must be defined.
  // Otherwise all option fields and "buckets" field must be omitted in which case the
  // distribution of values in the histogram is unknown and only the total count and sum are known.

  // explicit_bounds is the only supported bucket option currently.
  // TODO: Add more bucket options.

  // explicit_bounds specifies buckets with explicitly defined bounds for values.
  // The bucket boundaries are described by "bounds" field.
  //
  // This defines size(bounds) + 1 (= N) buckets. The boundaries for bucket
  // at index i are:
  //
  // (-infinity, bounds[i]) for i == 0
  // [bounds[i-1], bounds[i]) for 0 < i < N-1
  // [bounds[i], +infinity) for i == N-1
  // The values in bounds array must be strictly increasing.
  //
  // Note: only [a, b) intervals are currently supported for each bucket except the first one.
  // If we decide to also support (a, b] intervals we should add support for these by defining
  // a boolean value which decides what type of intervals to use.
  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.
message DoubleHistogramDataPoint {
  // 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. 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;

  // A histogram may optionally contain the distribution of the values in the population.
  // In that case one of the option fields below and "buckets" field both must be defined.
  // Otherwise all option fields and "buckets" field must be omitted in which case the
  // distribution of values in the histogram is unknown and only the total count and sum are known.

  // explicit_bounds is the only supported bucket option currently.
  // TODO: Add more bucket options.

  // explicit_bounds specifies buckets with explicitly defined bounds for values.
  // The bucket boundaries are described by "bounds" field.
  //
  // This defines size(bounds) + 1 (= N) buckets. The boundaries for bucket
  // at index i are:
  //
  // (-infinity, bounds[i]) for i == 0
  // [bounds[i-1], bounds[i]) for 0 < i < N-1
  // [bounds[i], +infinity) for i == N-1
  // The values in bounds array must be strictly increasing.
  //
  // Note: only [a, b) intervals are currently supported for each bucket except the first one.
  // If we decide to also support (a, b] intervals we should add support for these by defining
  // a boolean value which decides what type of intervals to use.
  repeated double explicit_bounds = 7;

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

// 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.
  //
  // 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 {
  // 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 opentelemetry.proto.common.v1.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 double 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 DoubleExemplar {
  // 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 opentelemetry.proto.common.v1.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 double value of the measurement that was recorded.
  double 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;
}
