syntax = "proto3";

package cortex;

option go_package = "client";

import "github.com/gogo/protobuf/gogoproto/gogo.proto";

option (gogoproto.marshaler_all) = true;
option (gogoproto.unmarshaler_all) = true;

service Ingester {
  rpc Push(WriteRequest) returns (WriteResponse) {};
  rpc Query(QueryRequest) returns (QueryResponse) {};
  rpc QueryStream(QueryRequest) returns (stream QueryStreamResponse) {};

  rpc LabelValues(LabelValuesRequest) returns (LabelValuesResponse) {};
  rpc LabelNames(LabelNamesRequest) returns (LabelNamesResponse) {};
  rpc UserStats(UserStatsRequest) returns (UserStatsResponse) {};
  rpc AllUserStats(UserStatsRequest) returns (UsersStatsResponse) {};
  rpc MetricsForLabelMatchers(MetricsForLabelMatchersRequest) returns (MetricsForLabelMatchersResponse) {};
  rpc MetricsMetadata(MetricsMetadataRequest) returns (MetricsMetadataResponse) {};

  // TransferChunks allows leaving ingester (client) to stream chunks directly to joining ingesters (server).
  rpc TransferChunks(stream TimeSeriesChunk) returns (TransferChunksResponse) {};
}

message WriteRequest {
  repeated TimeSeries timeseries = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "PreallocTimeseries"];
  enum SourceEnum {
    API = 0;
    RULE = 1;
  }
  SourceEnum Source = 2;
  repeated MetricMetadata metadata = 3 [(gogoproto.nullable) = true];
}

message WriteResponse {}

message ReadRequest {
  repeated QueryRequest queries = 1;
}

message ReadResponse {
  repeated QueryResponse results = 1;
}

message QueryRequest {
  int64 start_timestamp_ms = 1;
  int64 end_timestamp_ms = 2;
  repeated LabelMatcher matchers = 3;
}

message QueryResponse {
  repeated TimeSeries timeseries = 1 [(gogoproto.nullable) = false];
}

// QueryStreamResponse contains a batch of timeseries chunks or timeseries. Only one of these series will be populated.
message QueryStreamResponse {
  repeated TimeSeriesChunk chunkseries = 1 [(gogoproto.nullable) = false];
  repeated TimeSeries timeseries = 2 [(gogoproto.nullable) = false];
}

message LabelValuesRequest {
  string label_name = 1;
}

message LabelValuesResponse {
  repeated string label_values = 1;
}

message LabelNamesRequest {
}

message LabelNamesResponse {
  repeated string label_names = 1;
}

message UserStatsRequest {}

message UserStatsResponse {
  double ingestion_rate = 1;
  uint64 num_series = 2;
  double api_ingestion_rate = 3;
  double rule_ingestion_rate = 4;
}

message UserIDStatsResponse {
  string user_id = 1;
  UserStatsResponse data = 2;
}

message UsersStatsResponse {
  repeated UserIDStatsResponse stats = 1;
}

message MetricsForLabelMatchersRequest {
  int64 start_timestamp_ms = 1;
  int64 end_timestamp_ms = 2;
  repeated LabelMatchers matchers_set = 3;
}

message MetricsForLabelMatchersResponse {
  repeated Metric metric = 1;
}

message MetricsMetadataRequest {
}

message MetricsMetadataResponse {
  repeated MetricMetadata metadata = 1;
}

message TimeSeriesChunk {
  string from_ingester_id = 1;
  string user_id = 2;
  repeated LabelPair labels = 3 [(gogoproto.nullable) = false, (gogoproto.customtype) = "LabelAdapter"];
  repeated Chunk chunks = 4 [(gogoproto.nullable) = false];
}

message Chunk {
  int64 start_timestamp_ms = 1;
  int64 end_timestamp_ms = 2;
  int32 encoding = 3;
  bytes data = 4;
}

message TransferChunksResponse {
}

message TimeSeries {
  repeated LabelPair labels = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "LabelAdapter"];
  // Sorted by time, oldest sample first.
  repeated Sample samples   = 2 [(gogoproto.nullable) = false];
}

message LabelPair {
  bytes name  = 1;
  bytes value = 2;
}

message Sample {
  double value       = 1;
  int64 timestamp_ms = 2;
}

message LabelMatchers {
  repeated LabelMatcher matchers = 1;
}

message MetricMetadata {
  enum MetricType {
    UNKNOWN        = 0;
    COUNTER        = 1;
    GAUGE          = 2;
    HISTOGRAM      = 3;
    GAUGEHISTOGRAM = 4;
    SUMMARY        = 5;
    INFO           = 6;
    STATESET       = 7;
  }

  MetricType type = 1;
  string metric_name = 2;
  string help = 4;
  string unit = 5;
}

message Metric {
  repeated LabelPair labels = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "LabelAdapter"];
}

enum MatchType {
  EQUAL = 0;
  NOT_EQUAL = 1;
  REGEX_MATCH = 2;
  REGEX_NO_MATCH = 3;
}

message LabelMatcher {
  MatchType type = 1;
  string name = 2;
  string value = 3;
}

message TimeSeriesFile {
  string from_ingester_id = 1;
  string user_id = 2;
  string filename = 3;
  bytes data = 4;
}
