diff --git a/example/integration-log/integration-log-main/pom.xml b/example/integration-log/integration-log-main/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a77618ac2b14b21033ce3f75476f5b70da458357
--- /dev/null
+++ b/example/integration-log/integration-log-main/pom.xml
@@ -0,0 +1,80 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.3.RELEASE
+
+
+
+ com.gitee.starblues
+ 2.4.2-RELEASE
+ integration-log-main
+ jar
+ 集成插件日志 案例--主程序
+
+
+ 1.8
+ UTF-8
+ UTF-8
+ 3.7.0
+ 2.4.2-RELEASE
+ 2.4.2-RELEASE
+
+
+
+
+ com.gitee.starblues
+ springboot-plugin-framework
+ ${springboot-plugin-framework.version}
+
+
+ com.gitee.starblues
+ springboot-plugin-framework-extension-log
+ ${extension-log.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ exec
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/integration-log/integration-log-main/src/main/java/com/log/main/LogMain.java b/example/integration-log/integration-log-main/src/main/java/com/log/main/LogMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..69b8d7e213c55ca46b9d53ea000b5d8f97e9c60c
--- /dev/null
+++ b/example/integration-log/integration-log-main/src/main/java/com/log/main/LogMain.java
@@ -0,0 +1,19 @@
+package com.log.main;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * 主启动程序
+ *
+ * @author starBlues
+ * @version 1.0
+ */
+@SpringBootApplication()
+public class LogMain {
+
+ public static void main(String[] args) {
+ SpringApplication.run(LogMain.class, args);
+ }
+
+}
diff --git a/example/integration-log/integration-log-main/src/main/java/com/log/main/config/PluginBeanConfig.java b/example/integration-log/integration-log-main/src/main/java/com/log/main/config/PluginBeanConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf5c0a012a70a84f7eb0651d6d6f225e65acb15c
--- /dev/null
+++ b/example/integration-log/integration-log-main/src/main/java/com/log/main/config/PluginBeanConfig.java
@@ -0,0 +1,78 @@
+package com.log.main.config;
+
+import com.gitee.starblues.extension.log.SpringBootLogExtension;
+import com.gitee.starblues.integration.ConfigurationBuilder;
+import com.gitee.starblues.integration.IntegrationConfiguration;
+import com.gitee.starblues.integration.application.AutoPluginApplication;
+import com.gitee.starblues.integration.application.PluginApplication;
+import org.pf4j.RuntimeMode;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "plugin")
+public class PluginBeanConfig {
+
+ /**
+ * 运行模式
+ * 开发环境: development、dev
+ * 生产/部署 环境: deployment、prod
+ */
+ @Value("${runMode:dev}")
+ private String runMode;
+
+ /**
+ * 插件的路径
+ */
+ @Value("${pluginPath:plugins}")
+ private String pluginPath;
+
+ /**
+ * 插件文件的路径
+ */
+ @Value("${pluginConfigFilePath:pluginConfigs}")
+ private String pluginConfigFilePath;
+
+
+
+ @Bean
+ public IntegrationConfiguration configuration(){
+ return ConfigurationBuilder.toBuilder()
+ .runtimeMode(RuntimeMode.byName(runMode))
+ .pluginPath(pluginPath)
+ .pluginConfigFilePath(pluginConfigFilePath)
+ .uploadTempPath("temp")
+ .backupPath("backupPlugin")
+ .pluginRestPathPrefix("/api/plugin")
+ .enablePluginIdRestPathPrefix(true)
+ .enableSwaggerRefresh(true)
+ .build();
+ }
+
+
+ /**
+ * 定义插件应用。使用可以注入它操作插件。
+ * @return PluginApplication
+ */
+ @Bean
+ public PluginApplication pluginApplication(){
+ // 实例化自动初始化插件的PluginApplication
+ PluginApplication pluginApplication = new AutoPluginApplication();
+ pluginApplication.addExtension(new SpringBootLogExtension());
+ return pluginApplication;
+ }
+
+ public void setRunMode(String runMode) {
+ this.runMode = runMode;
+ }
+
+ public void setPluginPath(String pluginPath) {
+ this.pluginPath = pluginPath;
+ }
+
+ public void setPluginConfigFilePath(String pluginConfigFilePath) {
+ this.pluginConfigFilePath = pluginConfigFilePath;
+ }
+}
diff --git a/example/integration-log/integration-log-main/src/main/java/com/log/main/rest/MainRest.java b/example/integration-log/integration-log-main/src/main/java/com/log/main/rest/MainRest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e48f48e6f822a1bb52aa362e168eefc589b57e9e
--- /dev/null
+++ b/example/integration-log/integration-log-main/src/main/java/com/log/main/rest/MainRest.java
@@ -0,0 +1,24 @@
+package com.log.main.rest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 插件jar 包测试功能
+ * @author sousouki
+ * @version 1.0
+ */
+@RestController
+@RequestMapping("/log/main")
+public class MainRest {
+
+ private static final Logger log = LoggerFactory.getLogger(MainRest.class);
+
+ @GetMapping("/print")
+ public String print(@RequestParam("value") String value){
+ log.info("Request value: {}", value);
+ return value;
+ }
+
+}
diff --git a/example/integration-log/plugins/integration-log-plugin/plugin.properties b/example/integration-log/plugins/integration-log-plugin/plugin.properties
new file mode 100644
index 0000000000000000000000000000000000000000..c541bf21843c28502d1fc0499507f3faf26dfec7
--- /dev/null
+++ b/example/integration-log/plugins/integration-log-plugin/plugin.properties
@@ -0,0 +1,4 @@
+plugin.id=integration-log-plugin
+plugin.class=com.log.plugin.LogPlugin
+plugin.version=2.4.2-RELEASE
+plugin.provider=sousouki
\ No newline at end of file
diff --git a/example/integration-log/plugins/integration-log-plugin/pom.xml b/example/integration-log/plugins/integration-log-plugin/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cfefb45a63e3fec8bb06b7c500800ff334ae91c5
--- /dev/null
+++ b/example/integration-log/plugins/integration-log-plugin/pom.xml
@@ -0,0 +1,87 @@
+
+
+ 4.0.0
+
+ com.gitee.starblues
+ integration-log-plugin
+ 2.4.2-RELEASE
+ jar
+
+
+ integration-log-plugin
+ com.log.plugin.TkMybatisPlugin
+ ${project.version}
+ sousouki
+
+
+ 1.8
+ UTF-8
+ UTF-8
+
+ 3.7.0
+ 3.1.1
+
+
+
+
+
+
+ com.gitee.starblues
+ integration-log-main
+ ${project.version}
+ provided
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ ${maven-assembly-plugin.version}
+
+
+ jar-with-dependencies
+
+
+
+ true
+ true
+
+
+ ${plugin.id}
+ ${plugin.version}
+ ${plugin.provider}
+ ${plugin.class}
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/LogMain.java b/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/LogMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/LogPlugin.java b/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/LogPlugin.java
new file mode 100644
index 0000000000000000000000000000000000000000..346cae5c2c6827bb4dd14b1460dcbee828e71cca
--- /dev/null
+++ b/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/LogPlugin.java
@@ -0,0 +1,45 @@
+package com.log.plugin;
+
+import com.gitee.starblues.extension.log.config.SpringBootLogConfig;
+import com.gitee.starblues.realize.BasePlugin;
+import org.pf4j.PluginWrapper;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * description
+ *
+ * @author sousouki
+ * @version 1.0
+ */
+public class LogPlugin extends BasePlugin implements SpringBootLogConfig {
+
+ private Set locations = new HashSet<>();
+
+ public LogPlugin(PluginWrapper wrapper) {
+ super(wrapper);
+ locations.add("classpath:log.xml");
+ }
+
+ @Override
+ protected void startEvent() {
+
+ }
+
+ @Override
+ protected void deleteEvent() {
+
+ }
+
+ @Override
+ protected void stopEvent() {
+
+ }
+
+ @Override
+ public Set logConfigLocations() {
+ return locations;
+ }
+}
+
diff --git a/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/rest/MainRest.java b/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/rest/MainRest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e48f48e6f822a1bb52aa362e168eefc589b57e9e
--- /dev/null
+++ b/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/rest/MainRest.java
@@ -0,0 +1,24 @@
+package com.log.main.rest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 插件jar 包测试功能
+ * @author sousouki
+ * @version 1.0
+ */
+@RestController
+@RequestMapping("/log/main")
+public class MainRest {
+
+ private static final Logger log = LoggerFactory.getLogger(MainRest.class);
+
+ @GetMapping("/print")
+ public String print(@RequestParam("value") String value){
+ log.info("Request value: {}", value);
+ return value;
+ }
+
+}
diff --git a/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/rest/PluginRest.java b/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/rest/PluginRest.java
new file mode 100644
index 0000000000000000000000000000000000000000..26bcc02fc33be241dd94ea046409502dbe807825
--- /dev/null
+++ b/example/integration-log/plugins/integration-log-plugin/src/main/java/com/log/main/rest/PluginRest.java
@@ -0,0 +1,28 @@
+package com.log.plugin.rest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * description
+ *
+ * @author starBlues
+ * @version 1.0
+ */
+@RestController
+@RequestMapping("/log/plugin")
+public class PluginRest {
+
+ private static final Logger log = LoggerFactory.getLogger(PluginRest.class);
+
+ @GetMapping("/print")
+ public String print(@RequestParam("value") String value){
+ log.info("Request value: {}", value);
+ return value;
+ }
+
+}
diff --git a/example/integration-log/plugins/integration-log-plugin/src/main/resources/log.xml b/example/integration-log/plugins/integration-log-plugin/src/main/resources/log.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b0fabf290e7aab4e8b8055b6b0026e63f08f1571
--- /dev/null
+++ b/example/integration-log/plugins/integration-log-plugin/src/main/resources/log.xml
@@ -0,0 +1,9 @@
+
+
+ integration-log-plugin
+ INFO
+ 10MB
+ 10GB
+ 30
+ %d{yyyy-MM-dd HH:mm:ss.SSS} -%5p --- [%t] %-40.40logger{39} : %m%n
+
\ No newline at end of file
diff --git a/example/integration-log/pom.xml b/example/integration-log/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..876a306d3fe77f2498db8db94535e1e5590d0825
--- /dev/null
+++ b/example/integration-log/pom.xml
@@ -0,0 +1,18 @@
+
+
+ 4.0.0
+
+ com.gitee.starblues
+ integration-log
+ 2.4.2-RELEASE
+ pom
+ 集成插件日志案例
+
+
+ integration-log-main
+ plugins/integration-log-plugin
+
+
+
\ No newline at end of file
diff --git a/example/pom.xml b/example/pom.xml
index f192a2684053ca4445252be2002751be8564c083..a8acf4bf2b7b269ded68f6f82f1ece8411b3e948 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -14,6 +14,7 @@
integration-mybatis
integration-mybatisplus
integration-tkmybatis
+ integration-log
diff --git a/springboot-plugin-framework-extension/pom.xml b/springboot-plugin-framework-extension/pom.xml
index 55ce429ed22c68dc62915575b71577ff09d65270..0c360834d2253595776ae0722ffc282680d86273 100644
--- a/springboot-plugin-framework-extension/pom.xml
+++ b/springboot-plugin-framework-extension/pom.xml
@@ -15,6 +15,7 @@
springboot-plugin-framework-extension-mybatis
springboot-plugin-framework-extension-resources
+ springboot-plugin-framework-extension-log
\ No newline at end of file
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/pom.xml b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..74ff998e7be4614dcdea39b5c82a1a75e0e40d06
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+ org.sonatype.oss
+ oss-parent
+ 7
+
+
+ 4.0.0
+
+ com.gitee.starblues
+ springboot-plugin-framework-extension-log
+ 2.4.2-RELEASE
+
+
+ 2.4.2-RELEASE
+ 5.0.7.RELEASE
+ 1.2.3
+
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+ provided
+
+
+ org.springframework
+ spring-context
+ ${spring-version}
+ compile
+
+
+ com.gitee.starblues
+ springboot-plugin-framework
+ ${springboot-plugin-framework.version}
+ compile
+
+
+
+
+
\ No newline at end of file
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/PluginLogConfigLoader.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/PluginLogConfigLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..cffdc0e334530c260c3cd9017905ed1166ca6eb8
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/PluginLogConfigLoader.java
@@ -0,0 +1,171 @@
+package com.gitee.starblues.extension.log;
+
+import com.gitee.starblues.extension.log.config.SpringBootLogConfig;
+import com.gitee.starblues.factory.PluginRegistryInfo;
+import com.gitee.starblues.factory.process.pipe.loader.PluginResourceLoader;
+import com.gitee.starblues.factory.process.pipe.loader.ResourceWrapper;
+import com.gitee.starblues.realize.BasePlugin;
+import com.gitee.starblues.utils.OrderPriority;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.util.CollectionUtils;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+public class PluginLogConfigLoader implements PluginResourceLoader {
+
+ private Logger log = LoggerFactory.getLogger(PluginLogConfigLoader.class);
+
+ public static final String KEY = "SpringBootLogConfigLoader";
+
+ private final static String TYPE_FILE = "file";
+ private final static String TYPE_CLASSPATH = "classpath";
+ private final static String TYPE_PACKAGE = "package";
+
+ @Override
+ public String key() {
+ return KEY;
+ }
+
+ @Override
+ public ResourceWrapper load(PluginRegistryInfo pluginRegistryInfo) throws Exception {
+ BasePlugin basePlugin = pluginRegistryInfo.getBasePlugin();
+ if (!(basePlugin instanceof SpringBootLogConfig)) {
+ log.warn("Plugin '{}' not implements SpringBootLogConfig, If you need to use log in the plugin," + "Please implements SpringBootLogConfig interface", basePlugin.getWrapper().getPluginId());
+ return null;
+ }
+ SpringBootLogConfig springBootLogConfig = (SpringBootLogConfig) basePlugin;
+ Set logConfigLocations = springBootLogConfig.logConfigLocations();
+ if (logConfigLocations == null || logConfigLocations.isEmpty()) {
+ log.warn("SpringBootLogConfig -> logConfigLocations return is empty, " + "Please check configuration");
+ return new ResourceWrapper();
+ }
+ List resources = new ArrayList<>();
+ for (String logConfigLocation : logConfigLocations) {
+ if (logConfigLocation == null || "".equals(logConfigLocation)) {
+ continue;
+ }
+ List loadResources = load(logConfigLocation, basePlugin);
+ if (loadResources != null && !loadResources.isEmpty()) {
+ resources.addAll(loadResources);
+ }
+ }
+ ResourceWrapper resourceWrapper = new ResourceWrapper();
+ resourceWrapper.addResources(resources);
+ return resourceWrapper;
+ }
+
+ @Override
+ public void unload(PluginRegistryInfo pluginRegistryInfo, ResourceWrapper resourceWrapper) throws Exception {
+
+ }
+
+ @Override
+ public OrderPriority order() {
+ return OrderPriority.getHighPriority();
+ }
+
+ private List load(String logConfigLocation, BasePlugin basePlugin) throws Exception {
+ String[] split = logConfigLocation.split(":");
+ if (split.length != 2) {
+ return null;
+ }
+ String type = split[0];
+ String location = split[1];
+ String matchLocation;
+ if (Objects.equals(type, TYPE_CLASSPATH)) {
+ matchLocation = location;
+ } else if (Objects.equals(type, TYPE_FILE)) {
+
+ return loadFileSystemResources(basePlugin, location);
+ } else if (Objects.equals(type, TYPE_PACKAGE)) {
+ matchLocation = location.replaceAll("\\.", "/");
+ } else {
+ log.warn("logConfigLocation {} illegal", logConfigLocation);
+ return null;
+ }
+ return loadClassPathResources(basePlugin, matchLocation);
+ }
+
+ private List loadClassPathResources(BasePlugin basePlugin, String matchLocation) throws Exception {
+ Logger log = LoggerFactory.getLogger(getClass());
+ String pluginPath = basePlugin.getWrapper().getPluginPath().toString();
+ try (JarFile jarFile = new JarFile(pluginPath)) {
+ Enumeration entryEnumeration = jarFile.entries();
+ List entries = Collections.list(entryEnumeration);
+ return entries.stream().filter(entry -> {
+ String entryName = entry.getName();
+ // 将资源规则转换为正则表达式,例如“mapper/*Mapper.xml”转换后为“mapper/.*Mapper\\.xml”
+ String regex = matchLocation.replaceAll("\\\\", "/").replaceAll("\\.", "\\\\.").replaceAll("\\*", ".*");
+ return entryName.matches(regex);
+ }).map(entry -> {
+ try (InputStream inputStream = jarFile.getInputStream(entry);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ BufferedInputStream in = new BufferedInputStream(inputStream)) {
+ int buf_size = 1024;
+ byte[] buffer = new byte[buf_size];
+ int len;
+ while (-1 != (len = in.read(buffer, 0, buf_size))) {
+ bos.write(buffer, 0, len);
+ }
+ // 这里只能用ByteArrayResource,使用InputStreamResource后续读取时会报流已关闭
+ ByteArrayResource resource = new ByteArrayResource(bos.toByteArray());
+ log.debug("Loaded plugin resource '{}'.", entry.getName());
+ return resource;
+ } catch (IOException e) {
+ log.warn("Load resource failed, caused by: {}", e.toString());
+ return null;
+ }
+ }).filter(Objects::nonNull).collect(Collectors.toList());
+ }
+ }
+
+ private List loadFileSystemResources(BasePlugin basePlugin, String matchLocation) {
+ String basePath = basePlugin.getWrapper().getPluginPath().toString().concat(File.separator).concat(basePlugin.getWrapper().getPluginId()).concat("/config/");
+ String tmpPath = basePath.concat(matchLocation);
+ String regex = tmpPath.replaceAll("\\\\", "/").replaceAll("\\.", "\\\\.").replaceAll("\\*", ".*");
+ List matchedFilePaths = new ArrayList<>();
+ getMatchedFilePaths(regex, new File(basePath), matchedFilePaths);
+ if (CollectionUtils.isEmpty(matchedFilePaths)) {
+ return new ArrayList<>();
+ }
+ return matchedFilePaths.stream().map(FileSystemResource::new).collect(Collectors.toList());
+ }
+
+ private void getMatchedFilePaths(String regex, File file, List matchedFilePath) {
+ File[] files = file.listFiles();
+ if (files == null) {
+ return;
+ }
+ for (File subFile : files) {
+ if (subFile.isDirectory()) {
+ getMatchedFilePaths(regex, subFile, matchedFilePath);
+ } else {
+ try {
+ String filePath = subFile.getCanonicalPath();
+ filePath = filePath.replaceAll("\\\\", "/");
+ if (filePath.matches(regex)) {
+ matchedFilePath.add(subFile.getCanonicalPath());
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+}
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/SpringBootLogExtension.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/SpringBootLogExtension.java
new file mode 100644
index 0000000000000000000000000000000000000000..8cc5baed53ec90c75189f947689d77b94c4a4c98
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/SpringBootLogExtension.java
@@ -0,0 +1,34 @@
+package com.gitee.starblues.extension.log;
+
+
+import com.gitee.starblues.extension.AbstractExtension;
+import com.gitee.starblues.factory.process.pipe.PluginPipeProcessorExtend;
+import com.gitee.starblues.factory.process.pipe.loader.PluginResourceLoader;
+import org.springframework.context.ApplicationContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SpringBootLogExtension extends AbstractExtension {
+
+ public static final String KEY = "SpringBootLogExtension";
+
+ @Override
+ public String key() {
+ return KEY;
+ }
+
+ @Override
+ public List getPluginResourceLoader() {
+ List resourceLoaders = new ArrayList<>();
+ resourceLoaders.add(new PluginLogConfigLoader());
+ return resourceLoaders;
+ }
+
+ @Override
+ public List getPluginPipeProcessor(ApplicationContext applicationContext) {
+ List pipeProcessorExtends = new ArrayList<>();
+ pipeProcessorExtends.add(new PluginLogConfigProcessor());
+ return pipeProcessorExtends;
+ }
+}
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/annotation/ConfigItem.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/annotation/ConfigItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..c868a46430ae2a0a30a7532065f3269f138cbfea
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/annotation/ConfigItem.java
@@ -0,0 +1,14 @@
+package com.gitee.starblues.extension.log.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ConfigItem {
+ String defaultValue() default "";
+}
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/config/LogConfig.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/config/LogConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..64ef3d840c78c64cce73acad9f56dd45b1fc83ba
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/config/LogConfig.java
@@ -0,0 +1,91 @@
+package com.gitee.starblues.extension.log.config;
+
+import com.gitee.starblues.extension.log.annotation.ConfigItem;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+public class LogConfig {
+
+ @XmlElement(name = "fileName")
+ private String fileName;
+
+ @ConfigItem(defaultValue = "INFO")
+ @XmlElement(name = "level")
+ private String level;
+
+ @ConfigItem(defaultValue = "10MB")
+ @XmlElement(name = "maxFileSize")
+ private String maxFileSize;
+
+ @ConfigItem(defaultValue = "10GB")
+ @XmlElement(name = "totalFileSize")
+ private String totalFileSize;
+
+ @ConfigItem(defaultValue = "30")
+ @XmlElement(name = "maxHistory")
+ private Integer maxHistory;
+
+ @ConfigItem(defaultValue = "%d{yyyy-MM-dd HH:mm:ss.SSS} -%5p --- [%t] %-40.40logger{39} : %m%n")
+ @XmlElement(name = "pattern")
+ private String pattern;
+
+ @XmlTransient
+ private String packageName;
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public String getLevel() {
+ return level;
+ }
+
+ public void setLevel(String level) {
+ this.level = level;
+ }
+
+ public String getMaxFileSize() {
+ return maxFileSize;
+ }
+
+ public void setMaxFileSize(String maxFileSize) {
+ this.maxFileSize = maxFileSize;
+ }
+
+ public String getTotalFileSize() {
+ return totalFileSize;
+ }
+
+ public void setTotalFileSize(String totalFileSize) {
+ this.totalFileSize = totalFileSize;
+ }
+
+ public Integer getMaxHistory() {
+ return maxHistory;
+ }
+
+ public void setMaxHistory(Integer maxHistory) {
+ this.maxHistory = maxHistory;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+}
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/config/SpringBootLogConfig.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/config/SpringBootLogConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b1688188bcbc32d855e229898adb7e30482bd8c
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/config/SpringBootLogConfig.java
@@ -0,0 +1,7 @@
+package com.gitee.starblues.extension.log.config;
+
+import java.util.Set;
+
+public interface SpringBootLogConfig {
+ Set logConfigLocations();
+}
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/logConfigProcess.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/logConfigProcess.java
new file mode 100644
index 0000000000000000000000000000000000000000..0671450fa3f3d47944f7c91e854e31599adfd778
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/logConfigProcess.java
@@ -0,0 +1,54 @@
+package com.gitee.starblues.extension.log;
+
+import com.gitee.starblues.extension.log.util.LogConfigProcess;
+import com.gitee.starblues.factory.PluginRegistryInfo;
+import com.gitee.starblues.factory.process.pipe.PluginPipeProcessorExtend;
+import com.gitee.starblues.factory.process.pipe.loader.ResourceWrapper;
+import com.gitee.starblues.utils.OrderPriority;
+import org.pf4j.PluginWrapper;
+import org.springframework.core.io.Resource;
+
+import java.util.List;
+
+public class PluginLogConfigProcessor implements PluginPipeProcessorExtend {
+
+ private final LogConfigProcess logConfigProcess = LogConfigProcess.getInstance();
+
+ @Override
+ public String key() {
+ return null;
+ }
+
+ @Override
+ public OrderPriority order() {
+ return OrderPriority.getLowPriority();
+ }
+
+ @Override
+ public void initialize() throws Exception {
+
+ }
+
+ @Override
+ public void registry(PluginRegistryInfo pluginRegistryInfo) throws Exception {
+ if (logConfigProcess == null) {
+ return;
+ }
+ PluginWrapper pluginWrapper = pluginRegistryInfo.getPluginWrapper();
+ ResourceWrapper resourceWrapper = pluginRegistryInfo.getPluginLoadResource(PluginLogConfigLoader.KEY);
+ if (resourceWrapper == null) {
+ return;
+ }
+
+ List pluginResources = resourceWrapper.getResources();
+ if (pluginResources == null || pluginResources.isEmpty()) {
+ return;
+ }
+ logConfigProcess.loadLogConfig(pluginResources, pluginWrapper);
+ }
+
+ @Override
+ public void unRegistry(PluginRegistryInfo pluginRegistryInfo) throws Exception {
+ logConfigProcess.unloadLogConfig(pluginRegistryInfo.getPluginWrapper());
+ }
+}
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/util/ ObjectUtil.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/util/ ObjectUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac2909251d94117a615c2ac43e9123cb6b04d602
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/util/ ObjectUtil.java
@@ -0,0 +1,49 @@
+package com.gitee.starblues.extension.log.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ObjectUtil {
+
+ public static Object parseBasicTypeValue(Class> fieldType, String defaultValue) {
+ Object fixedValue;
+ if (Byte.class == fieldType || byte.class == fieldType) {
+ fixedValue = Byte.parseByte(defaultValue);
+ } else if (Integer.class == fieldType || int.class == fieldType) {
+ fixedValue = Integer.parseInt(defaultValue);
+ } else if (Double.class == fieldType || double.class == fieldType) {
+ fixedValue = Double.parseDouble(defaultValue);
+ } else if (Short.class == fieldType || short.class == fieldType) {
+ fixedValue = Short.parseShort(defaultValue);
+ } else if (Long.class == fieldType || long.class == fieldType) {
+ fixedValue = Long.parseLong(defaultValue);
+ } else if (Float.class == fieldType || float.class == fieldType) {
+ fixedValue = Float.parseFloat(defaultValue);
+ } else if (Boolean.class == fieldType || boolean.class == fieldType) {
+ fixedValue = Boolean.parseBoolean(defaultValue);
+ } else if (Character.class == fieldType || char.class == fieldType) {
+ fixedValue = defaultValue.charAt(0);
+ } else {
+ fixedValue = defaultValue;
+ }
+ return fixedValue;
+ }
+
+ public static boolean isEmptyObject(Class> fieldType, Object fieldValue) {
+ if (Byte.class == fieldType || byte.class == fieldType) {
+ return (byte) fieldValue == 0;
+ } else if (Integer.class == fieldType || int.class == fieldType) {
+ return (int) fieldValue == 0;
+ } else if (Double.class == fieldType || double.class == fieldType) {
+ return (double) fieldValue == 0;
+ } else if (Short.class == fieldType || short.class == fieldType) {
+ return (short) fieldValue == 0;
+ } else if (Long.class == fieldType || long.class == fieldType) {
+ return (long) fieldValue == 0;
+ } else if (Float.class == fieldType || float.class == fieldType) {
+ return (float) fieldValue == 0;
+ }
+ return false;
+ }
+
+}
diff --git a/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/util/LogConfigProcess.java b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/util/LogConfigProcess.java
new file mode 100644
index 0000000000000000000000000000000000000000..53aa7bcd0f578f3a69ce94e2017838075536abe6
--- /dev/null
+++ b/springboot-plugin-framework-extension/springboot-plugin-framework-extension-log/src/main/java/com/gitee/starblues/extension/log/util/LogConfigProcess.java
@@ -0,0 +1,244 @@
+package com.gitee.starblues.extension.log.util;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.ConsoleAppender;
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.rolling.RollingFileAppender;
+import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
+import ch.qos.logback.core.spi.FilterReply;
+import ch.qos.logback.core.util.FileSize;
+import ch.qos.logback.core.util.OptionHelper;
+import com.gitee.starblues.extension.log.annotation.ConfigItem;
+import com.gitee.starblues.extension.log.config.LogConfig;
+import org.pf4j.PluginWrapper;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.Resource;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class LogConfigProcess {
+
+ private org.slf4j.Logger log = LoggerFactory.getLogger(LogConfigProcess.class);
+
+ private final Map pluginLogMap = new HashMap<>();
+
+ private static LogConfigProcess instance = null;
+
+ private LogConfigProcess() {
+ }
+
+ public static LogConfigProcess getInstance() {
+ if (instance == null) {
+ synchronized (LogConfigProcess.class) {
+ if (instance == null) {
+ instance = new LogConfigProcess();
+ }
+ }
+ }
+ return instance;
+ }
+
+ public void loadLogConfig(List resources, PluginWrapper pluginWrapper) {
+ resources.forEach(resource -> {
+ String configText;
+ try {
+ configText = readConfigText(resource);
+ } catch (IOException e) {
+ log.error("Failed to read log configuration.", e);
+ return;
+ }
+ LogConfig logConfig;
+ try {
+ logConfig = (LogConfig) xml2object(configText);
+ } catch (Exception e) {
+ log.error("", e);
+ return;
+ }
+ checkLogConfig(logConfig, pluginWrapper.getPluginId());
+ String pluginClass = pluginWrapper.getDescriptor().getPluginClass();
+ String packageName = pluginClass.substring(0, pluginClass.lastIndexOf("."));
+ splitPluginLog(pluginWrapper, logConfig, packageName);
+ String pluginId = pluginWrapper.getPluginId();
+ logConfig.setPattern(packageName);
+ pluginLogMap.put(pluginId, logConfig);
+ });
+ }
+
+ public void unloadLogConfig(PluginWrapper pluginWrapper) {
+ pluginLogMap.remove(pluginWrapper.getPluginId());
+ }
+
+ private void splitPluginLog(PluginWrapper pluginWrapper, LogConfig logConfig, String packageName) {
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ Logger logger = context.getLogger(packageName);
+ logger.detachAndStopAllAppenders();
+
+ ConsoleAppender consoleAppender = createConsoleAppender(pluginWrapper, logConfig, packageName);
+ RollingFileAppender fileAppender = createFileAppender(pluginWrapper, logConfig, packageName);
+
+ logger.setAdditive(false);
+ logger.setLevel(Level.toLevel(logConfig.getLevel()));
+ logger.addAppender(consoleAppender);
+ logger.addAppender(fileAppender);
+ }
+
+ private ConsoleAppender createConsoleAppender(PluginWrapper pluginWrapper, LogConfig logConfig, String packageName) {
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ ConsoleAppender appender = new ConsoleAppender<>();
+ Filter filter = new LogFilter(packageName);
+ filter.start();
+ appender.addFilter(filter);
+ appender.setContext(context);
+ appender.setName(pluginWrapper.getPluginId().concat("-console"));
+
+ PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+ encoder.setContext(context);
+ encoder.setPattern(logConfig.getPattern());
+ encoder.start();
+
+ appender.setEncoder(encoder);
+ appender.start();
+ return appender;
+ }
+
+ private RollingFileAppender createFileAppender(PluginWrapper pluginWrapper, LogConfig logConfig, String packageName) {
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ RollingFileAppender appender = new RollingFileAppender<>();
+ Filter filter = new LogFilter(packageName);
+ filter.start();
+
+ appender.addFilter(filter);
+
+ appender.setContext(context);
+ appender.setName(pluginWrapper.getPluginId().concat("-file"));
+
+ String fileName = logConfig.getFileName();
+ if (fileName == null || "".equals(fileName)) {
+ fileName = pluginWrapper.getPluginId();
+ }
+
+ String home = pluginWrapper.getPluginPath().toString();
+ String logPrefix = home.concat("/logs/").concat(pluginWrapper.getPluginId()).concat("/").concat(fileName);
+ appender.setFile(OptionHelper.substVars(logPrefix.concat(".log"), context));
+
+ appender.setAppend(true);
+ appender.setPrudent(false);
+
+ SizeAndTimeBasedRollingPolicy policy = new SizeAndTimeBasedRollingPolicy<>();
+
+ String fp = OptionHelper.substVars(logPrefix.concat(".%d{yyyy-MM-dd}%i.log"), context);
+ policy.setMaxFileSize(FileSize.valueOf(logConfig.getMaxFileSize()));
+ policy.setFileNamePattern(fp);
+ policy.setMaxHistory(logConfig.getMaxHistory());
+ policy.setTotalSizeCap(FileSize.valueOf(logConfig.getTotalFileSize()));
+ policy.setParent(appender);
+ policy.setContext(context);
+ policy.start();
+
+ PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+ encoder.setContext(context);
+ encoder.setPattern(logConfig.getPattern());
+ encoder.start();
+
+ appender.setRollingPolicy(policy);
+ appender.setEncoder(encoder);
+ appender.start();
+ return appender;
+ }
+
+ private static class LogFilter extends Filter {
+
+ private final String packageName;
+ private final LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
+
+ private LogFilter(String packageName) {
+ this.packageName = packageName;
+ }
+
+ @Override
+ public FilterReply decide(ILoggingEvent event) {
+ Logger logger = loggerContext.getLogger(packageName);
+ if (event.getLoggerName().startsWith(packageName) && event.getLevel().isGreaterOrEqual(logger.getLevel())) {
+ return FilterReply.ACCEPT;
+ }
+ return FilterReply.DENY;
+ }
+ }
+
+ private void checkLogConfig(LogConfig logConfig, String pluginId) {
+ String fileName = logConfig.getFileName();
+ if (fileName == null || "".equals(fileName)) {
+ logConfig.setFileName(pluginId.concat("Log"));
+ }
+ Field[] fields = LogConfig.class.getDeclaredFields();
+ Arrays.stream(fields).forEach(field -> {
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ ConfigItem configItem = field.getDeclaredAnnotation(ConfigItem.class);
+ if (configItem == null) {
+ return;
+ }
+ try {
+ Object fieldValue = field.get(logConfig);
+ Class> fieldType = field.getType();
+ if ("".equals(fieldValue.toString()) || ObjectUtil.isEmptyObject(fieldType, fieldValue)) {
+ String defaultValue = configItem.defaultValue();
+ log.debug("Field {} is not config or invalid in log config of plugin {}, set it to default value {}.", field.getName(), defaultValue, pluginId);
+ Object fixedValue = ObjectUtil.parseBasicTypeValue(fieldType, defaultValue);
+ field.set(logConfig, fixedValue);
+ }
+ } catch (IllegalAccessException e) {
+ log.error("Failed to check config item {} in log config.", field.getName());
+ }
+ });
+ }
+
+ public Map getPluginLogMap() {
+ return pluginLogMap;
+ }
+
+ private String readConfigText(Resource resource) throws IOException {
+ String fileContent;
+ try (InputStream inputStream = resource.getInputStream();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+ byte[] buff = new byte[1024];
+ int len;
+ while ((len = inputStream.read(buff)) != -1) {
+ baos.write(buff, 0, len);
+ }
+ byte[] data = baos.toByteArray();
+ fileContent = new String(data);
+ }
+ return fileContent;
+ }
+
+ private Object xml2object(String xml) throws Exception {
+ Object object;
+ try {
+ JAXBContext context = JAXBContext.newInstance(LogConfig.class);
+ Unmarshaller unmarshaller = context.createUnmarshaller();
+ StringReader stringReader = new StringReader(xml);
+ object = unmarshaller.unmarshal(stringReader);
+ } catch (JAXBException e) {
+ throw new Exception("Invalid xml definition");
+ }
+ return object;
+ }
+
+}