// Copyright 2025 Envoy Project 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 envoy.config.accesslog.v3;

import "envoy/config/core/v3/base.proto";
import "envoy/config/route/v3/route_components.proto";
import "envoy/data/accesslog/v3/accesslog.proto";
import "envoy/type/matcher/v3/metadata.proto";
import "envoy/type/v3/percent.proto";

import "google/protobuf/any.proto";
import "google/protobuf/wrappers.proto";

import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.config.accesslog.v3";
option java_outer_classname = "AccesslogProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3;accesslogv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Common access log types]

message AccessLog {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.AccessLog";

  reserved 3;

  reserved "config";

  // The name of the access log extension configuration.
  string name = 1;

  // Filter which is used to determine if the access log needs to be written.
  AccessLogFilter filter = 2;

  // Custom configuration that must be set according to the access logger extension being instantiated.
  // [#extension-category: envoy.access_loggers]
  oneof config_type {
    google.protobuf.Any typed_config = 4;
  }
}

// [#next-free-field: 14]
message AccessLogFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.AccessLogFilter";

  oneof filter_specifier {
    option (validate.required) = true;

    // Status code filter.
    StatusCodeFilter status_code_filter = 1;

    // Duration filter.
    DurationFilter duration_filter = 2;

    // Not health check filter.
    NotHealthCheckFilter not_health_check_filter = 3;

    // Traceable filter.
    TraceableFilter traceable_filter = 4;

    // Runtime filter.
    RuntimeFilter runtime_filter = 5;

    // And filter.
    AndFilter and_filter = 6;

    // Or filter.
    OrFilter or_filter = 7;

    // Header filter.
    HeaderFilter header_filter = 8;

    // Response flag filter.
    ResponseFlagFilter response_flag_filter = 9;

    // gRPC status filter.
    GrpcStatusFilter grpc_status_filter = 10;

    // Extension filter.
    // [#extension-category: envoy.access_loggers.extension_filters]
    ExtensionFilter extension_filter = 11;

    // Metadata Filter
    MetadataFilter metadata_filter = 12;

    // Log Type Filter
    LogTypeFilter log_type_filter = 13;
  }
}

// Filter on an integer comparison.
message ComparisonFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.ComparisonFilter";

  enum Op {
    // =
    EQ = 0;

    // >=
    GE = 1;

    // <=
    LE = 2;
  }

  // Comparison operator.
  Op op = 1 [(validate.rules).enum = {defined_only: true}];

  // Value to compare against.
  core.v3.RuntimeUInt32 value = 2 [(validate.rules).message = {required: true}];
}

// Filters on HTTP response/status code.
message StatusCodeFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.StatusCodeFilter";

  // Comparison.
  ComparisonFilter comparison = 1 [(validate.rules).message = {required: true}];
}

// Filters based on the duration of the request or stream, in milliseconds.
// For end of stream access logs, the total duration of the stream will be used.
// For :ref:`periodic access logs<arch_overview_access_log_periodic>`,
// the duration of the stream at the time of log recording will be used.
message DurationFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.DurationFilter";

  // Comparison.
  ComparisonFilter comparison = 1 [(validate.rules).message = {required: true}];
}

// Filters for requests that are not health check requests. A health check
// request is marked by the health check filter.
message NotHealthCheckFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.NotHealthCheckFilter";
}

// Filters for requests that are traceable. See the tracing overview for more
// information on how a request becomes traceable.
message TraceableFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.TraceableFilter";
}

// Filters requests based on runtime-configurable sampling rates.
message RuntimeFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.RuntimeFilter";

  // Specifies a key used to look up a custom sampling rate from the runtime configuration. If a value is found for this
  // key, it will override the default sampling rate specified in ``percent_sampled``.
  string runtime_key = 1 [(validate.rules).string = {min_len: 1}];

  // Defines the default sampling percentage when no runtime override is present. If not specified, the default is
  // **0%** (with a denominator of 100).
  type.v3.FractionalPercent percent_sampled = 2;

  // Controls how sampling decisions are made.
  //
  // - Default behavior (``false``):
  //
  //   * Uses the :ref:`x-request-id<config_http_conn_man_headers_x-request-id>` as a consistent sampling pivot.
  //   * When :ref:`x-request-id<config_http_conn_man_headers_x-request-id>` is present, sampling will be consistent
  //     across multiple hosts based on both the ``runtime_key`` and
  //     :ref:`x-request-id<config_http_conn_man_headers_x-request-id>`.
  //   * Useful for tracking related requests across a distributed system.
  //
  // - When set to ``true`` or :ref:`x-request-id<config_http_conn_man_headers_x-request-id>` is missing:
  //
  //   * Sampling decisions are made randomly based only on the ``runtime_key``.
  //   * Useful in complex filter configurations (like nested
  //     :ref:`AndFilter<envoy_v3_api_msg_config.accesslog.v3.AndFilter>`/
  //     :ref:`OrFilter<envoy_v3_api_msg_config.accesslog.v3.OrFilter>` blocks) where independent probability
  //     calculations are desired.
  //   * Can be used to implement logging kill switches with predictable probability distributions.
  //
  bool use_independent_randomness = 3;
}

// Performs a logical “and” operation on the result of each filter in filters.
// Filters are evaluated sequentially and if one of them returns false, the
// filter returns false immediately.
message AndFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.AndFilter";

  repeated AccessLogFilter filters = 1 [(validate.rules).repeated = {min_items: 2}];
}

// Performs a logical “or” operation on the result of each individual filter.
// Filters are evaluated sequentially and if one of them returns true, the
// filter returns true immediately.
message OrFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.OrFilter";

  repeated AccessLogFilter filters = 2 [(validate.rules).repeated = {min_items: 2}];
}

// Filters requests based on the presence or value of a request header.
message HeaderFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.HeaderFilter";

  // Only requests with a header which matches the specified HeaderMatcher will
  // pass the filter check.
  route.v3.HeaderMatcher header = 1 [(validate.rules).message = {required: true}];
}

// Filters requests that received responses with an Envoy response flag set.
// A list of the response flags can be found
// in the access log formatter
// :ref:`documentation<config_access_log_format_response_flags>`.
message ResponseFlagFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.ResponseFlagFilter";

  // Only responses with the any of the flags listed in this field will be
  // logged. This field is optional. If it is not specified, then any response
  // flag will pass the filter check.
  repeated string flags = 1 [(validate.rules).repeated = {
    items {
      string {
        in: "LH"
        in: "UH"
        in: "UT"
        in: "LR"
        in: "UR"
        in: "UF"
        in: "UC"
        in: "UO"
        in: "NR"
        in: "DI"
        in: "FI"
        in: "RL"
        in: "UAEX"
        in: "RLSE"
        in: "DC"
        in: "URX"
        in: "SI"
        in: "IH"
        in: "DPE"
        in: "UMSDR"
        in: "RFCF"
        in: "NFCF"
        in: "DT"
        in: "UPE"
        in: "NC"
        in: "OM"
        in: "DF"
        in: "DO"
        in: "DR"
        in: "UDO"
      }
    }
  }];
}

// Filters gRPC requests based on their response status. If a gRPC status is not
// provided, the filter will infer the status from the HTTP status code.
message GrpcStatusFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.GrpcStatusFilter";

  enum Status {
    OK = 0;
    CANCELED = 1;
    UNKNOWN = 2;
    INVALID_ARGUMENT = 3;
    DEADLINE_EXCEEDED = 4;
    NOT_FOUND = 5;
    ALREADY_EXISTS = 6;
    PERMISSION_DENIED = 7;
    RESOURCE_EXHAUSTED = 8;
    FAILED_PRECONDITION = 9;
    ABORTED = 10;
    OUT_OF_RANGE = 11;
    UNIMPLEMENTED = 12;
    INTERNAL = 13;
    UNAVAILABLE = 14;
    DATA_LOSS = 15;
    UNAUTHENTICATED = 16;
  }

  // Logs only responses that have any one of the gRPC statuses in this field.
  repeated Status statuses = 1 [(validate.rules).repeated = {items {enum {defined_only: true}}}];

  // If included and set to true, the filter will instead block all responses
  // with a gRPC status or inferred gRPC status enumerated in statuses, and
  // allow all other responses.
  bool exclude = 2;
}

// Filters based on matching dynamic metadata.
// If the matcher path and key correspond to an existing key in dynamic
// metadata, the request is logged only if the matcher value is equal to the
// metadata value. If the matcher path and key *do not* correspond to an
// existing key in dynamic metadata, the request is logged only if
// match_if_key_not_found is "true" or unset.
message MetadataFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.MetadataFilter";

  // Matcher to check metadata for specified value. For example, to match on the
  // access_log_hint metadata, set the filter to "envoy.common" and the path to
  // "access_log_hint", and the value to "true".
  type.matcher.v3.MetadataMatcher matcher = 1;

  // Default result if the key does not exist in dynamic metadata: if unset or
  // true, then log; if false, then don't log.
  google.protobuf.BoolValue match_if_key_not_found = 2;
}

// Filters based on access log type.
message LogTypeFilter {
  // Logs only records which their type is one of the types defined in this field.
  repeated data.accesslog.v3.AccessLogType types = 1
      [(validate.rules).repeated = {items {enum {defined_only: true}}}];

  // If this field is set to true, the filter will instead block all records
  // with a access log type in types field, and allow all other records.
  bool exclude = 2;
}

// Extension filter is statically registered at runtime.
message ExtensionFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.accesslog.v2.ExtensionFilter";

  reserved 2;

  reserved "config";

  // The name of the filter implementation to instantiate. The name must
  // match a statically registered filter.
  string name = 1;

  // Custom configuration that depends on the filter being instantiated.
  oneof config_type {
    google.protobuf.Any typed_config = 3;
  }
}
