You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/04/09 02:04:49 UTC

[incubator-skywalking] branch envoy-access-log created (now 9949460)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a change to branch envoy-access-log
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking.git.


      at 9949460  Add ALS proto and receiver in envoy

This branch includes the following new commits:

     new 9949460  Add ALS proto and receiver in envoy

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[incubator-skywalking] 01/01: Add ALS proto and receiver in envoy

Posted by wu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch envoy-access-log
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking.git

commit 9949460e91a35349143fec2a35ec7f1f215da0a4
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Tue Apr 9 10:04:37 2019 +0800

    Add ALS proto and receiver in envoy
---
 .../envoy/AccessLogServiceGRPCHandler.java         |  53 ++++
 .../envoy/EnvoyMetricReceiverProvider.java         |   1 +
 .../src/main/proto/envoy/api/v2/core/address.proto | 121 ++++++++
 .../src/main/proto/envoy/api/v2/core/base.proto    | 176 +++++++++++
 .../proto/envoy/data/accesslog/v2/accesslog.proto  | 335 +++++++++++++++++++++
 .../proto/envoy/service/accesslog/v2/als.proto     |  73 +++++
 6 files changed, 759 insertions(+)

diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/AccessLogServiceGRPCHandler.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/AccessLogServiceGRPCHandler.java
new file mode 100644
index 0000000..32de937
--- /dev/null
+++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/AccessLogServiceGRPCHandler.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+package org.apache.skywalking.oap.server.receiver.envoy;
+
+import io.envoyproxy.envoy.service.accesslog.v2.*;
+import io.grpc.stub.StreamObserver;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.slf4j.*;
+
+public class AccessLogServiceGRPCHandler extends AccessLogServiceGrpc.AccessLogServiceImplBase {
+    private static final Logger logger = LoggerFactory.getLogger(AccessLogServiceGRPCHandler.class);
+
+    public AccessLogServiceGRPCHandler(ModuleManager manager) {
+
+    }
+
+    public StreamObserver<StreamAccessLogsMessage> streamAccessLogs(
+        StreamObserver<StreamAccessLogsResponse> responseObserver) {
+        return new StreamObserver<StreamAccessLogsMessage>() {
+            @Override public void onNext(StreamAccessLogsMessage message) {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Received msg {}", message);
+                }
+            }
+
+            @Override public void onError(Throwable throwable) {
+                logger.error("Error in receiving access log from envoy", throwable);
+                responseObserver.onCompleted();
+            }
+
+            @Override public void onCompleted() {
+                responseObserver.onNext(StreamAccessLogsResponse.newBuilder().build());
+                responseObserver.onCompleted();
+            }
+        };
+    }
+}
diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java
index 1631615..fce929e 100644
--- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java
+++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java
@@ -46,6 +46,7 @@ public class EnvoyMetricReceiverProvider extends ModuleProvider {
     @Override public void start() throws ServiceNotProvidedException, ModuleStartException {
         GRPCHandlerRegister service = getManager().find(CoreModule.NAME).provider().getService(GRPCHandlerRegister.class);
         service.addHandler(new MetricServiceGRPCHandler(getManager()));
+        service.addHandler(new AccessLogServiceGRPCHandler(getManager()));
     }
 
     @Override public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
diff --git a/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/api/v2/core/address.proto b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/api/v2/core/address.proto
new file mode 100644
index 0000000..6e76f5b
--- /dev/null
+++ b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/api/v2/core/address.proto
@@ -0,0 +1,121 @@
+syntax = "proto3";
+
+package envoy.api.v2.core;
+
+option java_outer_classname = "AddressProto";
+option java_multiple_files = true;
+option java_package = "io.envoyproxy.envoy.api.v2.core";
+
+import "envoy/api/v2/core/base.proto";
+
+import "google/protobuf/wrappers.proto";
+
+import "validate/validate.proto";
+import "gogoproto/gogo.proto";
+
+option (gogoproto.equal_all) = true;
+
+// [#protodoc-title: Network addresses]
+
+message Pipe {
+  // Unix Domain Socket path. On Linux, paths starting with '@' will use the
+  // abstract namespace. The starting '@' is replaced by a null byte by Envoy.
+  // Paths starting with '@' will result in an error in environments other than
+  // Linux.
+  string path = 1 [(validate.rules).string.min_bytes = 1];
+}
+
+message SocketAddress {
+  enum Protocol {
+    option (gogoproto.goproto_enum_prefix) = false;
+    TCP = 0;
+    // [#not-implemented-hide:]
+    UDP = 1;
+  }
+  Protocol protocol = 1 [(validate.rules).enum.defined_only = true];
+  // The address for this socket. :ref:`Listeners <config_listeners>` will bind
+  // to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::``
+  // to bind to any address. [#comment:TODO(zuercher) reinstate when implemented:
+  // It is possible to distinguish a Listener address via the prefix/suffix matching
+  // in :ref:`FilterChainMatch <envoy_api_msg_listener.FilterChainMatch>`.] When used
+  // within an upstream :ref:`BindConfig <envoy_api_msg_core.BindConfig>`, the address
+  // controls the source address of outbound connections. For :ref:`clusters
+  // <envoy_api_msg_Cluster>`, the cluster type determines whether the
+  // address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS
+  // (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized
+  // via :ref:`resolver_name <envoy_api_field_core.SocketAddress.resolver_name>`.
+  string address = 2 [(validate.rules).string.min_bytes = 1];
+  oneof port_specifier {
+    option (validate.required) = true;
+    uint32 port_value = 3 [(validate.rules).uint32.lte = 65535];
+    // This is only valid if :ref:`resolver_name
+    // <envoy_api_field_core.SocketAddress.resolver_name>` is specified below and the
+    // named resolver is capable of named port resolution.
+    string named_port = 4;
+  }
+  // The name of the resolver. This must have been registered with Envoy. If this is
+  // empty, a context dependent default applies. If address is a hostname this
+  // should be set for resolution other than DNS. If the address is a concrete
+  // IP address, no resolution will occur.
+  string resolver_name = 5;
+
+  // When binding to an IPv6 address above, this enables `IPv4 compatibility
+  // <https://tools.ietf.org/html/rfc3493#page-11>`_. Binding to ``::`` will
+  // allow both IPv4 and IPv6 connections, with peer IPv4 addresses mapped into
+  // IPv6 space as ``::FFFF:<IPv4-address>``.
+  bool ipv4_compat = 6;
+}
+
+message TcpKeepalive {
+  // Maximum number of keepalive probes to send without response before deciding
+  // the connection is dead. Default is to use the OS level configuration (unless
+  // overridden, Linux defaults to 9.)
+  google.protobuf.UInt32Value keepalive_probes = 1;
+  // The number of seconds a connection needs to be idle before keep-alive probes
+  // start being sent. Default is to use the OS level configuration (unless
+  // overridden, Linux defaults to 7200s (ie 2 hours.)
+  google.protobuf.UInt32Value keepalive_time = 2;
+  // The number of seconds between keep-alive probes. Default is to use the OS
+  // level configuration (unless overridden, Linux defaults to 75s.)
+  google.protobuf.UInt32Value keepalive_interval = 3;
+}
+
+message BindConfig {
+  // The address to bind to when creating a socket.
+  SocketAddress source_address = 1
+      [(validate.rules).message.required = true, (gogoproto.nullable) = false];
+
+  // Whether to set the *IP_FREEBIND* option when creating the socket. When this
+  // flag is set to true, allows the :ref:`source_address
+  // <envoy_api_field_UpstreamBindConfig.source_address>` to be an IP address
+  // that is not configured on the system running Envoy. When this flag is set
+  // to false, the option *IP_FREEBIND* is disabled on the socket. When this
+  // flag is not set (default), the socket is not modified, i.e. the option is
+  // neither enabled nor disabled.
+  google.protobuf.BoolValue freebind = 2;
+
+  // Additional socket options that may not be present in Envoy source code or
+  // precompiled binaries.
+  repeated SocketOption socket_options = 3;
+}
+
+// Addresses specify either a logical or physical address and port, which are
+// used to tell Envoy where to bind/listen, connect to upstream and find
+// management servers.
+message Address {
+  oneof address {
+    option (validate.required) = true;
+
+    SocketAddress socket_address = 1;
+    Pipe pipe = 2;
+  }
+}
+
+// CidrRange specifies an IP Address and a prefix length to construct
+// the subnet mask for a `CIDR <https://tools.ietf.org/html/rfc4632>`_ range.
+message CidrRange {
+  // IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``.
+  string address_prefix = 1 [(validate.rules).string.min_bytes = 1];
+  // Length of prefix, e.g. 0, 32.
+  google.protobuf.UInt32Value prefix_len = 2 [(validate.rules).uint32.lte = 128];
+}
diff --git a/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/api/v2/core/base.proto b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/api/v2/core/base.proto
index 3be09cd..6b4e931 100644
--- a/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/api/v2/core/base.proto
+++ b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/api/v2/core/base.proto
@@ -17,6 +17,7 @@ import "gogoproto/gogo.proto";
 import "envoy/type/percent.proto";
 
 option (gogoproto.equal_all) = true;
+option (gogoproto.stable_marshaler_all) = true;
 
 // [#protodoc-title: Common types]
 
@@ -78,3 +79,178 @@ message Node {
   // by Envoy in management server RPCs.
   string build_version = 5;
 }
+
+// Metadata provides additional inputs to filters based on matched listeners,
+// filter chains, routes and endpoints. It is structured as a map, usually from
+// filter name (in reverse DNS format) to metadata specific to the filter. Metadata
+// key-values for a filter are merged as connection and request handling occurs,
+// with later values for the same key overriding earlier values.
+//
+// An example use of metadata is providing additional values to
+// http_connection_manager in the envoy.http_connection_manager.access_log
+// namespace.
+//
+// Another example use of metadata is to per service config info in cluster metadata, which may get
+// consumed by multiple filters.
+//
+// For load balancing, Metadata provides a means to subset cluster endpoints.
+// Endpoints have a Metadata object associated and routes contain a Metadata
+// object to match against. There are some well defined metadata used today for
+// this purpose:
+//
+// * ``{"envoy.lb": {"canary": <bool> }}`` This indicates the canary status of an
+//   endpoint and is also used during header processing
+//   (x-envoy-upstream-canary) and for stats purposes.
+message Metadata {
+  // Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.*
+  // namespace is reserved for Envoy's built-in filters.
+  map<string, google.protobuf.Struct> filter_metadata = 1;
+}
+
+// Runtime derived uint32 with a default when not specified.
+message RuntimeUInt32 {
+  // Default value if runtime value is not available.
+  uint32 default_value = 2;
+
+  // Runtime key to get value for comparison. This value is used if defined.
+  string runtime_key = 3 [(validate.rules).string.min_bytes = 1];
+}
+
+// Envoy supports :ref:`upstream priority routing
+// <arch_overview_http_routing_priority>` both at the route and the virtual
+// cluster level. The current priority implementation uses different connection
+// pool and circuit breaking settings for each priority level. This means that
+// even for HTTP/2 requests, two physical connections will be used to an
+// upstream host. In the future Envoy will likely support true HTTP/2 priority
+// over a single upstream connection.
+enum RoutingPriority {
+  DEFAULT = 0;
+  HIGH = 1;
+}
+
+// HTTP request method.
+enum RequestMethod {
+  option (gogoproto.goproto_enum_prefix) = false;
+  METHOD_UNSPECIFIED = 0;
+  GET = 1;
+  HEAD = 2;
+  POST = 3;
+  PUT = 4;
+  DELETE = 5;
+  CONNECT = 6;
+  OPTIONS = 7;
+  TRACE = 8;
+}
+
+// Header name/value pair.
+message HeaderValue {
+  // Header name.
+  string key = 1 [(validate.rules).string = {min_bytes: 1, max_bytes: 16384}];
+
+  // Header value.
+  //
+  // The same :ref:`format specifier <config_access_log_format>` as used for
+  // :ref:`HTTP access logging <config_access_log>` applies here, however
+  // unknown header values are replaced with the empty string instead of `-`.
+  string value = 2 [(validate.rules).string.max_bytes = 16384];
+}
+
+// Header name/value pair plus option to control append behavior.
+message HeaderValueOption {
+  // Header name/value pair that this option applies to.
+  HeaderValue header = 1 [(validate.rules).message.required = true];
+
+  // Should the value be appended? If true (default), the value is appended to
+  // existing values.
+  google.protobuf.BoolValue append = 2;
+}
+
+// Wrapper for a set of headers.
+message HeaderMap {
+  repeated HeaderValue headers = 1;
+}
+
+// Data source consisting of either a file or an inline value.
+message DataSource {
+  oneof specifier {
+    option (validate.required) = true;
+
+    // Local filesystem data source.
+    string filename = 1 [(validate.rules).string.min_bytes = 1];
+
+    // Bytes inlined in the configuration.
+    bytes inline_bytes = 2 [(validate.rules).bytes.min_len = 1];
+
+    // String inlined in the configuration.
+    string inline_string = 3 [(validate.rules).string.min_bytes = 1];
+  }
+}
+
+// Configuration for transport socket in :ref:`listeners <config_listeners>` and
+// :ref:`clusters <envoy_api_msg_Cluster>`. If the configuration is
+// empty, a default transport socket implementation and configuration will be
+// chosen based on the platform and existence of tls_context.
+message TransportSocket {
+  // The name of the transport socket to instantiate. The name must match a supported transport
+  // socket implementation.
+  string name = 1 [(validate.rules).string.min_bytes = 1];
+
+  // Implementation specific configuration which depends on the implementation being instantiated.
+  // See the supported transport socket implementations for further documentation.
+  oneof config_type {
+    google.protobuf.Struct config = 2;
+
+    google.protobuf.Any typed_config = 3;
+  }
+}
+
+// Generic socket option message. This would be used to set socket options that
+// might not exist in upstream kernels or precompiled Envoy binaries.
+message SocketOption {
+  // An optional name to give this socket option for debugging, etc.
+  // Uniqueness is not required and no special meaning is assumed.
+  string description = 1;
+  // Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP
+  int64 level = 2;
+  // The numeric name as passed to setsockopt
+  int64 name = 3;
+  oneof value {
+    option (validate.required) = true;
+
+    // Because many sockopts take an int value.
+    int64 int_value = 4;
+    // Otherwise it's a byte buffer.
+    bytes buf_value = 5;
+  }
+  enum SocketState {
+    option (gogoproto.goproto_enum_prefix) = false;
+    // Socket options are applied after socket creation but before binding the socket to a port
+    STATE_PREBIND = 0;
+    // Socket options are applied after binding the socket to a port but before calling listen()
+    STATE_BOUND = 1;
+    // Socket options are applied after calling listen()
+    STATE_LISTENING = 2;
+  }
+  // The state in which the option will be applied. When used in BindConfig
+  // STATE_PREBIND is currently the only valid value.
+  SocketState state = 6
+      [(validate.rules).message.required = true, (validate.rules).enum.defined_only = true];
+}
+
+// Runtime derived FractionalPercent with defaults for when the numerator or denominator is not
+// specified via a runtime key.
+message RuntimeFractionalPercent {
+  // Default value if the runtime value's for the numerator/denominator keys are not available.
+  envoy.type.FractionalPercent default_value = 1 [(validate.rules).message.required = true];
+
+  // Runtime key for a YAML representation of a FractionalPercent.
+  string runtime_key = 2;
+}
+
+// Identifies a specific ControlPlane instance that Envoy is connected to.
+message ControlPlane {
+  // An opaque control plane identifier that uniquely identifies an instance
+  // of control plane. This can be used to identify which control plane instance,
+  // the Envoy is connected to.
+  string identifier = 1;
+}
diff --git a/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/data/accesslog/v2/accesslog.proto b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/data/accesslog/v2/accesslog.proto
new file mode 100644
index 0000000..b387433
--- /dev/null
+++ b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/data/accesslog/v2/accesslog.proto
@@ -0,0 +1,335 @@
+syntax = "proto3";
+
+package envoy.data.accesslog.v2;
+
+option java_outer_classname = "AccesslogProto";
+option java_multiple_files = true;
+option java_package = "io.envoyproxy.envoy.data.accesslog.v2";
+
+import "envoy/api/v2/core/address.proto";
+import "envoy/api/v2/core/base.proto";
+
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+import "gogoproto/gogo.proto";
+import "validate/validate.proto";
+
+option (gogoproto.stable_marshaler_all) = true;
+
+// [#protodoc-title: gRPC access logs]
+// 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.
+
+// [#not-implemented-hide:]
+message TCPAccessLogEntry {
+  // Common properties shared by all Envoy access logs.
+  AccessLogCommon common_properties = 1;
+}
+
+message HTTPAccessLogEntry {
+  // Common properties shared by all Envoy access logs.
+  AccessLogCommon common_properties = 1;
+
+  // HTTP version
+  enum HTTPVersion {
+    PROTOCOL_UNSPECIFIED = 0;
+    HTTP10 = 1;
+    HTTP11 = 2;
+    HTTP2 = 3;
+  }
+  HTTPVersion protocol_version = 2;
+
+  // Description of the incoming HTTP request.
+  HTTPRequestProperties request = 3;
+
+  // Description of the outgoing HTTP response.
+  HTTPResponseProperties response = 4;
+}
+
+// Defines fields that are shared by all Envoy access logs.
+message AccessLogCommon {
+  // [#not-implemented-hide:]
+  // 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 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.
+  envoy.api.v2.core.Address downstream_remote_address = 2;
+
+  // This field is the local/destination address on which the request from the user was received.
+  envoy.api.v2.core.Address downstream_local_address = 3;
+
+  // If the connection is secure,S this field will contain TLS properties.
+  TLSProperties tls_properties = 4;
+
+  // The time that Envoy started servicing this request. This is effectively the time that the first
+  // downstream byte is received.
+  google.protobuf.Timestamp start_time = 5 [(gogoproto.stdtime) = true];
+
+  // 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 = 6 [(gogoproto.stdduration) = true];
+
+  // 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.
+  google.protobuf.Duration time_to_first_upstream_tx_byte = 7 [(gogoproto.stdduration) = true];
+
+  // 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.
+  google.protobuf.Duration time_to_last_upstream_tx_byte = 8 [(gogoproto.stdduration) = true];
+
+  // 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 = 9 [(gogoproto.stdduration) = true];
+
+  // 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 = 10 [(gogoproto.stdduration) = true];
+
+  // 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.
+  google.protobuf.Duration time_to_first_downstream_tx_byte = 11 [(gogoproto.stdduration) = true];
+
+  // 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.
+  google.protobuf.Duration time_to_last_downstream_tx_byte = 12 [(gogoproto.stdduration) = true];
+
+  // The upstream remote/destination address that handles this exchange. This does not include
+  // retries.
+  envoy.api.v2.core.Address upstream_remote_address = 13;
+
+  // The upstream local/origin address that handles this exchange. This does not include retries.
+  envoy.api.v2.core.Address upstream_local_address = 14;
+
+  // The upstream cluster that *upstream_remote_address* belongs to.
+  string upstream_cluster = 15;
+
+  // Flags indicating occurrences during request/response processing.
+  ResponseFlags response_flags = 16;
+
+  // 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.
+  envoy.api.v2.core.Metadata metadata = 17;
+
+  // 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>`.
+  string upstream_transport_failure_reason = 18;
+}
+
+// Flags indicating occurrences during request/response processing.
+message ResponseFlags {
+  // Indicates local server healthcheck failed.
+  bool failed_local_healthcheck = 1;
+
+  // 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;
+
+  // Indicates remote codec level reset was received on the stream.
+  bool upstream_remote_reset = 5;
+
+  // Indicates there was a local reset by a connection pool due to an initial connection failure.
+  bool upstream_connection_failure = 6;
+
+  // Indicates the stream was reset due to an upstream connection termination.
+  bool upstream_connection_termination = 7;
+
+  // Indicates the stream was reset because of a resource overflow.
+  bool upstream_overflow = 8;
+
+  // Indicates no route was found for the request.
+  bool no_route_found = 9;
+
+  // Indicates that the request was delayed before proxying.
+  bool delay_injected = 10;
+
+  // Indicates that the request was aborted with an injected error code.
+  bool fault_injected = 11;
+
+  // Indicates that the request was rate-limited locally.
+  bool rate_limited = 12;
+
+  message Unauthorized {
+    // Reasons why the request was unauthorized
+    enum Reason {
+      REASON_UNSPECIFIED = 0;
+      // The request was denied by the external authorization service.
+      EXTERNAL_SERVICE = 1;
+    }
+
+    Reason reason = 1;
+  }
+
+  // Indicates if the request was deemed unauthorized and the reason for it.
+  Unauthorized unauthorized_details = 13;
+
+  // Indicates that the request was rejected because there was an error in rate limit service.
+  bool rate_limit_service_error = 14;
+
+  // Indicates the stream was reset due to a downstream connection termination.
+  bool downstream_connection_termination = 15;
+
+  // Indicates that the upstream retry limit was exceeded, resulting in a downstream error.
+  bool upstream_retry_limit_exceeded = 16;
+
+  // Indicates that the stream idle timeout was hit, resulting in a downstream 408.
+  bool stream_idle_timeout = 17;
+}
+
+// Properties of a negotiated TLS connection.
+message TLSProperties {
+  // [#not-implemented-hide:]
+  enum TLSVersion {
+    VERSION_UNSPECIFIED = 0;
+    TLSv1 = 1;
+    TLSv1_1 = 2;
+    TLSv1_2 = 3;
+    TLSv1_3 = 4;
+  }
+  // [#not-implemented-hide:]
+  // Version of TLS that was negotiated.
+  TLSVersion tls_version = 1;
+
+  // [#not-implemented-hide:]
+  // 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.
+  google.protobuf.UInt32Value tls_cipher_suite = 2;
+
+  // SNI hostname from handshake.
+  string tls_sni_hostname = 3;
+
+  message CertificateProperties {
+    message SubjectAltName {
+      oneof san {
+        string uri = 1;
+        // [#not-implemented-hide:]
+        string dns = 2;
+      }
+    }
+
+    // SANs present in the certificate.
+    repeated SubjectAltName subject_alt_name = 1;
+
+    // The subject field of the certificate.
+    string subject = 2;
+  }
+
+  // Properties of the local certificate used to negotiate TLS.
+  CertificateProperties local_certificate_properties = 4;
+
+  // Properties of the peer certificate used to negotiate TLS.
+  CertificateProperties peer_certificate_properties = 5;
+}
+
+message HTTPRequestProperties {
+  // The request method (RFC 7231/2616).
+  // [#comment:TODO(htuch): add (validate.rules).enum.defined_only = true once
+  // https://github.com/lyft/protoc-gen-validate/issues/42 is resolved.]
+  envoy.api.v2.core.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;
+
+  // Value of the ``User-Agent`` request header.
+  string user_agent = 6;
+
+  // Value of the ``Referer`` request header.
+  string referer = 7;
+
+  // 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.
+  string request_id = 9;
+
+  // Value of the ``X-Envoy-Original-Path`` request header.
+  string original_path = 10;
+
+  // 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.
+  uint64 request_headers_bytes = 11;
+
+  // 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.
+  uint64 request_body_bytes = 12;
+
+  // Map of additional headers that have been configured to be logged.
+  map<string, string> request_headers = 13;
+}
+
+message HTTPResponseProperties {
+  // The HTTP response code returned by Envoy.
+  google.protobuf.UInt32Value response_code = 1;
+
+  // 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.
+  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;
+
+  // Map of additional headers configured to be logged.
+  map<string, string> response_headers = 4;
+
+  // Map of trailers configured to be logged.
+  map<string, string> response_trailers = 5;
+}
diff --git a/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/service/accesslog/v2/als.proto b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/service/accesslog/v2/als.proto
new file mode 100644
index 0000000..1ee6ccd
--- /dev/null
+++ b/oap-server/server-receiver-plugin/receiver-proto/src/main/proto/envoy/service/accesslog/v2/als.proto
@@ -0,0 +1,73 @@
+syntax = "proto3";
+
+package envoy.service.accesslog.v2;
+
+option java_outer_classname = "AlsProto";
+option java_multiple_files = true;
+option java_package = "io.envoyproxy.envoy.service.accesslog.v2";
+option go_package = "v2";
+option java_generic_services = true;
+
+import "envoy/api/v2/core/base.proto";
+import "envoy/data/accesslog/v2/accesslog.proto";
+
+import "validate/validate.proto";
+
+// [#protodoc-title: gRPC Access Log Service (ALS)]
+
+// Service for streaming access logs from Envoy to an access log server.
+service AccessLogService {
+  // Envoy will connect and send StreamAccessLogsMessage messages forever. It does not expect any
+  // response to be sent as nothing would be done in the case of failure. The server should
+  // disconnect if it expects Envoy to reconnect. In the future we may decide to add a different
+  // API for "critical" access logs in which Envoy will buffer access logs for some period of time
+  // until it gets an ACK so it could then retry. This API is designed for high throughput with the
+  // expectation that it might be lossy.
+  rpc StreamAccessLogs(stream StreamAccessLogsMessage) returns (StreamAccessLogsResponse) {
+  }
+}
+
+// Empty response for the StreamAccessLogs API. Will never be sent. See below.
+message StreamAccessLogsResponse {
+}
+
+// Stream message for the StreamAccessLogs API. Envoy will open a stream to the server and stream
+// access logs without ever expecting a response.
+message StreamAccessLogsMessage {
+  message Identifier {
+    // The node sending the access log messages over the stream.
+    envoy.api.v2.core.Node node = 1 [(validate.rules).message.required = true];
+
+    // The friendly name of the log configured in :ref:`CommonGrpcAccessLogConfig
+    // <envoy_api_msg_config.accesslog.v2.CommonGrpcAccessLogConfig>`.
+    string log_name = 2 [(validate.rules).string.min_bytes = 1];
+  }
+
+  // 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 identifier = 1;
+
+  // Wrapper for batches of HTTP access log entries.
+  message HTTPAccessLogEntries {
+    repeated envoy.data.accesslog.v2.HTTPAccessLogEntry log_entry = 1
+        [(validate.rules).repeated .min_items = 1];
+  }
+
+  // [#not-implemented-hide:]
+  // Wrapper for batches of TCP access log entries.
+  message TCPAccessLogEntries {
+    repeated envoy.data.accesslog.v2.TCPAccessLogEntry log_entry = 1
+        [(validate.rules).repeated .min_items = 1];
+  }
+
+  // Batches of log entries of a single type. Generally speaking, a given stream should only
+  // ever include one type of log entry.
+  oneof log_entries {
+    option (validate.required) = true;
+
+    HTTPAccessLogEntries http_logs = 2;
+
+    // [#not-implemented-hide:]
+    TCPAccessLogEntries tcp_logs = 3;
+  }
+}