You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2022/06/19 14:11:36 UTC

[incubator-shenyu] branch master updated: [new : feature] add loggingElasticSearch plugin (#3580)

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

xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 30e0f6213 [new : feature] add loggingElasticSearch plugin (#3580)
30e0f6213 is described below

commit 30e0f6213379b7dfcaaa8c6f746bc0366a5d17a5
Author: qinghai777 <80...@users.noreply.github.com>
AuthorDate: Sun Jun 19 22:11:31 2022 +0800

    [new : feature] add loggingElasticSearch plugin (#3580)
    
    * add loggingElasticSearch plugin
    
    * modify es plugin
---
 db/init/mysql/schema.sql                           |   9 +
 db/init/oracle/schema.sql                          |  25 ++
 db/init/pg/create-table.sql                        |   9 +
 db/upgrade/2.4.3-upgrade-2.5.0-mysql.sql           |  15 +-
 db/upgrade/2.4.3-upgrade-2.5.0-pg.sql              |  15 +-
 pom.xml                                            |  16 +
 .../src/main/resources/sql-script/h2/schema.sql    |  11 +-
 shenyu-bootstrap/pom.xml                           |   8 +
 .../org/apache/shenyu/common/enums/PluginEnum.java |   5 +
 shenyu-plugin/shenyu-plugin-logging/pom.xml        |   1 +
 .../shenyu-plugin-logging-elasticsearch/pom.xml    |  66 ++++
 .../elasticsearch/AbstractLogCollector.java        | 115 ++++++
 .../logging/elasticsearch/DefaultLogCollector.java |  42 +++
 .../plugin/logging/elasticsearch/LogCollector.java |  38 ++
 .../logging/elasticsearch/LogConsumeClient.java    |  36 ++
 .../elasticsearch/LoggingElasticSearchPlugin.java  |  93 +++++
 .../logging/elasticsearch/body/BodyWriter.java     | 107 ++++++
 .../LoggingElasticSearchServerHttpRequest.java     |  65 ++++
 .../body/LoggingElasticSearchServerResponse.java   | 254 +++++++++++++
 .../elasticsearch/config/LogCollectConfig.java     | 250 +++++++++++++
 .../elasticsearch/constant/LoggingConstant.java    |  32 ++
 .../ElasticSearchLogCollectClient.java             | 145 ++++++++
 .../elasticsearch/entity/LZ4CompressData.java      |  69 ++++
 .../elasticsearch/entity/ShenyuRequestLog.java     | 407 +++++++++++++++++++++
 .../LoggingElasticSearchPluginDataHandler.java     | 145 ++++++++
 .../elasticsearch/sampler/CountSampler.java        | 115 ++++++
 .../logging/elasticsearch/sampler/Sampler.java     |  35 ++
 .../elasticsearch/utils/LogCollectConfigUtils.java | 143 ++++++++
 .../elasticsearch/utils/LogCollectUtils.java       |  62 ++++
 .../shenyu-spring-boot-starter-plugin/pom.xml      |   1 +
 .../pom.xml                                        |  31 +-
 .../LoggingElasticSearchPluginConfiguration.java   |  52 +++
 .../src/main/resources/META-INF/spring.factories   |  19 +
 .../src/main/resources/META-INF/spring.provides    |  18 +
 34 files changed, 2441 insertions(+), 13 deletions(-)

diff --git a/db/init/mysql/schema.sql b/db/init/mysql/schema.sql
index 0b87ed9c4..332780748 100644
--- a/db/init/mysql/schema.sql
+++ b/db/init/mysql/schema.sql
@@ -593,6 +593,7 @@ INSERT INTO `plugin` VALUES ('5', 'divide', '{\"multiSelectorHandle\":\"1\",\"mu
 INSERT INTO `plugin` VALUES ('6', 'dubbo', '{\"register\":\"zookeeper://localhost:2181\",\"multiSelectorHandle\":\"1\",\"threadpool\":\"cached\",\"corethreads\":0,\"threads\":2147483647,\"queues\":0}', 'Proxy', 310, 0, '2022-05-25 18:02:53', '2022-05-25 18:02:53');
 INSERT INTO `plugin` VALUES ('8', 'springCloud', NULL, 'Proxy', 200, 0, '2022-05-25 18:02:53', '2022-05-25 18:02:53');
 INSERT INTO `plugin` VALUES ('9', 'hystrix', NULL, 'FaultTolerance', 130, 0, '2022-05-25 18:02:53', '2022-05-25 18:02:53');
+INSERT INTO `plugin` VALUES ('32', 'loggingElasticSearch','{\"host\":\"localhost\", \"port\": \"9200\"}', 'Logging', 190, 0, '2022-06-19 22:00:00', '2022-06-19 22:00:00');
 
 -- ----------------------------
 -- Table structure for plugin_handle
@@ -779,6 +780,14 @@ INSERT INTO `plugin_handle` VALUES ('1529402613204172874', '11', 'queues', 'queu
 INSERT INTO `plugin_handle` VALUES ('1529402613204172875', '11', 'threadpool', 'threadpool', 3, 3, 3, '{\"required\":\"0\",\"defaultValue\":\"default\",\"placeholder\":\"threadpool\",\"rule\":\"\"}', '2022-05-25 18:02:53', '2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1537326008606343168', '31', 'responseContent', 'responseContent', 2, 2, 0, '{"required":"0","rule":""}', '2022-06-16 14:47:37', '2022-06-16 14:50:39');
 INSERT INTO `plugin_handle` VALUES ('1537325892176658432', '31', 'httpStatusCode', 'httpStatusCode', 1, 2, 0, '{"required":"0","defaultValue":"200","rule":""}', '2022-06-16 14:47:09', '2022-06-16 14:50:39');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172876', '32', 'host', 'host', 2, 3, 1, '{\"required\":\"1\",\"defaultValue\":\"localhost\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172877', '32', 'port', 'port', 2, 3, 2, '{\"required\":\"1\",\"defaultValue\":\"9200\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172878', '32', 'sampleRate', 'sampleRate', 2, 3, 3, '{\"required\":\"0\",\"defaultValue\":\"1\",\"placeholder\":\"optional,0,0.01~1\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172879', '32', 'maxResponseBody', 'maxResponseBody', 1, 3, 4, '{\"required\":\"0\",\"defaultValue\":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172880', '32', 'maxRequestBody', 'maxRequestBody', 1, 3, 5, '{\"required\":\"0\",\"defaultValue\":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172881', '32', 'compressAlg', 'compressAlg', 3, 3, 6, '{\"required\":\"0\",\"defaultValue\":\"none\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172882', '32', 'index', 'index', 2, 1, 1, '{\"required\":\"0\",\"defaultValue\":\"\",\"placeholder\":\"optional\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172883', '32', 'sampleRate', 'sampleRate', 2, 1, 2, '{\"required\":\"0\",\"defaultValue\":\"\",\"placeholder\":\"optional,0,0.01~1\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
 
 
 -- ----------------------------
diff --git a/db/init/oracle/schema.sql b/db/init/oracle/schema.sql
index 92b55c06c..50ba9348d 100644
--- a/db/init/oracle/schema.sql
+++ b/db/init/oracle/schema.sql
@@ -833,6 +833,7 @@ INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin(id)) */ INTO plugin (id, name, role
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin(id)) */ INTO plugin (id, name, role, sort, config, enabled) VALUES ('29', 'loggingRocketMQ', 'Logging', 170,'{"topic":"shenyu-access-logging", "namesrvAddr": "localhost:9876","producerGroup":"shenyu-plugin-logging-rocketmq"}', '0');
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin(id)) */ INTO plugin (id, name, config, role, sort, enabled) VALUES ('30', 'cache', '{"cacheType":"memory"}', 'Cache', 10, 0);
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin(id)) */ INTO plugin (id, name, role, sort, enabled) VALUES ('31', 'mock', 'Mock', 1, 0);
+INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin(id)) */ INTO plugin (id, name, role, sort, config, enabled) VALUES ('32', 'loggingElasticSearch', '{"host":"localhost", "port": "9200"}', 'Logging', 190, 0);
 
 
 
@@ -1315,6 +1316,30 @@ values ('1537326008606343168', '31', 'responseContent', 'responseContent', 2, 2,
 insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
 values ('1537325892176658432', '31', 'httpStatusCode', 'httpStatusCode', 1, 2, 0, '{"required":"0","defaultValue":"200","rule":""}');
 
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468168', '32', 'host', 'host', 2, 3, 1, '{"required":"1","defaultValue":"localhost"}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468169', '32', 'port', 'port', 2, 3, 2, '{"required":"1","defaultValue":"9200"}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468170', '32', 'sampleRate', 'sampleRate', 2, 3, 4, '{"required":"0","defaultValue":"1","placeholder":"optional,0,0.01~1"}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468171', '32', 'maxResponseBody', 'maxResponseBody', 1, 3, 5, '{"required":"0","defaultValue":524288}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468172', '32', 'maxRequestBody', 'maxRequestBody', 1, 3, 6, '{"required":"0","defaultValue":524288}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468173', '32', 'compressAlg', 'compressAlg', 3, 3, 7, '{"required":"0","defaultValue":"none"}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468174', '32', 'index', 'index', 2, 1, 1, '{"required":"0","defaultValue":"","placeholder":"optional"}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) */ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, EXT_OBJ)
+values ('1518229897214468175', '32', 'sampleRate', 'sampleRate', 2, 1, 2, '{"required":"0","defaultValue":"","placeholder":"optional,0,0.01~1"}');
+
 
 
 /** insert resource for resource */
diff --git a/db/init/pg/create-table.sql b/db/init/pg/create-table.sql
index a5b7ae2d2..d24fa2c73 100644
--- a/db/init/pg/create-table.sql
+++ b/db/init/pg/create-table.sql
@@ -670,6 +670,7 @@ INSERT INTO "public"."plugin" VALUES ('28', 'mqtt', '{"port": 9500,"bossGroupThr
 INSERT INTO "public"."plugin" VALUES ('29', 'loggingRocketMQ', '{"topic":"shenyu-access-logging", "namesrvAddr": "localhost:9876","producerGroup":"shenyu-plugin-logging-rocketmq"}', 'Logging', 170, 0, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
 INSERT INTO "public"."plugin" VALUES ('30', 'cache', '{"cacheType":"memory"}', 'Cache', 10, 0, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
 INSERT INTO "public"."plugin" VALUES ('31', 'mock', null, 'Mock', 1, 0, '2022-06-16 14:40:35', '2022-06-16 14:40:55');
+INSERT INTO "public"."plugin" VALUES ('32', 'loggingElasticSearch','{"host":"localhost", "port": "9200"}', 'Logging', 190, 0, '2022-06-19 22:00:00', '2022-06-19 22:00:00');
 
 -- ----------------------------
 -- Table structure for plugin_handle
@@ -864,6 +865,14 @@ INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524919', '11', 'queue
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524920', '11', 'threadpool', 'threadpool', 3, 3, 3, '{"required":"0","defaultValue":"default","placeholder":"threadpool","rule":""}', '2022-05-25 18:08:01', '2022-05-25 18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1537326008606343168', '31', 'responseContent', 'responseContent', 2, 2, 0, '{"required":"0","rule":""}', '2022-06-16 14:47:37', '2022-06-16 14:50:39');
 INSERT INTO "public"."plugin_handle" VALUES ('1537325892176658432', '31', 'httpStatusCode', 'httpStatusCode', 1, 2, 0, '{"required":"0","defaultValue":"200","rule":""}', '2022-06-16 14:47:09', '2022-06-16 14:50:39');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524921', '32', 'host', 'host', 2, 3, 2, '{"required":"1","defaultValue":"localhost"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524922', '32', 'port', 'port', 2, 3, 3, '{"required":"1","defaultValue":"9200"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524923', '32', 'sampleRate', 'sampleRate', 2, 3, 4, '{"required":"0","defaultValue":"1","placeholder":"optional,0,0.01~1"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524924', '32', 'maxResponseBody', 'maxResponseBody', 1, 3, 5, '{"required":"0","defaultValue":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524925', '32', 'maxRequestBody', 'maxRequestBody', 1, 3, 6, '{"required":"0","defaultValue":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524926', '32', 'compressAlg', 'compressAlg', 3, 3, 7, '{"required":"0","defaultValue":"none"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524927', '32', 'index', 'index', 2, 1, 1, '{"required":"0","defaultValue":"","placeholder":"optional"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524928', '32', 'sampleRate', 'sampleRate', 2, 1, 2, '{"required":"0","defaultValue":"","placeholder":"optional,0,0.01~1"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
 
 -- ----------------------------
 -- Table structure for resource
diff --git a/db/upgrade/2.4.3-upgrade-2.5.0-mysql.sql b/db/upgrade/2.4.3-upgrade-2.5.0-mysql.sql
index 31279985c..03efd48e7 100644
--- a/db/upgrade/2.4.3-upgrade-2.5.0-mysql.sql
+++ b/db/upgrade/2.4.3-upgrade-2.5.0-mysql.sql
@@ -71,4 +71,17 @@ INSERT INTO `resource` VALUES ('1534585531108564992', '1534585430311051264', 'se
 
 INSERT INTO `permission` VALUES ('1534577122279825408', '1346358560427216896', '1534577121923309568', '2022-06-09 00:44:32', '2022-06-09 00:44:31');
 INSERT INTO `permission` VALUES ('1534585430587875328', '1346358560427216896', '1534585430311051264', '2022-06-09 01:17:33', '2022-06-09 01:17:32');
-INSERT INTO `permission` VALUES ('1534585531389583360', '1346358560427216896', '1534585531108564992', '2022-06-09 01:17:57', '2022-06-09 01:17:56');
\ No newline at end of file
+INSERT INTO `permission` VALUES ('1534585531389583360', '1346358560427216896', '1534585531108564992', '2022-06-09 01:17:57', '2022-06-09 01:17:56');
+
+/* insert plugin for loggingElasticSearch  */
+INSERT INTO `plugin` VALUES ('32', 'loggingElasticSearch','{\"host\":\"localhost\", \"port\": \"9200\"}', 'Logging', 190, 0, '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+
+/*insert plugin_handle data for plugin loggingElasticSearch*/
+INSERT INTO `plugin_handle` VALUES ('1529402613204172876', '32', 'host', 'host', 2, 3, 1, '{\"required\":\"1\",\"defaultValue\":\"localhost\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172877', '32', 'port', 'port', 2, 3, 2, '{\"required\":\"1\",\"defaultValue\":\"9200\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172878', '32', 'sampleRate', 'sampleRate', 2, 3, 3, '{\"required\":\"0\",\"defaultValue\":\"1\",\"placeholder\":\"optional,0,0.01~1\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172879', '32', 'maxResponseBody', 'maxResponseBody', 1, 3, 4, '{\"required\":\"0\",\"defaultValue\":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172880', '32', 'maxRequestBody', 'maxRequestBody', 1, 3, 5, '{\"required\":\"0\",\"defaultValue\":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172881', '32', 'compressAlg', 'compressAlg', 3, 3, 6, '{\"required\":\"0\",\"defaultValue\":\"none\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172882', '32', 'index', 'index', 2, 1, 1, '{\"required\":\"0\",\"defaultValue\":\"\",\"placeholder\":\"optional\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO `plugin_handle` VALUES ('1529402613204172883', '32', 'sampleRate', 'sampleRate', 2, 1, 2, '{\"required\":\"0\",\"defaultValue\":\"\",\"placeholder\":\"optional,0,0.01~1\"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
\ No newline at end of file
diff --git a/db/upgrade/2.4.3-upgrade-2.5.0-pg.sql b/db/upgrade/2.4.3-upgrade-2.5.0-pg.sql
index 10c5cc0d6..59935fc69 100644
--- a/db/upgrade/2.4.3-upgrade-2.5.0-pg.sql
+++ b/db/upgrade/2.4.3-upgrade-2.5.0-pg.sql
@@ -81,4 +81,17 @@ INSERT INTO "public"."resource" VALUES ('1534585531108564992', '1534585430311051
 
 INSERT INTO "public"."permission" VALUES ('1529403932886044767', '1346358560427216896', '1534577121923309568', '2022-06-09 00:44:32', '2022-06-09 00:44:31');
 INSERT INTO "public"."permission" VALUES ('1529403932886044768', '1346358560427216896', '1534585430311051264', '2022-06-09 01:17:33', '2022-06-09 01:17:32');
-INSERT INTO "public"."permission" VALUES ('1529403932886044769', '1346358560427216896', '1534585531108564992', '2022-06-09 01:17:57', '2022-06-09 01:17:56');
\ No newline at end of file
+INSERT INTO "public"."permission" VALUES ('1529403932886044769', '1346358560427216896', '1534585531108564992', '2022-06-09 01:17:57', '2022-06-09 01:17:56');
+
+/* insert plugin for loggingElasticSearch  */
+INSERT INTO "public"."plugin" VALUES ('32', 'loggingElasticSearch','{"host":"localhost", "port": "9200"}', 'Logging', 190, 0, '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+
+/*insert plugin_handle data for plugin loggingElasticSearch*/
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524921', '32', 'host', 'host', 2, 3, 2, '{"required":"1","defaultValue":"localhost"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524922', '32', 'port', 'port', 2, 3, 3, '{"required":"1","defaultValue":"9200"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524923', '32', 'sampleRate', 'sampleRate', 2, 3, 4, '{"required":"0","defaultValue":"1","placeholder":"optional,0,0.01~1"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524924', '32', 'maxResponseBody', 'maxResponseBody', 1, 3, 5, '{"required":"0","defaultValue":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524925', '32', 'maxRequestBody', 'maxRequestBody', 1, 3, 6, '{"required":"0","defaultValue":524288}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524926', '32', 'compressAlg', 'compressAlg', 3, 3, 7, '{"required":"0","defaultValue":"none"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524927', '32', 'index', 'index', 2, 1, 1, '{"required":"0","defaultValue":"","placeholder":"optional"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
+INSERT INTO "public"."plugin_handle" VALUES ('1529403902783524928', '32', 'sampleRate', 'sampleRate', 2, 1, 2, '{"required":"0","defaultValue":"","placeholder":"optional,0,0.01~1"}', '2022-06-19 22:00:00', '2022-06-19 22:00:00');
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index b8edfc629..5d61956b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,6 +127,10 @@
         <grpc.version>1.33.1</grpc.version>
         <rocketmq-client.version>4.9.3</rocketmq-client.version>
         <lz4-java.version>1.8.0</lz4-java.version>
+        <elasticsearch-java.version>8.2.3</elasticsearch-java.version>
+        <jackson-databind.version>2.12.3</jackson-databind.version>
+        <jakarta.json-api.version>2.0.1</jakarta.json-api.version>
+        <elasticsearch-rest-client.version>8.2.3</elasticsearch-rest-client.version>
         <!--maven plugin version-->
         <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
         <jacoco-maven-plugin.version>0.8.7</jacoco-maven-plugin.version>
@@ -468,6 +472,18 @@
                 <version>${spring-cloud.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>org.elasticsearch.client</groupId>
+                <artifactId>elasticsearch-rest-client</artifactId>
+                <version>${elasticsearch-rest-client.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>jakarta.json</groupId>
+                <artifactId>jakarta.json-api</artifactId>
+                <version>${jakarta.json-api.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 
diff --git a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
index 13ef6efe7..6b617a91d 100644
--- a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
+++ b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
@@ -380,6 +380,7 @@ INSERT IGNORE INTO `plugin` (`id`, `name`, `role`, `sort`, `config`, `enabled`)
 INSERT IGNORE INTO `plugin` (`id`, `name`, `role`, `sort`, `config`, `enabled`) VALUES ('29', 'loggingRocketMQ', 'Logging', 170,'{"topic":"shenyu-access-logging", "namesrvAddr": "localhost:9876","producerGroup":"shenyu-plugin-logging-rocketmq"}', '0');
 INSERT IGNORE INTO `plugin` (`id`, `name`, `config`, `role`, `sort`, `enabled`) VALUES ('30', 'cache', '{"cacheType":"memory"}', 'Cache', 10, 0);
 INSERT IGNORE INTO `plugin` (`id`, `name`, `config`, `role`, `sort`, `enabled`) VALUES ('31', 'mock', null, 'Mock', 1, 0);
+INSERT IGNORE INTO `plugin` (`id`, `name`, `role`, `sort`, `config`, `enabled`) VALUES ('32', 'loggingElasticSearch', 'Logging', 190,'{"host":"localhost", "port": "9200"}', '0');
 
 /*insert plugin_handle data for sentinel*/
 INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613195784246', '10', 'flowRuleGrade', 'flowRuleGrade', 3, 2, 8, '{"required":"1","defaultValue":"1","rule":""}');
@@ -543,8 +544,16 @@ INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,
 INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172873', '11', 'threads', 'threads', 1, 3, 5, '{"required":"0","defaultValue":"2147483647","placeholder":"threads","rule":""}');
 INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172874', '11', 'queues', 'queues', 1, 3, 6, '{"required":"0","defaultValue":"0","placeholder":"queues","rule":""}');
 INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172875', '11', 'threadpool', 'threadpool', 3, 3, 3, '{"required":"0","defaultValue":"default","placeholder":"threadpool","rule":""}');
-INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES  ('1537326008606343168', '31', 'responseContent', 'responseContent', 2, 2, 0, '{"required":"0","rule":""}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1537326008606343168', '31', 'responseContent', 'responseContent', 2, 2, 0, '{"required":"0","rule":""}');
 INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1537325892176658432', '31', 'httpStatusCode', 'httpStatusCode', 1, 2, 0, '{"required":"0","defaultValue":"200","rule":""}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172876', '32', 'host', 'host', 2, 3, 1, '{"required":"1","defaultValue":"localhost"}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172877', '32', 'port', 'port', 2, 3, 2, '{"required":"1","defaultValue":"9200"}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172878', '32', 'sampleRate', 'sampleRate', 2, 3, 3, '{"required":"0","defaultValue":"1","placeholder":"optional,0,0.01~1"}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172879', '32', 'maxResponseBody', 'maxResponseBody', 1, 3, 4, '{"required":"0","defaultValue":524288}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172880', '32', 'maxRequestBody', 'maxRequestBody', 1, 3, 5, '{"required":"0","defaultValue":524288}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172881', '32', 'compressAlg', 'compressAlg', 3, 3, 6, '{"required":"0","defaultValue":"none"}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172882', '32', 'index', 'index', 2, 1, 1, '{"required":"0","defaultValue":"","placeholder":"optional"}');
+INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172883', '32', 'sampleRate', 'sampleRate', 2, 1, 2, '{"required":"0","defaultValue":"","placeholder":"optional,0,0.01~1"}');
 
 
 
diff --git a/shenyu-bootstrap/pom.xml b/shenyu-bootstrap/pom.xml
index 7f626dbeb..60cfd3aaa 100644
--- a/shenyu-bootstrap/pom.xml
+++ b/shenyu-bootstrap/pom.xml
@@ -469,6 +469,14 @@
             <version>${project.version}</version>
         </dependency>
         <!--shenyu logging-rocketmq plugin end-->
+
+        <!--shenyu logging-elasticsearch plugin start-->
+        <dependency>
+            <groupId>org.apache.shenyu</groupId>
+            <artifactId>shenyu-spring-boot-starter-plugin-logging-elasticsearch</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!--shenyu logging-elasticsearch plugin end-->
     </dependencies>
     <profiles>
         <profile>
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/PluginEnum.java b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/PluginEnum.java
index 9548c306c..3ec0276c7 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/PluginEnum.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/PluginEnum.java
@@ -134,6 +134,11 @@ public enum PluginEnum {
      * Logging RocketMQ plugin enum.
      */
     LOGGING_ROCKETMQ(170, 0, "loggingRocketMQ"),
+
+    /**
+     * Logging ElasticSearch plugin enum.
+     */
+    LOGGING_ElasticSearch(190, 0, "loggingElasticSearch"),
     
     /**
      * Divide plugin enum.
diff --git a/shenyu-plugin/shenyu-plugin-logging/pom.xml b/shenyu-plugin/shenyu-plugin-logging/pom.xml
index dddc7a374..beb8864ef 100644
--- a/shenyu-plugin/shenyu-plugin-logging/pom.xml
+++ b/shenyu-plugin/shenyu-plugin-logging/pom.xml
@@ -31,5 +31,6 @@
     <modules>
         <module>shenyu-plugin-logging-console</module>
         <module>shenyu-plugin-logging-rocketmq</module>
+        <module>shenyu-plugin-logging-elasticsearch</module>
     </modules>
 </project>
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/pom.xml b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/pom.xml
new file mode 100644
index 000000000..23897f460
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.shenyu</groupId>
+        <artifactId>shenyu-plugin-logging</artifactId>
+        <version>2.5.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>shenyu-plugin-logging-elasticsearch</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.shenyu</groupId>
+            <artifactId>shenyu-plugin-base</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.lz4</groupId>
+            <artifactId>lz4-java</artifactId>
+            <version>${lz4-java.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>co.elastic.clients</groupId>
+            <artifactId>elasticsearch-java</artifactId>
+            <version>${elasticsearch-java.version}</version>
+       </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson-databind.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.json</groupId>
+            <artifactId>jakarta.json-api</artifactId>
+            <version>${jakarta.json-api.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/AbstractLogCollector.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/AbstractLogCollector.java
new file mode 100644
index 000000000..4aa98db44
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/AbstractLogCollector.java
@@ -0,0 +1,115 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch;
+
+import org.apache.shenyu.common.utils.ThreadUtils;
+import org.apache.shenyu.plugin.logging.elasticsearch.entity.ShenyuRequestLog;
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectConfigUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * abstract log collector,Contains common methods.
+ */
+public abstract class AbstractLogCollector implements LogCollector {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractLogCollector.class);
+
+    private int bufferSize;
+
+    private BlockingQueue<ShenyuRequestLog> bufferQueue;
+
+    private long lastPushTime;
+
+    private final AtomicBoolean started = new AtomicBoolean(true);
+
+    @Override
+    public void start() {
+        bufferSize = LogCollectConfigUtils.getGlobalLogConfig().getBufferQueueSize();
+        bufferQueue = new LinkedBlockingDeque<>(bufferSize);
+        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
+        started.set(true);
+        threadExecutor.execute(this::consume);
+    }
+
+    @Override
+    public void collect(final ShenyuRequestLog log) {
+        if (Objects.isNull(log) || Objects.isNull(getLogConsumeClient())) {
+            return;
+        }
+        if (bufferQueue.size() < bufferSize) {
+            bufferQueue.add(log);
+        }
+    }
+
+    /**
+     * batch and async consume.
+     */
+    private void consume() {
+        while (started.get()) {
+            int diffTimeMSForPush = 100;
+            try {
+                List<ShenyuRequestLog> logs = new ArrayList<>();
+                int size = bufferQueue.size();
+                long time = System.currentTimeMillis();
+                long timeDiffMs = time - lastPushTime;
+                int batchSize = 100;
+                if (size >= batchSize || timeDiffMs > diffTimeMSForPush) {
+                    bufferQueue.drainTo(logs, batchSize);
+                    LogConsumeClient logCollectClient = getLogConsumeClient();
+                    if (logCollectClient != null) {
+                        logCollectClient.consume(logs);
+                    }
+                    lastPushTime = time;
+                } else {
+                    ThreadUtils.sleep(TimeUnit.MILLISECONDS, diffTimeMSForPush);
+                }
+            } catch (Exception e) {
+                LOG.error("DefaultLogCollector collect log error", e);
+                ThreadUtils.sleep(TimeUnit.MILLISECONDS, diffTimeMSForPush);
+            }
+        }
+    }
+
+    /**
+     * get log consume client.
+     *
+     * @return log consume client
+     */
+    protected abstract LogConsumeClient getLogConsumeClient();
+
+    @Override
+    public void close() throws Exception {
+        started.set(false);
+        LogConsumeClient logCollectClient = getLogConsumeClient();
+        if (logCollectClient != null) {
+            logCollectClient.close();
+        }
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/DefaultLogCollector.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/DefaultLogCollector.java
new file mode 100644
index 000000000..29d4ae72b
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/DefaultLogCollector.java
@@ -0,0 +1,42 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch;
+
+import org.apache.shenyu.plugin.logging.elasticsearch.handler.LoggingElasticSearchPluginDataHandler;
+
+/**
+ * default log collector,depend a LogConsumeClient for consume logs.
+ */
+public class DefaultLogCollector extends AbstractLogCollector {
+
+    private static final LogCollector INSTANCE = new DefaultLogCollector();
+
+    /**
+     * get LogCollector instance.
+     *
+     * @return LogCollector instance
+     */
+    public static LogCollector getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected LogConsumeClient getLogConsumeClient() {
+        return LoggingElasticSearchPluginDataHandler.getElasticSearchLogCollectClient();
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LogCollector.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LogCollector.java
new file mode 100644
index 000000000..04d2595c6
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LogCollector.java
@@ -0,0 +1,38 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch;
+
+import org.apache.shenyu.plugin.logging.elasticsearch.entity.ShenyuRequestLog;
+
+/**
+ * Collect logs and put into buffer queue.
+ */
+public interface LogCollector extends AutoCloseable {
+
+    /**
+     * start log collector.
+     */
+    void start();
+
+    /**
+     * collect log.
+     *
+     * @param log access log
+     */
+    void collect(ShenyuRequestLog log);
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LogConsumeClient.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LogConsumeClient.java
new file mode 100644
index 000000000..0d3810f67
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LogConsumeClient.java
@@ -0,0 +1,36 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch;
+
+import org.apache.shenyu.plugin.logging.elasticsearch.entity.ShenyuRequestLog;
+
+import java.util.List;
+
+/**
+ * Used to collect logs, which can be stored in remote or local files or databases, or others.
+ */
+public interface LogConsumeClient extends AutoCloseable {
+    
+    /**
+     * collect logs.
+     *
+     * @param logs list of log
+     * @throws Exception produce exception
+     */
+    void consume(List<ShenyuRequestLog> logs) throws Exception;
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LoggingElasticSearchPlugin.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LoggingElasticSearchPlugin.java
new file mode 100644
index 000000000..0c861540e
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/LoggingElasticSearchPlugin.java
@@ -0,0 +1,93 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch;
+
+import org.apache.shenyu.common.dto.RuleData;
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.plugin.api.ShenyuPluginChain;
+import org.apache.shenyu.plugin.base.AbstractShenyuPlugin;
+import org.apache.shenyu.plugin.base.utils.HostAddressUtils;
+import org.apache.shenyu.plugin.logging.elasticsearch.body.LoggingElasticSearchServerHttpRequest;
+import org.apache.shenyu.plugin.logging.elasticsearch.body.LoggingElasticSearchServerResponse;
+import org.apache.shenyu.plugin.logging.elasticsearch.entity.ShenyuRequestLog;
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectConfigUtils;
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectUtils;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import static org.apache.shenyu.common.enums.PluginEnum.LOGGING_ElasticSearch;
+
+/**
+ * Integrated elasticsearch collect log.
+ */
+public class LoggingElasticSearchPlugin extends AbstractShenyuPlugin {
+
+    private static final String USER_AGENT = "User-Agent";
+
+    private static final String HOST = "Host";
+
+    @Override
+    protected Mono<Void> doExecute(final ServerWebExchange exchange, final ShenyuPluginChain chain,
+                                   final SelectorData selector, final RuleData rule) {
+        ServerHttpRequest request = exchange.getRequest();
+        // control sampling
+        if (!LogCollectConfigUtils.isSampled(exchange.getRequest())) {
+            return chain.execute(exchange);
+        }
+
+        ShenyuRequestLog requestInfo = new ShenyuRequestLog();
+        requestInfo.setRequestUri(request.getURI().toString());
+        requestInfo.setMethod(request.getMethodValue());
+        requestInfo.setRequestHeader(LogCollectUtils.getHeaders(request.getHeaders()));
+        requestInfo.setQueryParams(request.getURI().getQuery());
+        requestInfo.setClientIp(HostAddressUtils.acquireIp(exchange));
+        requestInfo.setUserAgent(request.getHeaders().getFirst(USER_AGENT));
+        requestInfo.setHost(request.getHeaders().getFirst(HOST));
+        requestInfo.setPath(request.getURI().getPath());
+
+        LoggingElasticSearchServerHttpRequest loggingElasticSearchServerHttpRequest = new LoggingElasticSearchServerHttpRequest(request, requestInfo);
+        LoggingElasticSearchServerResponse loggingElasticSearchServerResponse = new LoggingElasticSearchServerResponse(exchange.getResponse(),
+                requestInfo, DefaultLogCollector.getInstance());
+        ServerWebExchange webExchange = exchange.mutate().request(loggingElasticSearchServerHttpRequest)
+                .response(loggingElasticSearchServerResponse).build();
+        loggingElasticSearchServerResponse.setExchange(webExchange);
+
+        return chain.execute(webExchange).doOnError(loggingElasticSearchServerResponse::logError);
+    }
+
+    /**
+     * get plugin order.
+     *
+     * @return order
+     */
+    @Override
+    public int getOrder() {
+        return LOGGING_ElasticSearch.getCode();
+    }
+
+    /**
+     * get plugin name.
+     *
+     * @return plugin name
+     */
+    @Override
+    public String named() {
+        return LOGGING_ElasticSearch.getName();
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/BodyWriter.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/BodyWriter.java
new file mode 100644
index 000000000..8ff7ae73e
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/BodyWriter.java
@@ -0,0 +1,107 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.body;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * bodyWriter is used to read Body.
+ */
+public class BodyWriter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BodyWriter.class);
+
+    private final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+    private final WritableByteChannel channel = Channels.newChannel(stream);
+
+    private final AtomicBoolean isClosed = new AtomicBoolean(false);
+
+
+    /**
+     * write ByteBuffer.
+     *
+     * @param buffer byte buffer
+     */
+    public void write(final ByteBuffer buffer) {
+        if (!isClosed.get()) {
+            try {
+                channel.write(buffer);
+            } catch (IOException e) {
+                isClosed.compareAndSet(false, true);
+                LOG.error("write buffer Failed.", e);
+            }
+        }
+    }
+
+    /**
+     * get stream size.
+     *
+     * @return size of stream
+     */
+    public int size() {
+        return stream.size();
+    }
+
+    /**
+     * output stream value.
+     *
+     * @return string of stream
+     */
+    public String output() {
+        if (isEmpty()) {
+            return "";
+        }
+        try {
+            isClosed.compareAndSet(false, true);
+            return new String(stream.toByteArray(), StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            LOG.error("Write failed: ", e);
+            return "Write failed: " + e.getMessage();
+        } finally {
+            try {
+                stream.close();
+            } catch (IOException e) {
+                LOG.error("Close stream error: ", e);
+            }
+            try {
+                channel.close();
+            } catch (IOException e) {
+                LOG.error("Close channel error: ", e);
+            }
+        }
+    }
+
+    /**
+     * judge stream is empty.
+     *
+     * @return true: stream is empty
+     */
+    boolean isEmpty() {
+        return stream.size() == 0;
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/LoggingElasticSearchServerHttpRequest.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/LoggingElasticSearchServerHttpRequest.java
new file mode 100644
index 000000000..8dd57407a
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/LoggingElasticSearchServerHttpRequest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.body;
+
+import org.apache.shenyu.plugin.logging.elasticsearch.entity.ShenyuRequestLog;
+
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectConfigUtils;
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectUtils;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
+import reactor.core.publisher.Flux;
+import reactor.util.annotation.NonNull;
+
+/**
+ * decorate ServerHttpRequest for read org.apache.shenyu.plugin.logging.body.
+ */
+public class LoggingElasticSearchServerHttpRequest extends ServerHttpRequestDecorator {
+    
+    private final ShenyuRequestLog logInfo;
+
+    public LoggingElasticSearchServerHttpRequest(final ServerHttpRequest delegate, final ShenyuRequestLog logInfo) {
+        super(delegate);
+        this.logInfo = logInfo;
+    }
+
+    /**
+     * get request org.apache.shenyu.plugin.logging.body.
+     *
+     * @return Flux
+     */
+    @Override
+    @NonNull
+    public Flux<DataBuffer> getBody() {
+        BodyWriter writer = new BodyWriter();
+        return super.getBody().doOnNext(dataBuffer -> {
+            if (LogCollectUtils.isNotBinaryType(getHeaders())) {
+                writer.write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
+            }
+        }).doFinally(signal -> {
+            int size = writer.size();
+            String body = writer.output();
+            boolean requestBodyTooLarge = LogCollectConfigUtils.isRequestBodyTooLarge(size);
+            if (size == 0 || requestBodyTooLarge) {
+                return;
+            }
+            logInfo.setRequestBody(body);
+        });
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/LoggingElasticSearchServerResponse.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/LoggingElasticSearchServerResponse.java
new file mode 100644
index 000000000..89fed618c
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/body/LoggingElasticSearchServerResponse.java
@@ -0,0 +1,254 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.body;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.enums.RpcTypeEnum;
+import org.apache.shenyu.common.utils.DateUtils;
+import org.apache.shenyu.plugin.api.context.ShenyuContext;
+import org.apache.shenyu.plugin.api.result.ShenyuResult;
+import org.apache.shenyu.plugin.api.result.ShenyuResultWrap;
+import org.apache.shenyu.plugin.logging.elasticsearch.entity.ShenyuRequestLog;
+import org.apache.shenyu.plugin.logging.elasticsearch.DefaultLogCollector;
+import org.apache.shenyu.plugin.logging.elasticsearch.LogCollector;
+import org.apache.shenyu.plugin.logging.elasticsearch.constant.LoggingConstant;
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectConfigUtils;
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectUtils;
+import org.reactivestreams.Publisher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.util.annotation.NonNull;
+
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * decorate ServerHttpResponse for read org.apache.shenyu.plugin.logging.body.
+ */
+public class LoggingElasticSearchServerResponse extends ServerHttpResponseDecorator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LoggingElasticSearchServerResponse.class);
+
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
+
+    private final ShenyuRequestLog logInfo;
+
+    private ServerWebExchange exchange;
+
+    private final LogCollector logCollector;
+
+    /**
+     * Constructor LoggingServerHttpResponse.
+     *
+     * @param delegate     delegate ServerHttpResponse
+     * @param logInfo      access log
+     * @param logCollector LogCollector  instance
+     */
+    public LoggingElasticSearchServerResponse(final ServerHttpResponse delegate, final ShenyuRequestLog logInfo,
+                                              final LogCollector logCollector) {
+        super(delegate);
+        this.logInfo = logInfo;
+        this.logCollector = logCollector;
+    }
+
+    /**
+     * set relevant ServerWebExchange.
+     *
+     * @param exchange ServerWebExchange
+     */
+    public void setExchange(final ServerWebExchange exchange) {
+        this.exchange = exchange;
+    }
+
+    /**
+     * write with a publisher.
+     *
+     * @param body response org.apache.shenyu.plugin.logging.body
+     * @return Mono
+     */
+    @Override
+    @NonNull
+    public Mono<Void> writeWith(@NonNull final Publisher<? extends DataBuffer> body) {
+        return super.writeWith(appendResponse(body));
+    }
+
+    /**
+     * append response.
+     *
+     * @param body publisher
+     * @return wrap Flux
+     */
+    @NonNull
+    private Flux<? extends DataBuffer> appendResponse(final Publisher<? extends DataBuffer> body) {
+        ShenyuContext shenyuContext = exchange.getAttribute(Constants.CONTEXT);
+        assert shenyuContext != null;
+        if (getStatusCode() != null) {
+            logInfo.setStatus(getStatusCode().value());
+        }
+        logInfo.setResponseHeader(LogCollectUtils.getHeaders(getHeaders()));
+        BodyWriter writer = new BodyWriter();
+        logInfo.setTraceId(getTraceId());
+        return Flux.from(body).doOnNext(buffer -> {
+            if (LogCollectUtils.isNotBinaryType(getHeaders())) {
+                writer.write(buffer.asByteBuffer().asReadOnlyBuffer());
+            }
+        }).doFinally(signal -> logResponse(shenyuContext, writer));
+    }
+
+    /**
+     * record response log.
+     *
+     * @param shenyuContext request context
+     * @param writer        bodyWriter
+     */
+    private void logResponse(final ShenyuContext shenyuContext, final BodyWriter writer) {
+        if (StringUtils.isNotBlank(getHeaders().getFirst(HttpHeaders.CONTENT_LENGTH))) {
+            String size = StringUtils.defaultIfEmpty(getHeaders().getFirst(HttpHeaders.CONTENT_LENGTH), "0");
+            logInfo.setResponseContentLength(Integer.parseInt(size));
+        } else {
+            logInfo.setResponseContentLength(writer.size());
+        }
+        logInfo.setTimeLocal(shenyuContext.getStartDateTime().format(DATE_TIME_FORMATTER));
+        logInfo.setModule(shenyuContext.getModule());
+        long costTime = DateUtils.acquireMillisBetween(shenyuContext.getStartDateTime(), LocalDateTime.now());
+        logInfo.setUpstreamResponseTime(costTime);
+        logInfo.setMethod(shenyuContext.getMethod());
+        logInfo.setRpcType(shenyuContext.getRpcType());
+        if (StringUtils.isNotBlank(shenyuContext.getRpcType())) {
+            logInfo.setUpstreamIp(getUpstreamIp());
+        }
+        int size = writer.size();
+        String body = writer.output();
+        if (size > 0 && !LogCollectConfigUtils.isResponseBodyTooLarge(size)) {
+            logInfo.setResponseBody(body);
+        }
+        // collect log
+        if (logCollector != null) {
+            logCollector.collect(logInfo);
+        }
+    }
+
+    /**
+     * get upstream ip.
+     *
+     * @return upstream ip
+     */
+    private String getUpstreamIp() {
+        ShenyuContext shenyuContext = exchange.getAttribute(Constants.CONTEXT);
+        assert shenyuContext != null;
+        if (RpcTypeEnum.HTTP.getName().equals(shenyuContext.getRpcType())) {
+            URI uri = exchange.getAttribute(Constants.HTTP_URI);
+            if (uri != null) {
+                return uri.getHost();
+            } else {
+                return getUpstreamIpFromHttpDomain();
+            }
+        } else {
+            String domain = (String) exchange.getAttributes().get(Constants.HTTP_DOMAIN);
+            if (StringUtils.isNotBlank(domain)) {
+                return getUpstreamIpFromHttpDomain();
+            }
+            // The current context is difficult to obtain the upstream IP of grpc and Dubbo. need change plugin code.
+        }
+        return "";
+    }
+
+    /**
+     * Encourage developers to provide plugins to upstream like SkyWalking, ZipKin and OpenTelemetry
+     * to implement the tracing features. These plug-ins can set a traceId to the context.
+     *
+     * @return traceId
+     */
+    private String getTraceId() {
+        return (String) exchange.getAttributes().get(LoggingConstant.SHENYU_AGENT_TRACE_ID);
+    }
+
+    /**
+     * collect access error.
+     *
+     * @param throwable Exception occurred。
+     */
+    public void logError(final Throwable throwable) {
+        HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
+        if (throwable instanceof ResponseStatusException) {
+            httpStatus = ((ResponseStatusException) throwable).getStatus();
+        }
+        logInfo.setStatus(httpStatus.value());
+        logInfo.setTraceId(getTraceId());
+        // Do not collect stack
+        Object result = ShenyuResultWrap.error(exchange, httpStatus.value(),
+                httpStatus.getReasonPhrase(), throwable.getMessage());
+        final ShenyuResult<?> shenyuResult = ShenyuResultWrap.shenyuResult();
+        Object resultData = shenyuResult.format(exchange, result);
+        final Object responseData = shenyuResult.result(exchange, resultData);
+        assert null != responseData;
+        final byte[] bytes = (responseData instanceof byte[])
+                ? (byte[]) responseData
+                : responseData.toString().getBytes(StandardCharsets.UTF_8);
+        logInfo.setResponseContentLength(bytes.length);
+        ShenyuContext shenyuContext = exchange.getAttribute(Constants.CONTEXT);
+        assert shenyuContext != null;
+        logInfo.setTimeLocal(shenyuContext.getStartDateTime().format(DATE_TIME_FORMATTER));
+        logInfo.setModule(shenyuContext.getModule());
+        long costTime = DateUtils.acquireMillisBetween(shenyuContext.getStartDateTime(), LocalDateTime.now());
+        logInfo.setUpstreamResponseTime(costTime);
+        logInfo.setResponseHeader(LogCollectUtils.getHeaders(exchange.getResponse().getHeaders()));
+        logInfo.setRpcType(shenyuContext.getRpcType());
+        logInfo.setMethod(shenyuContext.getMethod());
+        if (StringUtils.isNotBlank(shenyuContext.getRpcType())) {
+            logInfo.setUpstreamIp(getUpstreamIp());
+        }
+
+        int size = bytes.length;
+        String body = new String(bytes, StandardCharsets.UTF_8);
+        if (size > 0 && !LogCollectConfigUtils.isResponseBodyTooLarge(size)) {
+            logInfo.setResponseBody(body);
+        }
+        // collect log
+        if (DefaultLogCollector.getInstance() != null) {
+            DefaultLogCollector.getInstance().collect(logInfo);
+        }
+    }
+
+    private String getUpstreamIpFromHttpDomain() {
+        String domain = (String) exchange.getAttributes().get(Constants.HTTP_DOMAIN);
+        try {
+            if (StringUtils.isNotBlank(domain)) {
+                URL url = new URL(domain);
+                return url.getHost();
+            }
+        } catch (Exception e) {
+            LOG.error("get upstream ip error");
+        }
+        return "";
+    }
+
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/config/LogCollectConfig.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/config/LogCollectConfig.java
new file mode 100644
index 000000000..96d064955
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/config/LogCollectConfig.java
@@ -0,0 +1,250 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.config;
+
+/**
+ * log collect config, include elasticsearch config.
+ * Host and port must be included, and others are optional.
+ * We should operate the configuration through admin instead of the configuration file.
+ */
+public class LogCollectConfig {
+
+    private GlobalLogConfig globalLogConfig;
+
+    /**
+     * get global log config.
+     *
+     * @return global log config
+     */
+    public GlobalLogConfig getGlobalLogConfig() {
+        return globalLogConfig;
+    }
+
+    /**
+     * set global log config.
+     *
+     * @param globalLogConfig global log config.
+     */
+    public void setGlobalLogConfig(final GlobalLogConfig globalLogConfig) {
+        this.globalLogConfig = globalLogConfig;
+    }
+
+    /**
+     * global log config.
+     */
+    public static class GlobalLogConfig {
+
+        private String host;
+
+        private String port;
+
+        private String sampleRate = "1";
+
+        private String compressAlg;
+
+        /**
+         * default 512KB.
+         */
+        private int maxResponseBody = 524288;
+
+        /**
+         * default 512kb.
+         */
+        private int maxRequestBody = 524288;
+
+        private int bufferQueueSize = 50000;
+
+        /**
+         * get sample rate.
+         *
+         * @return sample
+         */
+        public String getSampleRate() {
+            return sampleRate;
+        }
+
+        /**
+         * set sample rate.
+         *
+         * @param sampleRate rate
+         */
+        public void setSampleRate(final String sampleRate) {
+            this.sampleRate = sampleRate;
+        }
+
+        /**
+         * whether compress.
+         *
+         * @return compress or not
+         */
+        public String getCompressAlg() {
+            return compressAlg;
+        }
+
+        /**
+         * set compress.
+         *
+         * @param compressAlg compress alg.
+         */
+        public void setCompressAlg(final String compressAlg) {
+            this.compressAlg = compressAlg;
+        }
+
+        /**
+         * get max response org.apache.shenyu.plugin.logging.body.
+         *
+         * @return get max response org.apache.shenyu.plugin.logging.body
+         */
+        public int getMaxResponseBody() {
+            return maxResponseBody;
+        }
+
+        /**
+         * set max response org.apache.shenyu.plugin.logging.body.
+         *
+         * @param maxResponseBody max response org.apache.shenyu.plugin.logging.body
+         */
+        public void setMaxResponseBody(final int maxResponseBody) {
+            this.maxResponseBody = maxResponseBody;
+        }
+
+        /**
+         * get max request org.apache.shenyu.plugin.logging.body.
+         *
+         * @return max request org.apache.shenyu.plugin.logging.body
+         */
+        public int getMaxRequestBody() {
+            return maxRequestBody;
+        }
+
+        /**
+         * set max request org.apache.shenyu.plugin.logging.body.
+         *
+         * @param maxRequestBody max request org.apache.shenyu.plugin.logging.body
+         */
+        public void setMaxRequestBody(final int maxRequestBody) {
+            this.maxRequestBody = maxRequestBody;
+        }
+
+        /**
+         * get buffer queue size.
+         *
+         * @return buffer queue size
+         */
+        public int getBufferQueueSize() {
+            return bufferQueueSize;
+        }
+
+        /**
+         * set buffer queue size.
+         *
+         * @param bufferQueueSize buffer queue size
+         */
+        public void setBufferQueueSize(final int bufferQueueSize) {
+            this.bufferQueueSize = bufferQueueSize;
+        }
+
+        /**
+         * get host.
+         *
+         * @return host
+         */
+        public String getHost() {
+            return host;
+        }
+
+        /**
+         * set host.
+         *
+         * @param host host name
+         */
+        public void setHost(final String host) {
+            this.host = host;
+        }
+
+        /**
+         * get port.
+         *
+         * @return port
+         */
+        public String getPort() {
+            return port;
+        }
+
+        /**
+         * set port.
+         *
+         * @param port port name
+         */
+        public void setPort(final String port) {
+            this.port = port;
+        }
+
+    }
+
+    /**
+     * api log config.
+     */
+    public static class LogApiConfig {
+
+        private String index;
+
+        /**
+         * 0 means never sample, 1 means always sample. Minimum probability is 0.01, or 1% of logging
+         */
+        private String sampleRate;
+
+        /**
+         * get sample rate.
+         *
+         * @return sample rate
+         */
+        public String getSampleRate() {
+            return sampleRate;
+        }
+
+        /**
+         * set sample rate.
+         *
+         * @param sampleRate sample rate
+         */
+        public void setSampleRate(final String sampleRate) {
+            this.sampleRate = sampleRate;
+        }
+
+        /**
+         * get index name.
+         *
+         * @return index name
+         */
+        public String getIndex() {
+            return index;
+        }
+
+        /**
+         * set index name.
+         *
+         * @param index index name
+         */
+        public void setIndex(final String index) {
+            this.index = index;
+        }
+
+    }
+
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/constant/LoggingConstant.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/constant/LoggingConstant.java
new file mode 100644
index 000000000..80278b655
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/constant/LoggingConstant.java
@@ -0,0 +1,32 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.constant;
+
+/**
+ * Some log related property constants.
+ */
+public class LoggingConstant {
+
+    public static final String INDEX = "shenyu-access-logging";
+
+    public static final String HOST = "host";
+
+    public static final String PORT = "port";
+
+    public static final String SHENYU_AGENT_TRACE_ID = "shenyu-agent-trace-id";
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/elasticsearch/ElasticSearchLogCollectClient.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/elasticsearch/ElasticSearchLogCollectClient.java
new file mode 100644
index 000000000..357097e7a
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/elasticsearch/ElasticSearchLogCollectClient.java
@@ -0,0 +1,145 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.elasticsearch;
+
+import co.elastic.clients.elasticsearch.ElasticsearchClient;
+import co.elastic.clients.elasticsearch.core.BulkResponse;
+import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
+import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
+import co.elastic.clients.json.jackson.JacksonJsonpMapper;
+import co.elastic.clients.transport.ElasticsearchTransport;
+import co.elastic.clients.transport.endpoints.BooleanResponse;
+import co.elastic.clients.transport.rest_client.RestClientTransport;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.http.HttpHost;
+import org.apache.shenyu.plugin.logging.elasticsearch.LogConsumeClient;
+import org.apache.shenyu.plugin.logging.elasticsearch.constant.LoggingConstant;
+import org.apache.shenyu.plugin.logging.elasticsearch.entity.ShenyuRequestLog;
+import org.elasticsearch.client.RestClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * queue-based logging collector.
+ */
+public class ElasticSearchLogCollectClient implements LogConsumeClient {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ElasticSearchLogCollectClient.class);
+
+    private RestClient restClient;
+
+    private ElasticsearchTransport transport;
+
+    private ElasticsearchClient client;
+
+    private final AtomicBoolean isStarted = new AtomicBoolean(false);
+
+    /**
+     * init elasticsearch client.
+     *
+     * @param props elasticsearch client properties
+     */
+    public void initClient(final Properties props) {
+        restClient = RestClient
+                .builder(new HttpHost(props.getProperty(LoggingConstant.HOST), Integer.parseInt(props.getProperty(LoggingConstant.PORT))))
+                .build();
+        transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
+        client = new ElasticsearchClient(transport);
+        LOG.info("init ElasticSearchLogCollectClient success");
+        isStarted.set(true);
+        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
+    }
+
+    @Override
+    public void consume(final List<ShenyuRequestLog> logs) throws Exception {
+        if (!existsIndex(LoggingConstant.INDEX)) {
+            createIndex(LoggingConstant.INDEX);
+        }
+        if (CollectionUtils.isEmpty(logs) || !isStarted.get()) {
+            return;
+        }
+        List<BulkOperation> bulkOperations = new ArrayList<>();
+        logs.forEach(log -> {
+            try {
+                bulkOperations.add(new BulkOperation.Builder().create(d -> d.document(log).index(LoggingConstant.INDEX)).build());
+            } catch (Exception e) {
+                LOG.error("elasticsearch store logs error", e);
+            }
+        });
+        BulkResponse response = client.bulk(e -> e.index(LoggingConstant.INDEX).operations(bulkOperations));
+    }
+
+    /**
+     * determine whether the index already exists.
+     *
+     * @param indexName index name
+     * @return true or false
+     */
+    public boolean existsIndex(final String indexName) {
+        try {
+            BooleanResponse existsResponse = client.indices().exists(c -> c.index(indexName));
+            return existsResponse.value();
+        } catch (Exception e) {
+            LOG.error("fail to check the index exists");
+        }
+        return true;
+    }
+
+    /**
+     * create elasticsearch client.
+     *
+     * @param indexName index name
+     * @return true or false
+     */
+    public boolean createIndex(final String indexName) {
+        try {
+            CreateIndexResponse createIndexResponse = client.indices().create(c -> c.index(indexName));
+            return createIndexResponse.acknowledged();
+        } catch (IOException e) {
+            LOG.error("create index error");
+        }
+        return true;
+    }
+
+    /**
+     * close client.
+     */
+    @Override
+    public void close() {
+        if (restClient != null && isStarted.get()) {
+            try {
+                transport.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            try {
+                restClient.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            isStarted.set(false);
+        }
+    }
+
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/entity/LZ4CompressData.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/entity/LZ4CompressData.java
new file mode 100644
index 000000000..d5be64ac4
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/entity/LZ4CompressData.java
@@ -0,0 +1,69 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.entity;
+
+/**
+ * Lz4 compressed data.
+ */
+public class LZ4CompressData {
+
+    private int length;
+
+    private byte[] compressedData;
+
+    public LZ4CompressData(final int length, final byte[] compressedData) {
+        this.length = length;
+        this.compressedData = compressedData;
+    }
+
+    /**
+     * get the exact size of the original input.
+     *
+     * @return the exact size of the original input
+     */
+    public int getLength() {
+        return length;
+    }
+
+    /**
+     * set the exact size of the original input.
+     *
+     * @param length the exact size of the original input.
+     */
+    public void setLength(final int length) {
+        this.length = length;
+    }
+
+    /**
+     * get the compressed data.
+     *
+     * @return the compressed data
+     */
+    public byte[] getCompressedData() {
+        return compressedData;
+    }
+
+    /**
+     * set the compressed data.
+     *
+     * @param compressedData the compressed data
+     */
+    public void setCompressedData(final byte[] compressedData) {
+        this.compressedData = compressedData;
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/entity/ShenyuRequestLog.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/entity/ShenyuRequestLog.java
new file mode 100644
index 000000000..821244345
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/entity/ShenyuRequestLog.java
@@ -0,0 +1,407 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.entity;
+
+/**
+ * shenyu gateway access log.
+ */
+public class ShenyuRequestLog {
+
+    private String clientIp;
+
+    private String timeLocal;
+
+    private String method;
+
+    private String requestHeader;
+
+    private String responseHeader;
+
+    private String queryParams;
+
+    private String requestBody;
+
+    private String requestUri;
+
+    private String responseBody;
+
+    private int responseContentLength;
+
+    private String rpcType;
+
+    private int status;
+
+    private String upstreamIp;
+
+    private long upstreamResponseTime;
+
+    private String userAgent;
+
+    private String host;
+
+    private String module;
+
+    private String traceId;
+
+    /**
+     * path.
+     */
+    private String path;
+
+    /**
+     * get module.
+     *
+     * @return module
+     */
+    public String getModule() {
+        return module;
+    }
+
+    /**
+     * set module.
+     *
+     * @param module module
+     */
+    public void setModule(final String module) {
+        this.module = module;
+    }
+
+    /**
+     * get responseContentLength.
+     *
+     * @return ResponseContentLength
+     */
+    public int getResponseContentLength() {
+        return responseContentLength;
+    }
+
+    /**
+     * set ResponseContentLength.
+     *
+     * @param responseContentLength ResponseContentLength
+     */
+    public void setResponseContentLength(final int responseContentLength) {
+        this.responseContentLength = responseContentLength;
+    }
+
+    /**
+     * get userAgent.
+     *
+     * @return userAgent
+     */
+    public String getUserAgent() {
+        return userAgent;
+    }
+
+    /**
+     * set userAgent.
+     *
+     * @param userAgent userAgent
+     */
+    public void setUserAgent(final String userAgent) {
+        this.userAgent = userAgent;
+    }
+
+    /**
+     * get host.
+     *
+     * @return host
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * set host.
+     *
+     * @param host host
+     */
+    public void setHost(final String host) {
+        this.host = host;
+    }
+
+    /**
+     * get clientIp.
+     *
+     * @return clientIp
+     */
+    public String getClientIp() {
+        return clientIp;
+    }
+
+    /**
+     * set clientIp.
+     *
+     * @param clientIp clientIp
+     */
+    public void setClientIp(final String clientIp) {
+        this.clientIp = clientIp;
+    }
+
+    /**
+     * get timeLocal.
+     *
+     * @return timeLocal
+     */
+    public String getTimeLocal() {
+        return timeLocal;
+    }
+
+    /**
+     * set timeLocal.
+     *
+     * @param timeLocal timeLocal
+     */
+    public void setTimeLocal(final String timeLocal) {
+        this.timeLocal = timeLocal;
+    }
+
+    /**
+     * get method.
+     *
+     * @return method
+     */
+    public String getMethod() {
+        return method;
+    }
+
+    /**
+     * set method.
+     *
+     * @param method method
+     */
+    public void setMethod(final String method) {
+        this.method = method;
+    }
+
+    /**
+     * get requestHeader.
+     *
+     * @return requestHeader
+     */
+    public String getRequestHeader() {
+        return requestHeader;
+    }
+
+    /**
+     * set requestHeader.
+     *
+     * @param requestHeader requestHeader
+     */
+    public void setRequestHeader(final String requestHeader) {
+        this.requestHeader = requestHeader;
+    }
+
+    /**
+     * get responseHeader.
+     *
+     * @return responseHeader
+     */
+    public String getResponseHeader() {
+        return responseHeader;
+    }
+
+    /**
+     * set responseHeader.
+     *
+     * @param responseHeader responseHeader
+     */
+    public void setResponseHeader(final String responseHeader) {
+        this.responseHeader = responseHeader;
+    }
+
+    /**
+     * get queryParams.
+     *
+     * @return queryParams
+     */
+    public String getQueryParams() {
+        return queryParams;
+    }
+
+    /**
+     * set queryParams.
+     *
+     * @param queryParams queryParams
+     */
+    public void setQueryParams(final String queryParams) {
+        this.queryParams = queryParams;
+    }
+
+    /**
+     * get requestBody.
+     *
+     * @return requestBody
+     */
+    public String getRequestBody() {
+        return requestBody;
+    }
+
+    /**
+     * set requestBody.
+     *
+     * @param requestBody requestBody
+     */
+    public void setRequestBody(final String requestBody) {
+        this.requestBody = requestBody;
+    }
+
+    /**
+     * get requestUri.
+     *
+     * @return requestUri
+     */
+    public String getRequestUri() {
+        return requestUri;
+    }
+
+    /**
+     * set requestUri.
+     *
+     * @param requestUri requestUri
+     */
+    public void setRequestUri(final String requestUri) {
+        this.requestUri = requestUri;
+    }
+
+    /**
+     * get responseBody.
+     *
+     * @return responseBody
+     */
+    public String getResponseBody() {
+        return responseBody;
+    }
+
+    /**
+     * set responseBody.
+     *
+     * @param responseBody responseBody
+     */
+    public void setResponseBody(final String responseBody) {
+        this.responseBody = responseBody;
+    }
+
+    /**
+     * get rpcType.
+     *
+     * @return rpcType
+     */
+    public String getRpcType() {
+        return rpcType;
+    }
+
+    /**
+     * set rpcType.
+     *
+     * @param rpcType rpcType
+     */
+    public void setRpcType(final String rpcType) {
+        this.rpcType = rpcType;
+    }
+
+    /**
+     * set status.
+     *
+     * @return status
+     */
+    public int getStatus() {
+        return status;
+    }
+
+    /**
+     * set status.
+     *
+     * @param status status
+     */
+    public void setStatus(final int status) {
+        this.status = status;
+    }
+
+    /**
+     * get upstreamIp.
+     *
+     * @return upstreamIp
+     */
+    public String getUpstreamIp() {
+        return upstreamIp;
+    }
+
+    /**
+     * set upstreamIp.
+     *
+     * @param upstreamIp upstreamIp
+     */
+    public void setUpstreamIp(final String upstreamIp) {
+        this.upstreamIp = upstreamIp;
+    }
+
+    /**
+     * get upstreamResponseTime.
+     *
+     * @return upstreamResponseTime
+     */
+    public long getUpstreamResponseTime() {
+        return upstreamResponseTime;
+    }
+
+    /**
+     * set UpstreamResponseTime.
+     *
+     * @param upstreamResponseTime upstreamResponseTime
+     */
+    public void setUpstreamResponseTime(final long upstreamResponseTime) {
+        this.upstreamResponseTime = upstreamResponseTime;
+    }
+
+    /**
+     * get traceId.
+     *
+     * @return traceId
+     */
+    public String getTraceId() {
+        return traceId;
+    }
+
+    /**
+     * set traceId.
+     *
+     * @param traceId tracing id
+     */
+    public void setTraceId(final String traceId) {
+        this.traceId = traceId;
+    }
+
+    /**
+     * get request path.
+     *
+     * @return request path
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * request path.
+     *
+     * @param path request path
+     */
+    public void setPath(final String path) {
+        this.path = path;
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/handler/LoggingElasticSearchPluginDataHandler.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/handler/LoggingElasticSearchPluginDataHandler.java
new file mode 100644
index 000000000..4ed3a1eae
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/handler/LoggingElasticSearchPluginDataHandler.java
@@ -0,0 +1,145 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.handler;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.common.dto.ConditionData;
+import org.apache.shenyu.common.dto.PluginData;
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.enums.SelectorTypeEnum;
+import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
+import org.apache.shenyu.plugin.logging.elasticsearch.DefaultLogCollector;
+import org.apache.shenyu.plugin.logging.elasticsearch.config.LogCollectConfig;
+import org.apache.shenyu.plugin.logging.elasticsearch.constant.LoggingConstant;
+import org.apache.shenyu.plugin.logging.elasticsearch.elasticsearch.ElasticSearchLogCollectClient;
+import org.apache.shenyu.plugin.logging.elasticsearch.utils.LogCollectConfigUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The type logging elasticsearch plugin data handler.
+ */
+public class LoggingElasticSearchPluginDataHandler implements PluginDataHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(LoggingElasticSearchPluginDataHandler.class);
+
+    private static final ElasticSearchLogCollectClient ELASTICSEARCH_LOG_COLLECT_CLIENT = new ElasticSearchLogCollectClient();
+
+    private static final String EMPTY_JSON = "{}";
+
+    private static final Map<String, List<String>> SELECT_ID_URI_LIST_MAP = new ConcurrentHashMap<>();
+
+    private static final Map<String, LogCollectConfig.LogApiConfig> SELECT_API_CONFIG_MAP = new ConcurrentHashMap<>();
+
+    /**
+     * start or close elasticsearch client.
+     */
+    @Override
+    public void handlerPlugin(final PluginData pluginData) {
+        LOG.info("handler loggingElasticSearch Plugin data:{}", GsonUtils.getGson().toJson(pluginData));
+        if (pluginData.getEnabled()) {
+            LogCollectConfig.GlobalLogConfig globalLogConfig = GsonUtils.getInstance().fromJson(pluginData.getConfig(),
+                    LogCollectConfig.GlobalLogConfig.class);
+
+            LogCollectConfigUtils.setGlobalConfig(globalLogConfig);
+            Properties properties = new Properties();
+            properties.setProperty(LoggingConstant.HOST, globalLogConfig.getHost());
+            properties.setProperty(LoggingConstant.PORT, globalLogConfig.getPort());
+            ELASTICSEARCH_LOG_COLLECT_CLIENT.initClient(properties);
+            DefaultLogCollector.getInstance().start();
+        } else {
+            try {
+                DefaultLogCollector.getInstance().close();
+            } catch (Exception e) {
+                LOG.error("close log collector error", e);
+            }
+        }
+    }
+
+    @Override
+    public void handlerSelector(final SelectorData selectorData) {
+        LOG.info("handler loggingElasticSearch selector data:{}", GsonUtils.getGson().toJson(selectorData));
+        String handleJson = selectorData.getHandle();
+        if (StringUtils.isEmpty(handleJson) || EMPTY_JSON.equals(handleJson.trim())) {
+            return;
+        }
+        if (selectorData.getType() != SelectorTypeEnum.CUSTOM_FLOW.getCode()
+                || CollectionUtils.isEmpty(selectorData.getConditionList())) {
+            return;
+        }
+
+        LogCollectConfig.LogApiConfig logApiConfig = GsonUtils.getInstance().fromJson(handleJson,
+                LogCollectConfig.LogApiConfig.class);
+        if (StringUtils.isBlank(logApiConfig.getIndex()) || StringUtils.isBlank(logApiConfig.getSampleRate())) {
+            return;
+        }
+        List<String> uriList = new ArrayList<>();
+        for (ConditionData conditionData : selectorData.getConditionList()) {
+            if ("uri".equals(conditionData.getParamType()) && StringUtils.isNotBlank(conditionData.getParamValue())
+                    && ("match".equals(conditionData.getOperator()) || "=".equals(conditionData.getOperator()))) {
+                uriList.add(conditionData.getParamValue().trim());
+            }
+        }
+        SELECT_ID_URI_LIST_MAP.put(selectorData.getId(), uriList);
+        SELECT_API_CONFIG_MAP.put(selectorData.getId(), logApiConfig);
+    }
+
+    @Override
+    public void removeSelector(final SelectorData selectorData) {
+        LOG.info("handler remove loggingElasticSearch selector data:{}", GsonUtils.getGson().toJson(selectorData));
+        SELECT_ID_URI_LIST_MAP.remove(selectorData.getId());
+        SELECT_API_CONFIG_MAP.remove(selectorData.getId());
+    }
+
+    @Override
+    public String pluginNamed() {
+        return PluginEnum.LOGGING_ElasticSearch.getName();
+    }
+
+    /**
+     * get elasticsearch log collect client.
+     * @return elastcisearch log collect client.
+     */
+    public static ElasticSearchLogCollectClient getElasticSearchLogCollectClient() {
+        return ELASTICSEARCH_LOG_COLLECT_CLIENT;
+    }
+
+    /**
+     * get selectId uriList map.
+     * @return selectId uriList map
+     */
+    public static Map<String, List<String>> getSelectIdUriListMap() {
+        return SELECT_ID_URI_LIST_MAP;
+    }
+
+    /**
+     * get select api config map.
+     * @return select api config map
+     */
+    public static Map<String, LogCollectConfig.LogApiConfig> getSelectApiConfigMap() {
+        return SELECT_API_CONFIG_MAP;
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/sampler/CountSampler.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/sampler/CountSampler.java
new file mode 100644
index 000000000..15e0cc6c1
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/sampler/CountSampler.java
@@ -0,0 +1,115 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.sampler;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+
+import java.util.BitSet;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * used for sample log.
+ * reference resources: http://stackoverflow.com/questions/12817946/generate-a-random-bitset-with-n-1s
+ */
+public class CountSampler implements Sampler {
+
+    private final AtomicInteger counter;
+
+    private final BitSet sampleDecisions;
+
+    /**
+     * Fills a bitset with decisions according to the supplied probability.
+     */
+    CountSampler(final float probability) {
+        counter = new AtomicInteger();
+        int percent = (int) (probability * 100.0f);
+        this.sampleDecisions = genRandomBitSet(100, percent);
+    }
+
+    /**
+     * loops over the pre-canned decisions, resetting to zero when it gets to the end.
+     */
+    @Override
+    public boolean isSampled(final ServerHttpRequest request) {
+        return sampleDecisions.get(mod(counter.getAndIncrement()));
+    }
+
+    /**
+     * Returns a non-negative mod.
+     */
+    private int mod(final int dividend) {
+        int result = dividend % 100;
+        return result >= 0 ? result : 100 + result;
+    }
+
+    /**
+     * gen random bitSet.
+     * reference resources: http://stackoverflow.com/questions/12817946/generate-a-random-bitset-with-n-1s
+     *
+     * @param size        bitmap size
+     * @param cardinality cardinality
+     * @return bitSet
+     */
+    private BitSet genRandomBitSet(final int size, final int cardinality) {
+        BitSet result = new BitSet(size);
+        int[] chosen = new int[cardinality];
+        int i;
+        for (i = 0; i < cardinality; ++i) {
+            chosen[i] = i;
+            result.set(i);
+        }
+        Random random = new Random();
+        for (; i < size; ++i) {
+            int j = random.nextInt(i + 1);
+            if (j < cardinality) {
+                result.clear(chosen[j]);
+                result.set(i);
+                chosen[j] = i;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * create a sampler instance.
+     *
+     * @param probability probability
+     * @return sampler instance
+     */
+    public static Sampler create(final String probability) {
+        if (StringUtils.isBlank(probability)) {
+            return ALWAYS_SAMPLE;
+        }
+        if ("0".equals(probability)) {
+            return NEVER_SAMPLE;
+        }
+        if ("1".equals(probability) || "1.0".equals(probability) || "1.0.0".equals(probability)) {
+            return ALWAYS_SAMPLE;
+        }
+        float parseProbability = NumberUtils.toFloat(probability, 1);
+        if (parseProbability < 0.01f || parseProbability > 1) {
+            throw new IllegalArgumentException(
+                    "probability should be between 0.01 and 1: was " + probability);
+        }
+        return new CountSampler(parseProbability);
+    }
+
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/sampler/Sampler.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/sampler/Sampler.java
new file mode 100644
index 000000000..8112bfbac
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/sampler/Sampler.java
@@ -0,0 +1,35 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.sampler;
+
+import org.springframework.http.server.reactive.ServerHttpRequest;
+
+public interface Sampler {
+
+    Sampler ALWAYS_SAMPLE = request -> true;
+    Sampler NEVER_SAMPLE = request -> false;
+
+    /**
+     * judge a ServerHttpRequest should be sample.
+     *
+     * @param request request
+     * @return whether sample
+     */
+    boolean isSampled(ServerHttpRequest request);
+
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/utils/LogCollectConfigUtils.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/utils/LogCollectConfigUtils.java
new file mode 100644
index 000000000..00af59a6f
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/utils/LogCollectConfigUtils.java
@@ -0,0 +1,143 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.plugin.logging.elasticsearch.config.LogCollectConfig.GlobalLogConfig;
+import org.apache.shenyu.plugin.logging.elasticsearch.sampler.CountSampler;
+import org.apache.shenyu.plugin.logging.elasticsearch.sampler.Sampler;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.util.AntPathMatcher;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * log collect config Utils.
+ */
+public final class LogCollectConfigUtils {
+
+    private static final AntPathMatcher MATCHER = new AntPathMatcher();
+
+    private static GlobalLogConfig globalLogConfig;
+
+    private static final GlobalLogConfig DEFAULT_GLOBAL_LOG_CONFIG =
+            new GlobalLogConfig();
+
+    private static Map<String, Sampler> apiSamplerMap = new HashMap<>();
+
+    private static Sampler globalSampler = Sampler.ALWAYS_SAMPLE;
+
+    private LogCollectConfigUtils() {
+    }
+
+    /**
+     * set global config.
+     * @param config global config
+     */
+    public static void setGlobalConfig(final GlobalLogConfig config) {
+        globalLogConfig = config;
+    }
+
+    /**
+     * set api sample.
+     * @param uriSampleMap api sample map
+     */
+    public static void setSampler(final Map<String, String> uriSampleMap) {
+        Map<String, Sampler> samplerMap = new HashMap<>();
+        uriSampleMap.forEach((path, sampler) -> {
+            if (StringUtils.isBlank(sampler)) {
+                samplerMap.put(path, globalSampler);
+            } else {
+                samplerMap.put(path, CountSampler.create(sampler));
+            }
+        });
+        apiSamplerMap = samplerMap;
+    }
+
+    /**
+     * set global Sampler.
+     * @param sampler global sampler
+     */
+    public static void setGlobalSampler(final String sampler) {
+        if (StringUtils.isNotBlank(sampler)) {
+            try {
+                globalSampler = CountSampler.create(sampler);
+            } catch (Exception e) {
+                globalSampler = Sampler.ALWAYS_SAMPLE;
+            }
+        }
+    }
+
+    /**
+     * judge whether sample.
+     *
+     * @param request request
+     * @return whether sample
+     */
+    public static boolean isSampled(final ServerHttpRequest request) {
+        String path = request.getURI().getPath();
+        for (Map.Entry<String, Sampler> entry : apiSamplerMap.entrySet()) {
+            String pattern = entry.getKey();
+            if (MATCHER.match(pattern, path)) {
+                return entry.getValue().isSampled(request);
+            }
+        }
+        if (globalSampler != null) {
+            return globalSampler.isSampled(request);
+        }
+        return true;
+    }
+
+    /**
+     * judge whether request org.apache.shenyu.plugin.logging.body too large.
+     *
+     * @param bodySize org.apache.shenyu.plugin.logging.body size
+     * @return whether request org.apache.shenyu.plugin.logging.body too large
+     */
+    public static boolean isRequestBodyTooLarge(final int bodySize) {
+        if (Objects.isNull(globalLogConfig)) {
+            return false;
+        }
+        return bodySize > globalLogConfig.getMaxRequestBody();
+    }
+
+    /**
+     * judge whether response org.apache.shenyu.plugin.logging.body too large.
+     *
+     * @param bodySize org.apache.shenyu.plugin.logging.body size.
+     * @return whether response org.apache.shenyu.plugin.logging.body too large
+     */
+    public static boolean isResponseBodyTooLarge(final int bodySize) {
+        if (Objects.isNull(globalLogConfig)) {
+            return false;
+        }
+        return bodySize > globalLogConfig.getMaxResponseBody();
+    }
+
+    /**
+     * get global log config.
+     *
+     * @return global log config
+     */
+    public static GlobalLogConfig getGlobalLogConfig() {
+        return Optional.ofNullable(globalLogConfig).orElse(DEFAULT_GLOBAL_LOG_CONFIG);
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/utils/LogCollectUtils.java b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/utils/LogCollectUtils.java
new file mode 100644
index 000000000..414c76e1f
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/plugin/logging/elasticsearch/utils/LogCollectUtils.java
@@ -0,0 +1,62 @@
+/*
+ * 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.shenyu.plugin.logging.elasticsearch.utils;
+
+import org.apache.shenyu.common.utils.JsonUtils;
+import org.springframework.http.HttpHeaders;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * log collect utils.
+ */
+public class LogCollectUtils {
+
+    private static final List<String> BINARY_TYPE_LIST = Arrays.asList("image", "multipart", "cbor",
+            "octet-stream", "pdf", "javascript", "css", "html");
+
+    /**
+     * judge whether is binary type.
+     *
+     * @param headers request or response header
+     * @return whether binary type
+     */
+    public static boolean isNotBinaryType(final HttpHeaders headers) {
+        return Optional.ofNullable(headers).map(HttpHeaders::getContentType)
+                .map(contentType -> !BINARY_TYPE_LIST.contains(contentType.getType())
+                        && !BINARY_TYPE_LIST.contains(contentType.getSubtype()))
+                .orElse(true);
+    }
+
+    /**
+     * get request header string.
+     *
+     * @param headers request headers
+     * @return header string
+     */
+    public static String getHeaders(final HttpHeaders headers) {
+        Map<String, String> map = headers.entrySet().stream()
+                .collect(Collectors.toMap(Map.Entry::getKey, entry -> String.join(",", entry.getValue())));
+        return JsonUtils.toJson(map).replaceAll("\\\"", "");
+    }
+
+}
diff --git a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/pom.xml b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/pom.xml
index 502b795c5..3acd0a769 100644
--- a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/pom.xml
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/pom.xml
@@ -59,6 +59,7 @@
         <module>shenyu-spring-boot-starter-plugin-mqtt</module>
         <module>shenyu-spring-boot-starter-plugin-metrics</module>
         <module>shenyu-spring-boot-starter-plugin-logging-rocketmq</module>
+        <module>shenyu-spring-boot-starter-plugin-logging-elasticsearch</module>
         <module>shenyu-spring-boot-starter-plugin-cache</module>
         <module>shenyu-spring-boot-starter-plugin-mock</module>
     </modules>
diff --git a/shenyu-plugin/shenyu-plugin-logging/pom.xml b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/pom.xml
similarity index 51%
copy from shenyu-plugin/shenyu-plugin-logging/pom.xml
copy to shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/pom.xml
index dddc7a374..ef062e273 100644
--- a/shenyu-plugin/shenyu-plugin-logging/pom.xml
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/pom.xml
@@ -16,20 +16,31 @@
   ~ limitations under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
         <groupId>org.apache.shenyu</groupId>
-        <artifactId>shenyu-plugin</artifactId>
+        <artifactId>shenyu-spring-boot-starter-plugin</artifactId>
         <version>2.5.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
-    <artifactId>shenyu-plugin-logging</artifactId>
-    <packaging>pom</packaging>
 
-    <modules>
-        <module>shenyu-plugin-logging-console</module>
-        <module>shenyu-plugin-logging-rocketmq</module>
-    </modules>
+    <artifactId>shenyu-spring-boot-starter-plugin-logging-elasticsearch</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.shenyu</groupId>
+            <artifactId>shenyu-plugin-logging-elasticsearch</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/springboot/starter/plugin/logging/elasticsearch/LoggingElasticSearchPluginConfiguration.java b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/springboot/starter/plugin/logging/elasticsearch/LoggingElasticSearchPluginConfiguration.java
new file mode 100644
index 000000000..62c2a24b4
--- /dev/null
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/java/org/apache/shenyu/springboot/starter/plugin/logging/elasticsearch/LoggingElasticSearchPluginConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.shenyu.springboot.starter.plugin.logging.elasticsearch;
+
+import org.apache.shenyu.plugin.api.ShenyuPlugin;
+import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
+import org.apache.shenyu.plugin.logging.elasticsearch.LoggingElasticSearchPlugin;
+import org.apache.shenyu.plugin.logging.elasticsearch.handler.LoggingElasticSearchPluginDataHandler;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * config logging ElasticSearch plugin.
+ */
+@Configuration
+@ConditionalOnProperty(value = {"shenyu.plugins.logging-elasticsearch.enabled"}, havingValue = "true", matchIfMissing = true)
+public class LoggingElasticSearchPluginConfiguration {
+
+    /**
+     * logging elasticsearch plugin data handler.
+     * @return logging elasticsearch PluginDataHandler
+     */
+    @Bean
+    public PluginDataHandler loggingElasticSearchPluginDataHandler() {
+        return new LoggingElasticSearchPluginDataHandler();
+    }
+
+    /**
+     * Logging ElasticSearch plugin.
+     * @return LoggingElasticSearch
+     */
+    @Bean
+    public ShenyuPlugin loggingElasticSearchPlugin() {
+        return new LoggingElasticSearchPlugin();
+    }
+}
diff --git a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/resources/META-INF/spring.factories b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..a77d19005
--- /dev/null
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.shenyu.springboot.starter.plugin.logging.elasticsearch.LoggingElasticSearchPluginConfiguration
diff --git a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/resources/META-INF/spring.provides b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/resources/META-INF/spring.provides
new file mode 100644
index 000000000..6061f34fe
--- /dev/null
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-plugin/shenyu-spring-boot-starter-plugin-logging-elasticsearch/src/main/resources/META-INF/spring.provides
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+provides: shenyu-spring-boot-starter-plugin-logging-elasticsearch