syntax = "proto3";

package metrics;

option go_package = "go.k6.io/k6/output/cloud/expv2/pbcloud";

import "google/protobuf/timestamp.proto";

// The type of a Metric.
enum MetricType {
  // Metric of type METRICTYPE_UNSPECIFIED declared, but not allowed.
  // See: https://protobuf.dev/programming-guides/dos-donts/#do-include-an-unspecified-value-in-an-enum.
  METRIC_TYPE_UNSPECIFIED = 0;
  METRIC_TYPE_COUNTER = 1;
  METRIC_TYPE_GAUGE = 2;
  METRIC_TYPE_RATE = 3;
  METRIC_TYPE_TREND = 4;
}

// MetricSet is the top-level container type
// that is encoded and sent over the wire.
message MetricSet {
  // Required.
  string test_run_id = 1;

  // Required.
  // time bucket size in seconds
  uint32 aggregation_period = 2;

  // Required.
  repeated Metric metrics = 3;
}

message Metric {
  // Required.
  string name = 1;

  // Required.
  // Can't be of type MetricType.METRICTYPE_UNSPECIFIED (which is zero value).
  MetricType type = 2;

  // Optional.
  repeated TimeSeries time_series = 3;
}

// Label is a name-value pair.
message Label {
  // Required.
  string name = 1;

  // Required.
  string value = 2;
}

// TimeSeries is a single metric with a unique set of labels.
message TimeSeries {
  // Optional.
  repeated Label labels = 1;

  // Required.
  oneof samples {
    CounterSamples counter_samples = 2;
    GaugeSamples gauge_samples = 3;
    RateSamples rate_samples = 4;
    TrendHdrSamples trend_hdr_samples = 5;
  }
}

message CounterSamples {
  // Required.
  repeated CounterValue values = 1;
}

message GaugeSamples {
  // Required.
  repeated GaugeValue values = 1;
}

message RateSamples {
  // Required.
  repeated RateValue values = 1;
}

message TrendHdrSamples {
  // Required.
  repeated TrendHdrValue values = 1;
}

message CounterValue {
  // Required.
  google.protobuf.Timestamp time = 1;

  double value = 2;
}

message GaugeValue {
  // Required.
  google.protobuf.Timestamp time = 1;

  // last observed value
  double last = 2;
  // count of observations
  uint32 count = 3;
  // min, max, and average of observed values
  double min = 4;
  double max = 5;
  double avg = 6;
}

message RateValue {
  // Required.
  google.protobuf.Timestamp time = 1;

  uint32 nonzero_count = 2;
  uint32 total_count = 3;
}

// BucketSpan represents the consecutive and significant (non-zero) buckets.
// The concept is imported from the Prometheus' native histogram.
// It should simplify an eventual transition to Prometheus.
// https://github.com/prometheus/prometheus/blob/f399f386cef3b19c48157e9678a4f50997db3f41/prompb/io/prometheus/client/metrics.proto#L115-L124
message BucketSpan {
  uint32 offset = 1; // Gap to previous span, or starting point for 1st span.
  uint32 length = 2; // Length of the next consecutive buckets.
}

message TrendHdrValue {
  // Required.
  google.protobuf.Timestamp time = 1;

  // positive buckets starting from bucket 1, each counter is an absolute value.
  repeated uint32 counters = 2;
  repeated BucketSpan spans = 3;

  // sum of observations
  double sum = 5;
  // count of observations
  uint32 count = 6;
  // smallest and largest observed value
  double min_value = 7;
  double max_value = 8;

  // counters for zero- and infinity-buckets
  optional uint32 extra_low_values_counter = 9;
  optional uint32 extra_high_values_counter = 10;

  // min_resolution is a multiplier factor applied to the tracked values of the histogram.
  // It is helpful for up and down scaling values and representing different orders of magnitude.
  // default = 1.0
  double min_resolution = 11;

  // histogram parameter - number of significant digits used to calculate buckets formula
  // default = 2
  optional uint32 significant_digits = 12;
}
