From c73aac33c9d9f07dfc2d93e09b110a2269bb0632 Mon Sep 17 00:00:00 2001 From: Mike Schore Date: Fri, 24 Nov 2017 13:22:29 -0800 Subject: [PATCH] refactor access logs to support specific protocols (#237) Signed-off-by: Mike Schore --- api/filter/BUILD | 2 +- api/filter/accesslog.proto | 321 +++++++++++++++++++++++-------------- 2 files changed, 199 insertions(+), 124 deletions(-) diff --git a/api/filter/BUILD b/api/filter/BUILD index 10dca52c..529e7927 100644 --- a/api/filter/BUILD +++ b/api/filter/BUILD @@ -45,5 +45,5 @@ api_proto_library( name = "accesslog", srcs = ["accesslog.proto"], has_services = 1, - deps = ["//api:base"], + deps = ["//api:address", "//api:base"], ) diff --git a/api/filter/accesslog.proto b/api/filter/accesslog.proto index c2546c75..a7b6131b 100644 --- a/api/filter/accesslog.proto +++ b/api/filter/accesslog.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package envoy.api.v2.filter; +import "api/address.proto"; import "api/base.proto"; import "google/protobuf/duration.proto"; @@ -9,164 +10,224 @@ import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; -message AccessLogEntry { - // The HTTP request method (RFC 7231/2616) - RequestMethod request_method = 1; +import "validate/validate.proto"; + + +// Envoy access logs describe incoming interaction with Envoy over a fixed +// period of time, and typically cover a single request/response exchange, +// (e.g. HTTP), stream (e.g. over HTTP/gRPC), or proxied connection (e.g. TCP). +// Access logs contain fields defined in protocol-specific protobuf messages. +// +// Except where explicitly declared otherwise, all fields describe +// *downstream* interaction between Envoy and a connected client. +// Fields describing *upstream* interaction will explicitly include ``upstream`` +// in their name. + +// Defines fields that are shared by all Envoy access logs. +message AccessLogCommon { + // This field indicates the rate at which this log entry was sampled. + // Valid range is (0.0, 1.0]. + double sample_rate = 1 [(validate.rules).double.gt = 0.0, (validate.rules).double.lte = 1.0]; + + // This field is the IP and port on which the request from the user was + // received. + SocketAddress destination_host = 2; + + // If the connection is secure, this field will contain TLS properties. + TLSProperties tls_properties = 3; // The time that Envoy started servicing this request - google.protobuf.Timestamp start_time = 2; + google.protobuf.Timestamp start_time = 4; - // Incoming protocol variation spoken - enum Protocol { - PROTOCOL_UNSPECIFIED = 0; - HTTP10 = 1; - HTTP11 = 2; - HTTP2 = 3; - } - Protocol protocol_variant = 3; - - // This enum defines the various things that may have occurred while - // processing a request. - enum ResponseFlag { - // Local server healthcheck failed. - FAILED_LOCAL_HEALTHCHECK = 0; - // No healthy upstream. - NO_HEALTHY_UPSTREAM = 1; - // Request timeout on upstream. - UPSTREAM_REQUEST_TIMEOUT = 2; - // Local codec level reset was sent on the stream. - LOCAL_RESET = 3; - // Remote codec level reset was received on the stream. - UPSTREAM_REMOTE_RESET = 4; - // Local reset by a connection pool due to an initial connection failure. - UPSTREAM_CONNECTION_FAILURE = 5; - // If the stream was locally reset due to connection termination. - UPSTREAM_CONNECTION_TERMINATION = 6; - // The stream was reset because of a resource overflow. - UPSTREAM_OVERFLOW = 7; - // No route found for a given request. - NO_ROUTE_FOUND = 8; - // Request was delayed before proxying. - DELAY_INJECTED = 9; - // Abort with error code was injected. - FAULT_INJECTED = 10; - // Request was ratelimited locally by rate limit filter. - RATE_LIMITED = 11; - } - // Status flags about the response. - repeated ResponseFlag response_flags = 4; + // Interval between the first downstream byte received and the last + // downstream byte received (i.e. time it takes to receive a request). + google.protobuf.Duration time_to_last_rx_byte = 5; - // The upstream host URL (Envoy connects to). - // - // For example, tcp://ip:port for TCP connections. + // Interval between the first downstream byte received and the first upstream + // byte received (i.e. time it takes to start receiving a response). + google.protobuf.Duration time_to_first_upstream_rx_byte = 6; + + // Interval between the first downstream byte received and the last upstream + // byte received (i.e. time it takes to receive a complete response). + google.protobuf.Duration time_to_last_upstream_rx_byte = 7; + + // The (primary) upstream host that handles this exchange. + SocketAddress upstream_host = 8; + + // The upstream cluster that ``upstream_host`` belongs to. + string upstream_cluster = 9; + + // Flags indicating occurences during request/response processing. + ResponseFlags response_flags = 10; + + // All metadata encountered during request processing, including endpoint + // selection. // - // IPv6 addresses should be stored in canonical (compressed) format using - // [address]:port notation. - string upstream_host = 5; + // This can be used to associate IDs attached to the various configurations + // used to process this request with the access log entry. For example, a + // route created from a higher level forwarding rule with some ID can place + // that ID in this field and cross reference later. It can also be used to + // determine if a canary endpoint was used or not. + Metadata metadata = 11; +} - // The Upstream Cluster that the upstream host belongs to. - string upstream_cluster = 6; +// Flags indicating occurences during request/response processing. +message ResponseFlags { + // Indicates local server healthcheck failed. + bool failed_local_healthcheck = 1; - // This field is the IP and port on which the request from the user was - // received, stored in ipv4:port or [ipv6]:port format. - string destination_host = 7; + // Indicates there was no healthy upstream. + bool no_healthy_upstream = 2; + + // Indicates an there was an upstream request timeout. + bool upstream_request_timeout = 3; + + // Indicates local codec level reset was sent on the stream. + bool local_reset = 4; - // Size of the HTTP request body in bytes - google.protobuf.UInt64Value request_body_bytes = 8; + // Indicates remote codec level reset was received on the stream. + bool upstream_remote_reset = 5; - // Size of the HTTP response body in bytes - google.protobuf.UInt64Value response_body_bytes = 9; + // Indicates there was a local reset by a connection pool due to an initial connection failure. + bool upstream_connection_failure = 6; - // Size of the HTTP request headers in bytes - google.protobuf.UInt64Value request_headers_bytes = 10; + // Indicates the stream was reset locally due to connection termination. + bool upstream_connection_termination = 7; - // Size of the HTTP response headers in bytes - google.protobuf.UInt64Value response_headers_bytes = 11; + // Indicates the stream was reset because of a resource overflow. + bool upstream_overflow = 8; - // Whether the request arrived via a secure (TLS) protocol - google.protobuf.BoolValue secure = 12; + // Indicates no route was found for the request. + bool no_route_found = 9; - // Whether the request is a HealthCheck request - google.protobuf.BoolValue health_check = 13; + // Indicates that the request was delayed before proxying. + bool delay_injected = 10; - // The HTTP response code - google.protobuf.UInt32Value response_code = 14; + // Indicates that the request was aborted with an injected error code. + bool fault_injected = 11; - // User agent as sent by client HTTP - string user_agent = 15; + // Indicates that the request was rate-limited locally. + bool rate_limited = 12; +} + +// Properties of a negotiated TLS connection. +message TLSProperties { + enum TLSVersion { + VERSION_UNSPECIFIED = 0; + TLSv1 = 1; + TLSv1_1 = 2; + TLSv1_2 = 3; + TLSv1_3 = 4; + } + // Version of TLS that was negotiated. + TLSVersion tls_version = 1; - // Path + // TLS cipher suite negotiated during handshake. The value is a + // four-digit hex code defined by the IANA TLS Cipher Suite Registry + // (e.g. ``009C`` for ``TLS_RSA_WITH_AES_128_GCM_SHA256``). // - // This is the Path portion from the incoming request URI - string path = 17; + // Here it is expressed as an integer. + google.protobuf.UInt32Value tls_cipher_suite = 2; + + // SNI hostname from handshake. + string tls_sni_hostname = 3; +} + +message TCPAccessLogEntry { + // Common properties shared by all Envoy access logs. + AccessLogCommon common_properties = 1; +} + +message HTTPRequestProperties { + // The request method (RFC 7231/2616). + RequestMethod request_method = 1; + + // The scheme portion of the incoming request URI. + string scheme = 2; + + // HTTP/2 ``:authority`` or HTTP/1.1 ``Host`` header value. + string authority = 3; + + // The port of the incoming request URI + // (unused currently, as port is composed onto authority). + google.protobuf.UInt32Value port = 4; + + // The path portion from the incoming request URI. + string path = 5; - // Referer header as sent by client HTTP - // (Referer is spelled to match the HTTP spec, not English). - string referer = 18; + // Value of the ``User-Agent`` request header. + string user_agent = 6; - // X-Forwarded-For request header - string forwarded_for = 19; + // Value of the ``Referer`` request header. + string referer = 7; - // X-Request-Id request header + // Value of the ``X-Forwarded-For`` request header. + string forwarded_for = 8; + + // Value of the ``X-Request-Id`` request header // // This header is used by Envoy to uniquely identify a request. // It will be generated for all external requests and internal requests that - // do not already have a request ID. So this field can be guaranteed to exist - // and be unique for request tracing purposes. - string request_id = 20; + // do not already have a request ID. + string request_id = 9; - // HTTP2 :authority header value or HTTP1.1 Host header value - string authority = 21; + // Value of the ``X-Envoy-Original-Path`` request header. + string original_path = 10; - // Duration (milliseconds) + // Size of the HTTP request headers in bytes. // - // The total duration it took to service this request from the StartTime until - // the response was written to the user. - google.protobuf.Duration response_duration = 22; + // This value is captured from the OSI layer 7 perspective, i.e. it does not + // include overhead from framing or encoding at other networking layers. + uint64 request_headers_bytes = 11; - // Upstream Service Time Duration + // Size of the HTTP request body in bytes. // - // From the X-Envoy-Upstream-Service-Time response header. This is the amount it took - // the upstream server to service the request. - google.protobuf.Duration upstream_service_duration = 23; + // This value is captured from the OSI layer 7 perspective, i.e. it does not + // include overhead from framing or encoding at other networking layers. + uint64 request_body_bytes = 12; + // Map of additional headers that have been configured to be logged. + map request_headers = 13; +} - // Original Path from the X-Envoy-Original-Path header. - string original_path = 24; +message HTTPResponseProperties { + // The HTTP response code returned by Envoy. + google.protobuf.UInt32Value response_code = 1; - // All metadata encountered during request processing, including endpoint - // selection. + // Size of the HTTP response headers in bytes. // - // This can be used to associate IDs attached to the various configurations - // used to process this request with the access log entry. For example, a - // route created from a higher level forwarding rule with some ID can place - // that ID in this field and cross reference later. It can also be used to - // determine if a canary endpoint was used or not. - google.protobuf.Struct metadata = 25; + // This value is captured from the OSI layer 7 perspective, i.e. it does not + // include overhead from framing or encoding at other networking layers. + uint64 response_headers_bytes = 2; + + // Size of the HTTP response body in bytes. + // + // This value is captured from the OSI layer 7 perspective, i.e. it does not + // include overhead from framing or encoding at other networking layers. + uint64 response_body_bytes = 3; - // Headers configured for logging but not covered by a specific field. - repeated HeaderValue request_headers = 26; - repeated HeaderValue response_headers = 27; + // Map of additional headers configured to be logged. + map response_headers = 4; +} - // SNI hostname from handshake. - string tls_sni_hostname = 28; +message HTTPAccessLogEntry { + // Common properties shared by all Envoy access logs. + AccessLogCommon common_properties = 1; - // TLS Version or VERSION_UNSPECIFIED if TLS was not used - enum TLSVersion { - VERSION_UNSPECIFIED = 0; - TLSv1 = 1; - TLSv1_1 = 2; - TLSv1_2 = 3; - TLSv1_3 = 4; + // HTTP version + enum HTTPVersion { + PROTOCOL_UNSPECIFIED = 0; + HTTP10 = 1; + HTTP11 = 2; + HTTP2 = 3; } - TLSVersion tls_version = 29; + HTTPVersion protocol_version = 2; - // TLS Cipher suite negotiated during TLS handshake. - // The value is four hex digits defined by the IANA TLS Cipher Suite Registry, - // eg, "009C" for TLS_RSA_WITH_AES_128_GCM_SHA256. - // - // Here is is expressed as an integer. - google.protobuf.UInt32Value tls_cipher_suite = 30; + // Description of the incoming HTTP request. + HTTPRequestProperties request = 3; + + // Description of the outgoing HTTP response. + HTTPResponseProperties response = 4; } // Filter on some integer comparison. @@ -284,8 +345,22 @@ message StreamAccessLogsMessage { // structured metadata and is a performance optimization. Identifier identifier = 1; - // A list of access logs. - repeated AccessLogEntry logs = 2; + // Wrapper for batches of HTTP access log entries. + message HTTPAccessLogEntries { + repeated HTTPAccessLogEntry log_entry = 1; + } + + // Wrapper for batches of TCP access log entries. + message TCPAccessLogEntries { + repeated TCPAccessLogEntry log_entry = 1; + } + + // Batches of log entries of a single type. Generally speaking, a given stream should only + // ever incude one type of log entry. + oneof log_entries { + HTTPAccessLogEntries http_logs = 2; + TCPAccessLogEntries tcp_logs = 3; + } } // Empty response for the StreamAccessLogs API. Will never be sent. See below.