accesslogv3

package
v0.0.0-...-634b83c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 1, 2022 License: MIT Imports: 7 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ResponseFlags_Unauthorized_Reason_name = map[int32]string{
		0: "REASON_UNSPECIFIED",
		1: "EXTERNAL_SERVICE",
	}
	ResponseFlags_Unauthorized_Reason_value = map[string]int32{
		"REASON_UNSPECIFIED": 0,
		"EXTERNAL_SERVICE":   1,
	}
)

Enum value maps for ResponseFlags_Unauthorized_Reason.

View Source
var (
	TLSProperties_TLSVersion_name = map[int32]string{
		0: "VERSION_UNSPECIFIED",
		1: "TLSv1",
		2: "TLSv1_1",
		3: "TLSv1_2",
		4: "TLSv1_3",
	}
	TLSProperties_TLSVersion_value = map[string]int32{
		"VERSION_UNSPECIFIED": 0,
		"TLSv1":               1,
		"TLSv1_1":             2,
		"TLSv1_2":             3,
		"TLSv1_3":             4,
	}
)

Enum value maps for TLSProperties_TLSVersion.

Functions

This section is empty.

Types

type AccessLogCommon

type AccessLogCommon struct {
	SampleRate float64 `protobuf:"fixed64,1,opt,name=sample_rate,json=sampleRate,proto3" json:"sample_rate,omitempty"`
	// This field is the remote/origin address on which the request from the user was received.
	// Note: This may not be the physical peer. E.g, if the remote address is inferred from for
	// example the x-forwarder-for header, proxy protocol, etc.
	DownstreamRemoteAddress *v32.Address `` /* 132-byte string literal not displayed */
	// This field is the local/destination address on which the request from the user was received.
	DownstreamLocalAddress *v32.Address `` /* 129-byte string literal not displayed */
	// If the connection is secure,S this field will contain TLS properties.
	TlsProperties *TLSProperties `protobuf:"bytes,4,opt,name=tls_properties,json=tlsProperties,proto3" json:"tls_properties,omitempty"`
	// The time that Envoy started servicing this request. This is effectively the time that the first
	// downstream byte is received.
	StartTime *timestamp.Timestamp `protobuf:"bytes,5,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
	// Interval between the first downstream byte received and the last
	// downstream byte received (i.e. time it takes to receive a request).
	TimeToLastRxByte *duration.Duration `protobuf:"bytes,6,opt,name=time_to_last_rx_byte,json=timeToLastRxByte,proto3" json:"time_to_last_rx_byte,omitempty"`
	// Interval between the first downstream byte received and the first upstream byte sent. There may
	// by considerable delta between “time_to_last_rx_byte“ and this value due to filters.
	// Additionally, the same caveats apply as documented in “time_to_last_downstream_tx_byte“ about
	// not accounting for kernel socket buffer time, etc.
	TimeToFirstUpstreamTxByte *duration.Duration `` /* 144-byte string literal not displayed */
	// Interval between the first downstream byte received and the last upstream byte sent. There may
	// by considerable delta between “time_to_last_rx_byte“ and this value due to filters.
	// Additionally, the same caveats apply as documented in “time_to_last_downstream_tx_byte“ about
	// not accounting for kernel socket buffer time, etc.
	TimeToLastUpstreamTxByte *duration.Duration `` /* 141-byte string literal not displayed */
	// Interval between the first downstream byte received and the first upstream
	// byte received (i.e. time it takes to start receiving a response).
	TimeToFirstUpstreamRxByte *duration.Duration `` /* 144-byte string literal not displayed */
	// Interval between the first downstream byte received and the last upstream
	// byte received (i.e. time it takes to receive a complete response).
	TimeToLastUpstreamRxByte *duration.Duration `` /* 142-byte string literal not displayed */
	// Interval between the first downstream byte received and the first downstream byte sent.
	// There may be a considerable delta between the “time_to_first_upstream_rx_byte“ and this field
	// due to filters. Additionally, the same caveats apply as documented in
	// “time_to_last_downstream_tx_byte“ about not accounting for kernel socket buffer time, etc.
	TimeToFirstDownstreamTxByte *duration.Duration `` /* 151-byte string literal not displayed */
	// Interval between the first downstream byte received and the last downstream byte sent.
	// Depending on protocol, buffering, windowing, filters, etc. there may be a considerable delta
	// between “time_to_last_upstream_rx_byte“ and this field. Note also that this is an approximate
	// time. In the current implementation it does not include kernel socket buffer time. In the
	// current implementation it also does not include send window buffering inside the HTTP/2 codec.
	// In the future it is likely that work will be done to make this duration more accurate.
	TimeToLastDownstreamTxByte *duration.Duration `` /* 148-byte string literal not displayed */
	// The upstream remote/destination address that handles this exchange. This does not include
	// retries.
	UpstreamRemoteAddress *v32.Address `` /* 127-byte string literal not displayed */
	// The upstream local/origin address that handles this exchange. This does not include retries.
	UpstreamLocalAddress *v32.Address `protobuf:"bytes,14,opt,name=upstream_local_address,json=upstreamLocalAddress,proto3" json:"upstream_local_address,omitempty"`
	// The upstream cluster that “upstream_remote_address“ belongs to.
	UpstreamCluster string `protobuf:"bytes,15,opt,name=upstream_cluster,json=upstreamCluster,proto3" json:"upstream_cluster,omitempty"`
	// Flags indicating occurrences during request/response processing.
	ResponseFlags *ResponseFlags `protobuf:"bytes,16,opt,name=response_flags,json=responseFlags,proto3" json:"response_flags,omitempty"`
	// All metadata encountered during request processing, including endpoint
	// selection.
	//
	// 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 *v32.Metadata `protobuf:"bytes,17,opt,name=metadata,proto3" json:"metadata,omitempty"`
	// If upstream connection failed due to transport socket (e.g. TLS handshake), provides the
	// failure reason from the transport socket. The format of this field depends on the configured
	// upstream transport socket. Common TLS failures are in
	// :ref:`TLS trouble shooting <arch_overview_ssl_trouble_shooting>`.
	UpstreamTransportFailureReason string `` /* 156-byte string literal not displayed */
	// The name of the route
	RouteName string `protobuf:"bytes,19,opt,name=route_name,json=routeName,proto3" json:"route_name,omitempty"`
	// This field is the downstream direct remote address on which the request from the user was
	// received. Note: This is always the physical peer, even if the remote address is inferred from
	// for example the x-forwarder-for header, proxy protocol, etc.
	DownstreamDirectRemoteAddress *v32.Address `` /* 153-byte string literal not displayed */
	// Map of filter state in stream info that have been configured to be logged. If the filter
	// state serialized to any message other than “google.protobuf.Any“ it will be packed into
	// “google.protobuf.Any“.
	FilterStateObjects map[string]*any2.Any `` /* 206-byte string literal not displayed */
	// A list of custom tags, which annotate logs with additional information.
	// To configure this value, users should configure
	// :ref:`custom_tags <envoy_v3_api_field_extensions.access_loggers.grpc.v3.CommonGrpcAccessLogConfig.custom_tags>`.
	CustomTags map[string]string `` /* 180-byte string literal not displayed */
	// For HTTP: Total duration in milliseconds of the request from the start time to the last byte out.
	// For TCP: Total duration in milliseconds of the downstream connection.
	// This is the total duration of the request (i.e., when the request's ActiveStream is destroyed)
	// and may be longer than “time_to_last_downstream_tx_byte“.
	Duration *duration.Duration `protobuf:"bytes,23,opt,name=duration,proto3" json:"duration,omitempty"`
	// For HTTP: Number of times the request is attempted upstream. Note that the field is omitted when the request was never attempted upstream.
	// For TCP: Number of times the connection request is attempted upstream. Note that the field is omitted when the connect request was never attempted upstream.
	UpstreamRequestAttemptCount uint32 `` /* 148-byte string literal not displayed */
	// Connection termination details may provide additional information about why the connection was terminated by Envoy for L4 reasons.
	ConnectionTerminationDetails string `` /* 148-byte string literal not displayed */
}

type HTTPRequestProperties

type HTTPRequestProperties struct {

	// The request method (RFC 7231/2616).
	RequestMethod v3.RequestMethod `` /* 141-byte string literal not displayed */
	// The scheme portion of the incoming request URI.
	Scheme string `protobuf:"bytes,2,opt,name=scheme,proto3" json:"scheme,omitempty"`
	// HTTP/2 “:authority“ or HTTP/1.1 “Host“ header value.
	Authority string `protobuf:"bytes,3,opt,name=authority,proto3" json:"authority,omitempty"`
	// The port of the incoming request URI
	// (unused currently, as port is composed onto authority).
	Port *wrappers.UInt32Value `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"`
	// The path portion from the incoming request URI.
	Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"`
	// Value of the “User-Agent“ request header.
	UserAgent string `protobuf:"bytes,6,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
	// Value of the “Referer“ request header.
	Referer string `protobuf:"bytes,7,opt,name=referer,proto3" json:"referer,omitempty"`
	// Value of the “X-Forwarded-For“ request header.
	ForwardedFor string `protobuf:"bytes,8,opt,name=forwarded_for,json=forwardedFor,proto3" json:"forwarded_for,omitempty"`
	// 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.
	RequestId string `protobuf:"bytes,9,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	// Value of the “X-Envoy-Original-Path“ request header.
	OriginalPath string `protobuf:"bytes,10,opt,name=original_path,json=originalPath,proto3" json:"original_path,omitempty"`
	// Size of the HTTP request headers 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.
	RequestHeadersBytes uint64 `protobuf:"varint,11,opt,name=request_headers_bytes,json=requestHeadersBytes,proto3" json:"request_headers_bytes,omitempty"`
	// Size of the HTTP request 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.
	RequestBodyBytes uint64 `protobuf:"varint,12,opt,name=request_body_bytes,json=requestBodyBytes,proto3" json:"request_body_bytes,omitempty"`
	// Map of additional headers that have been configured to be logged.
	RequestHeaders map[string]string `` /* 192-byte string literal not displayed */
	// contains filtered or unexported fields
}

type HTTPResponseProperties

type HTTPResponseProperties struct {

	// The HTTP response code returned by Envoy.
	ResponseCode *wrappers.UInt32Value `protobuf:"bytes,1,opt,name=response_code,json=responseCode,proto3" json:"response_code,omitempty"`
	// Size of the HTTP response headers 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.
	ResponseHeadersBytes uint64 `protobuf:"varint,2,opt,name=response_headers_bytes,json=responseHeadersBytes,proto3" json:"response_headers_bytes,omitempty"`
	// 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.
	ResponseBodyBytes uint64 `protobuf:"varint,3,opt,name=response_body_bytes,json=responseBodyBytes,proto3" json:"response_body_bytes,omitempty"`
	// Map of additional headers configured to be logged.
	ResponseHeaders map[string]string `` /* 194-byte string literal not displayed */
	// Map of trailers configured to be logged.
	ResponseTrailers map[string]string `` /* 197-byte string literal not displayed */
	// The HTTP response code details.
	ResponseCodeDetails string `protobuf:"bytes,6,opt,name=response_code_details,json=responseCodeDetails,proto3" json:"response_code_details,omitempty"`
	// contains filtered or unexported fields
}

[#next-free-field: 7]

type ResponseFlags

type ResponseFlags struct {

	// Indicates local server healthcheck failed.
	FailedLocalHealthcheck bool `` /* 130-byte string literal not displayed */
	// Indicates there was no healthy upstream.
	NoHealthyUpstream bool `protobuf:"varint,2,opt,name=no_healthy_upstream,json=noHealthyUpstream,proto3" json:"no_healthy_upstream,omitempty"`
	// Indicates an there was an upstream request timeout.
	UpstreamRequestTimeout bool `` /* 130-byte string literal not displayed */
	// Indicates local codec level reset was sent on the stream.
	LocalReset bool `protobuf:"varint,4,opt,name=local_reset,json=localReset,proto3" json:"local_reset,omitempty"`
	// Indicates remote codec level reset was received on the stream.
	UpstreamRemoteReset bool `protobuf:"varint,5,opt,name=upstream_remote_reset,json=upstreamRemoteReset,proto3" json:"upstream_remote_reset,omitempty"`
	// Indicates there was a local reset by a connection pool due to an initial connection failure.
	UpstreamConnectionFailure bool `` /* 139-byte string literal not displayed */
	// Indicates the stream was reset due to an upstream connection termination.
	UpstreamConnectionTermination bool `` /* 151-byte string literal not displayed */
	// Indicates the stream was reset because of a resource overflow.
	UpstreamOverflow bool `protobuf:"varint,8,opt,name=upstream_overflow,json=upstreamOverflow,proto3" json:"upstream_overflow,omitempty"`
	// Indicates no route was found for the request.
	NoRouteFound bool `protobuf:"varint,9,opt,name=no_route_found,json=noRouteFound,proto3" json:"no_route_found,omitempty"`
	// Indicates that the request was delayed before proxying.
	DelayInjected bool `protobuf:"varint,10,opt,name=delay_injected,json=delayInjected,proto3" json:"delay_injected,omitempty"`
	// Indicates that the request was aborted with an injected error code.
	FaultInjected bool `protobuf:"varint,11,opt,name=fault_injected,json=faultInjected,proto3" json:"fault_injected,omitempty"`
	// Indicates that the request was rate-limited locally.
	RateLimited bool `protobuf:"varint,12,opt,name=rate_limited,json=rateLimited,proto3" json:"rate_limited,omitempty"`
	// Indicates if the request was deemed unauthorized and the reason for it.
	UnauthorizedDetails *ResponseFlags_Unauthorized `protobuf:"bytes,13,opt,name=unauthorized_details,json=unauthorizedDetails,proto3" json:"unauthorized_details,omitempty"`
	// Indicates that the request was rejected because there was an error in rate limit service.
	RateLimitServiceError bool `` /* 130-byte string literal not displayed */
	// Indicates the stream was reset due to a downstream connection termination.
	DownstreamConnectionTermination bool `` /* 158-byte string literal not displayed */
	// Indicates that the upstream retry limit was exceeded, resulting in a downstream error.
	UpstreamRetryLimitExceeded bool `` /* 145-byte string literal not displayed */
	// Indicates that the stream idle timeout was hit, resulting in a downstream 408.
	StreamIdleTimeout bool `protobuf:"varint,17,opt,name=stream_idle_timeout,json=streamIdleTimeout,proto3" json:"stream_idle_timeout,omitempty"`
	// Indicates that the request was rejected because an envoy request header failed strict
	// validation.
	InvalidEnvoyRequestHeaders bool `` /* 145-byte string literal not displayed */
	// Indicates there was an HTTP protocol error on the downstream request.
	DownstreamProtocolError bool `` /* 134-byte string literal not displayed */
	// Indicates there was a max stream duration reached on the upstream request.
	UpstreamMaxStreamDurationReached bool `` /* 165-byte string literal not displayed */
	// Indicates the response was served from a cache filter.
	ResponseFromCacheFilter bool `` /* 136-byte string literal not displayed */
	// Indicates that a filter configuration is not available.
	NoFilterConfigFound bool `protobuf:"varint,22,opt,name=no_filter_config_found,json=noFilterConfigFound,proto3" json:"no_filter_config_found,omitempty"`
	// Indicates that request or connection exceeded the downstream connection duration.
	DurationTimeout bool `protobuf:"varint,23,opt,name=duration_timeout,json=durationTimeout,proto3" json:"duration_timeout,omitempty"`
	// Indicates there was an HTTP protocol error in the upstream response.
	UpstreamProtocolError bool `` /* 128-byte string literal not displayed */
	// Indicates no cluster was found for the request.
	NoClusterFound bool `protobuf:"varint,25,opt,name=no_cluster_found,json=noClusterFound,proto3" json:"no_cluster_found,omitempty"`
	// Indicates overload manager terminated the request.
	OverloadManager bool `protobuf:"varint,26,opt,name=overload_manager,json=overloadManager,proto3" json:"overload_manager,omitempty"`
	// Indicates a DNS resolution failed.
	DnsResolutionFailure bool `protobuf:"varint,27,opt,name=dns_resolution_failure,json=dnsResolutionFailure,proto3" json:"dns_resolution_failure,omitempty"`
	// contains filtered or unexported fields
}

Flags indicating occurrences during request/response processing. [#next-free-field: 28]

type ResponseFlags_Unauthorized

type ResponseFlags_Unauthorized struct {
	Reason ResponseFlags_Unauthorized_Reason `` /* 131-byte string literal not displayed */
	// contains filtered or unexported fields
}

type ResponseFlags_Unauthorized_Reason

type ResponseFlags_Unauthorized_Reason int32

Reasons why the request was unauthorized

const (
	ResponseFlags_Unauthorized_REASON_UNSPECIFIED ResponseFlags_Unauthorized_Reason = 0
	// The request was denied by the external authorization service.
	ResponseFlags_Unauthorized_EXTERNAL_SERVICE ResponseFlags_Unauthorized_Reason = 1
)

type StreamAccessLogsMessage

type StreamAccessLogsMessage struct {

	// Identifier data that will only be sent in the first message on the stream. This is effectively
	// structured metadata and is a performance optimization.
	Identifier *StreamAccessLogsMessage_Identifier `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"`
	// Batches of log entries of a single type. Generally speaking, a given stream should only
	// ever include one type of log entry.
	//
	// Types that are assignable to LogEntries:
	//	*StreamAccessLogsMessage_HttpLogs
	//	*StreamAccessLogsMessage_TcpLogs
	LogEntries isStreamAccessLogsMessage_LogEntries `protobuf_oneof:"log_entries"`
	// contains filtered or unexported fields
}

Stream message for the StreamAccessLogs API. Envoy will open a stream to the server and stream access logs without ever expecting a response.

type StreamAccessLogsMessage_HTTPAccessLogEntries

type StreamAccessLogsMessage_HTTPAccessLogEntries struct {
	LogEntry []*v312.HTTPAccessLogEntry `protobuf:"bytes,1,rep,name=log_entry,json=logEntry,proto3" json:"log_entry,omitempty"`
	// contains filtered or unexported fields
}

Wrapper for batches of HTTP access log entries.

type StreamAccessLogsMessage_HttpLogs

type StreamAccessLogsMessage_HttpLogs struct {
	HttpLogs *StreamAccessLogsMessage_HTTPAccessLogEntries `protobuf:"bytes,2,opt,name=http_logs,json=httpLogs,proto3,oneof"`
}

type StreamAccessLogsMessage_Identifier

type StreamAccessLogsMessage_Identifier struct {

	// The node sending the access log messages over the stream.
	Node *v3.Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
	// The friendly name of the log configured in :ref:`CommonGrpcAccessLogConfig
	// <envoy_v3_api_msg_extensions.access_loggers.grpc.v3.CommonGrpcAccessLogConfig>`.
	LogName string `protobuf:"bytes,2,opt,name=log_name,json=logName,proto3" json:"log_name,omitempty"`
	// contains filtered or unexported fields
}

type StreamAccessLogsMessage_TCPAccessLogEntries

type StreamAccessLogsMessage_TCPAccessLogEntries struct {
	LogEntry []*v312.TCPAccessLogEntry `protobuf:"bytes,1,rep,name=log_entry,json=logEntry,proto3" json:"log_entry,omitempty"`
	// contains filtered or unexported fields
}

Wrapper for batches of TCP access log entries.

type StreamAccessLogsMessage_TcpLogs

type StreamAccessLogsMessage_TcpLogs struct {
	TcpLogs *StreamAccessLogsMessage_TCPAccessLogEntries `protobuf:"bytes,3,opt,name=tcp_logs,json=tcpLogs,proto3,oneof"`
}

type TLSProperties

type TLSProperties struct {

	// Version of TLS that was negotiated.
	TlsVersion TLSProperties_TLSVersion `` /* 148-byte string literal not displayed */
	// 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“).
	//
	// Here it is expressed as an integer.
	TlsCipherSuite *wrappers.UInt32Value `protobuf:"bytes,2,opt,name=tls_cipher_suite,json=tlsCipherSuite,proto3" json:"tls_cipher_suite,omitempty"`
	// SNI hostname from handshake.
	TlsSniHostname string `protobuf:"bytes,3,opt,name=tls_sni_hostname,json=tlsSniHostname,proto3" json:"tls_sni_hostname,omitempty"`
	// Properties of the local certificate used to negotiate TLS.
	LocalCertificateProperties *TLSProperties_CertificateProperties `` /* 141-byte string literal not displayed */
	// Properties of the peer certificate used to negotiate TLS.
	PeerCertificateProperties *TLSProperties_CertificateProperties `` /* 138-byte string literal not displayed */
	// The TLS session ID.
	TlsSessionId string `protobuf:"bytes,6,opt,name=tls_session_id,json=tlsSessionId,proto3" json:"tls_session_id,omitempty"`
	// The “JA3“ fingerprint when “JA3“ fingerprinting is enabled.
	Ja3Fingerprint string `protobuf:"bytes,7,opt,name=ja3_fingerprint,json=ja3Fingerprint,proto3" json:"ja3_fingerprint,omitempty"`
	// contains filtered or unexported fields
}

type TLSProperties_CertificateProperties

type TLSProperties_CertificateProperties struct {

	// SANs present in the certificate.
	SubjectAltName []*TLSProperties_CertificateProperties_SubjectAltName `protobuf:"bytes,1,rep,name=subject_alt_name,json=subjectAltName,proto3" json:"subject_alt_name,omitempty"`
	// The subject field of the certificate.
	Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"`
	// contains filtered or unexported fields
}

type TLSProperties_CertificateProperties_SubjectAltName

type TLSProperties_CertificateProperties_SubjectAltName struct {

	// Types that are assignable to San:
	//	*TLSProperties_CertificateProperties_SubjectAltName_Uri
	//	*TLSProperties_CertificateProperties_SubjectAltName_Dns
	San isTLSProperties_CertificateProperties_SubjectAltName_San `protobuf_oneof:"san"`
	// contains filtered or unexported fields
}

type TLSProperties_CertificateProperties_SubjectAltName_Dns

type TLSProperties_CertificateProperties_SubjectAltName_Dns struct {
	// [#not-implemented-hide:]
	Dns string `protobuf:"bytes,2,opt,name=dns,proto3,oneof"`
}

type TLSProperties_CertificateProperties_SubjectAltName_Uri

type TLSProperties_CertificateProperties_SubjectAltName_Uri struct {
	Uri string `protobuf:"bytes,1,opt,name=uri,proto3,oneof"`
}

type TLSProperties_TLSVersion

type TLSProperties_TLSVersion int32
const (
	TLSProperties_VERSION_UNSPECIFIED TLSProperties_TLSVersion = 0
	TLSProperties_TLSv1               TLSProperties_TLSVersion = 1
	TLSProperties_TLSv1_1             TLSProperties_TLSVersion = 2
	TLSProperties_TLSv1_2             TLSProperties_TLSVersion = 3
	TLSProperties_TLSv1_3             TLSProperties_TLSVersion = 4
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL