配置中心支持动态更改日志配置
This commit is contained in:
@@ -128,9 +128,6 @@ public final class Application {
|
|||||||
|
|
||||||
private static final int UDP_CAPACITY = 1024;
|
private static final int UDP_CAPACITY = 1024;
|
||||||
|
|
||||||
//仅仅用于传递给LoggingSearchHandler使用
|
|
||||||
static Application currentApplication;
|
|
||||||
|
|
||||||
//本进程节点ID
|
//本进程节点ID
|
||||||
final int nodeid;
|
final int nodeid;
|
||||||
|
|
||||||
@@ -144,6 +141,9 @@ public final class Application {
|
|||||||
//@since 2.3.0
|
//@since 2.3.0
|
||||||
final ExecutorService workExecutor;
|
final ExecutorService workExecutor;
|
||||||
|
|
||||||
|
//日志配置资源
|
||||||
|
final Properties loggingProperties = new Properties();
|
||||||
|
|
||||||
//Source 原始的配置资源, 只会存在redkale.datasource(.|[) redkale.cachesource(.|[)开头的配置项
|
//Source 原始的配置资源, 只会存在redkale.datasource(.|[) redkale.cachesource(.|[)开头的配置项
|
||||||
final Properties sourceProperties = new Properties();
|
final Properties sourceProperties = new Properties();
|
||||||
|
|
||||||
@@ -582,6 +582,7 @@ public final class Application {
|
|||||||
private void loadResourceProperties() throws IOException {
|
private void loadResourceProperties() throws IOException {
|
||||||
final Properties dyncProps = new Properties();
|
final Properties dyncProps = new Properties();
|
||||||
final AtomicInteger propertyIndex = new AtomicInteger();
|
final AtomicInteger propertyIndex = new AtomicInteger();
|
||||||
|
Properties logProps = null; //新的日志配置项
|
||||||
//------------------------------------ 读取本地DataSource、CacheSource配置 ------------------------------------
|
//------------------------------------ 读取本地DataSource、CacheSource配置 ------------------------------------
|
||||||
if ("file".equals(this.confPath.getScheme())) {
|
if ("file".equals(this.confPath.getScheme())) {
|
||||||
File sourceFile = new File(new File(confPath), "source.properties");
|
File sourceFile = new File(new File(confPath), "source.properties");
|
||||||
@@ -689,9 +690,19 @@ public final class Application {
|
|||||||
if (compileMode) {
|
if (compileMode) {
|
||||||
this.propertiesAgent.compile(propertiesConf);
|
this.propertiesAgent.compile(propertiesConf);
|
||||||
} else {
|
} else {
|
||||||
Properties props = this.propertiesAgent.init(this, propertiesConf);
|
Map<String, Properties> propMap = this.propertiesAgent.init(this, propertiesConf);
|
||||||
if (props != null) {
|
if (propMap != null) {
|
||||||
agentEnvs.putAll(props);
|
for (Map.Entry<String, Properties> en : propMap.entrySet()) {
|
||||||
|
if (en.getKey().startsWith("logging")) {
|
||||||
|
if (logProps != null) {
|
||||||
|
logger.log(Level.WARNING, "skip repeat logging config properties(" + en.getKey() + ")");
|
||||||
|
} else {
|
||||||
|
logProps = en.getValue();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
agentEnvs.putAll(en.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info("PropertiesAgent (type = " + this.propertiesAgent.getClass().getSimpleName() + ") init in " + (System.currentTimeMillis() - s) + " ms");
|
logger.info("PropertiesAgent (type = " + this.propertiesAgent.getClass().getSimpleName() + ") init in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
@@ -798,6 +809,10 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//重置日志配置
|
||||||
|
if (logProps != null && !logProps.isEmpty()) {
|
||||||
|
reconfigLogging(logProps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reconfigLogging(Properties properties0) {
|
void reconfigLogging(Properties properties0) {
|
||||||
@@ -887,8 +902,19 @@ public final class Application {
|
|||||||
final PrintStream ps = new PrintStream(out);
|
final PrintStream ps = new PrintStream(out);
|
||||||
properties.forEach((x, y) -> ps.println(x + "=" + y));
|
properties.forEach((x, y) -> ps.println(x + "=" + y));
|
||||||
try {
|
try {
|
||||||
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
|
LogManager manager = LogManager.getLogManager();
|
||||||
} catch (IOException e) {
|
manager.readConfiguration(new ByteArrayInputStream(out.toByteArray()));
|
||||||
|
loggingProperties.clear();
|
||||||
|
loggingProperties.putAll(properties);
|
||||||
|
Enumeration<String> en = manager.getLoggerNames();
|
||||||
|
while (en.hasMoreElements()) {
|
||||||
|
for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) {
|
||||||
|
if (handler instanceof LoggingSearchHandler) {
|
||||||
|
((LoggingSearchHandler) handler).application = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) { //不会发生
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1775,7 +1801,6 @@ public final class Application {
|
|||||||
//PrepareCompiler.main(args); //测试代码
|
//PrepareCompiler.main(args); //测试代码
|
||||||
|
|
||||||
final Application application = Application.create(false);
|
final Application application = Application.create(false);
|
||||||
currentApplication = application;
|
|
||||||
application.init();
|
application.init();
|
||||||
application.startSelfServer();
|
application.startSelfServer();
|
||||||
try {
|
try {
|
||||||
@@ -1794,7 +1819,7 @@ public final class Application {
|
|||||||
return value == null ? value : value.replace("${APP_HOME}", homePath).replace("${APP_NAME}", name);
|
return value == null ? value : value.replace("${APP_HOME}", homePath).replace("${APP_NAME}", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateEnvironmentProperties(List<ResourceEvent> events) {
|
void updateEnvironmentProperties(String namespace, List<ResourceEvent> events) {
|
||||||
if (events == null || events.isEmpty()) return;
|
if (events == null || events.isEmpty()) return;
|
||||||
synchronized (envProperties) {
|
synchronized (envProperties) {
|
||||||
Properties envRegisterProps = new Properties();
|
Properties envRegisterProps = new Properties();
|
||||||
@@ -1803,11 +1828,16 @@ public final class Application {
|
|||||||
|
|
||||||
Set<String> sourceRemovedKeys = new HashSet<>();
|
Set<String> sourceRemovedKeys = new HashSet<>();
|
||||||
Properties sourceChangedProps = new Properties();
|
Properties sourceChangedProps = new Properties();
|
||||||
|
Properties loggingChangedProps = new Properties();
|
||||||
for (ResourceEvent<String> event : events) {
|
for (ResourceEvent<String> event : events) {
|
||||||
|
if (namespace != null && namespace.startsWith("logging")) {
|
||||||
|
loggingChangedProps.put(event.name(), event.newValue());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (event.name().startsWith("redkale.datasource.") || event.name().startsWith("redkale.datasource[")
|
if (event.name().startsWith("redkale.datasource.") || event.name().startsWith("redkale.datasource[")
|
||||||
|| event.name().startsWith("redkale.cachesource.") || event.name().startsWith("redkale.cachesource[")) {
|
|| event.name().startsWith("redkale.cachesource.") || event.name().startsWith("redkale.cachesource[")) {
|
||||||
if (event.name().endsWith(".name")) {
|
if (event.name().endsWith(".name")) {
|
||||||
logger.log(Level.WARNING, "skip illegal key " + event.name() + " in source config, key cannot endsWith '.name'");
|
logger.log(Level.WARNING, "skip illegal key " + event.name() + " in source config " + (namespace == null ? "" : namespace) + ", key cannot endsWith '.name'");
|
||||||
} else {
|
} else {
|
||||||
if (!Objects.equals(event.newValue(), sourceProperties.getProperty(event.name()))) {
|
if (!Objects.equals(event.newValue(), sourceProperties.getProperty(event.name()))) {
|
||||||
if (event.newValue() == null) {
|
if (event.newValue() == null) {
|
||||||
@@ -1864,6 +1894,26 @@ public final class Application {
|
|||||||
envRemovedKeys.forEach(k -> envProperties.remove(k));
|
envRemovedKeys.forEach(k -> envProperties.remove(k));
|
||||||
resourceFactory.register(envRegisterProps, "", Environment.class);
|
resourceFactory.register(envRegisterProps, "", Environment.class);
|
||||||
}
|
}
|
||||||
|
//日志配置项的变更
|
||||||
|
if (!loggingChangedProps.isEmpty()) {
|
||||||
|
//只是简单变更日志级别则直接操作,无需重新配置日志
|
||||||
|
if (loggingChangedProps.size() == 1 && loggingChangedProps.containsKey(".level")) {
|
||||||
|
try {
|
||||||
|
Level logLevel = Level.parse(loggingChangedProps.getProperty(".level"));
|
||||||
|
Logger.getGlobal().setLevel(logLevel);
|
||||||
|
loggingProperties.putAll(loggingChangedProps);
|
||||||
|
logger.log(Level.INFO, "reconfig logging level to " + logLevel);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "reconfig logging level error, new level is " + loggingChangedProps.getProperty(".level"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Properties newLogProps = new Properties();
|
||||||
|
newLogProps.putAll(this.loggingProperties);
|
||||||
|
newLogProps.putAll(loggingChangedProps);
|
||||||
|
reconfigLogging(newLogProps);
|
||||||
|
logger.log(Level.INFO, "reconfig logging finished ");
|
||||||
|
}
|
||||||
|
}
|
||||||
//数据源配置项的变更
|
//数据源配置项的变更
|
||||||
if (!sourceChangedProps.isEmpty() || !sourceRemovedKeys.isEmpty()) {
|
if (!sourceChangedProps.isEmpty() || !sourceRemovedKeys.isEmpty()) {
|
||||||
Set<String> cacheSourceNames = new LinkedHashSet<>();
|
Set<String> cacheSourceNames = new LinkedHashSet<>();
|
||||||
|
|||||||
@@ -14,7 +14,4 @@ import java.util.logging.Handler;
|
|||||||
*/
|
*/
|
||||||
public abstract class LoggingBaseHandler extends Handler {
|
public abstract class LoggingBaseHandler extends Handler {
|
||||||
|
|
||||||
protected Application currentApplication() {
|
|
||||||
return Application.currentApplication; //不能直接暴露外界访问
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ public class LoggingSearchHandler extends LoggingBaseHandler {
|
|||||||
|
|
||||||
protected SearchSource source;
|
protected SearchSource source;
|
||||||
|
|
||||||
|
//在LogManager.getLogManager().readConfiguration执行完后,通过反射注入Application
|
||||||
|
protected Application application;
|
||||||
|
|
||||||
public LoggingSearchHandler() {
|
public LoggingSearchHandler() {
|
||||||
configure();
|
configure();
|
||||||
open();
|
open();
|
||||||
@@ -95,7 +98,10 @@ public class LoggingSearchHandler extends LoggingBaseHandler {
|
|||||||
if (retryCount.get() < 1) return;
|
if (retryCount.get() < 1) return;
|
||||||
try {
|
try {
|
||||||
Utility.sleep(3000); //如果SearchSource自身在打印日志,需要停顿一点时间让SearchSource初始化完成
|
Utility.sleep(3000); //如果SearchSource自身在打印日志,需要停顿一点时间让SearchSource初始化完成
|
||||||
Application application = currentApplication();
|
if (application == null) {
|
||||||
|
Utility.sleep(3000);
|
||||||
|
}
|
||||||
|
if (application == null) return;
|
||||||
this.source = (SearchSource) application.loadDataSource(sourceResourceName, false);
|
this.source = (SearchSource) application.loadDataSource(sourceResourceName, false);
|
||||||
if (retryCount.get() == 1 && this.source == null) System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")");
|
if (retryCount.get() == 1 && this.source == null) System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")");
|
||||||
} catch (Exception t) {
|
} catch (Exception t) {
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ public abstract class PropertiesAgent {
|
|||||||
* @param application Application
|
* @param application Application
|
||||||
* @param conf 节点配置
|
* @param conf 节点配置
|
||||||
*
|
*
|
||||||
* @return 加载的配置项
|
* @return 加载的配置项, key:namespace
|
||||||
*/
|
*/
|
||||||
public abstract Properties init(Application application, AnyValue conf);
|
public abstract Map<String, Properties> init(Application application, AnyValue conf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 销毁动作
|
* 销毁动作
|
||||||
@@ -56,18 +56,9 @@ public abstract class PropertiesAgent {
|
|||||||
*/
|
*/
|
||||||
public abstract void destroy(AnyValue conf);
|
public abstract void destroy(AnyValue conf);
|
||||||
|
|
||||||
protected void updateEnvironmentProperties(Application application, List<ResourceEvent> events) {
|
protected void updateEnvironmentProperties(Application application, String namespace, List<ResourceEvent> events) {
|
||||||
if (events == null || events.isEmpty()) return;
|
if (events == null || events.isEmpty()) return;
|
||||||
application.updateEnvironmentProperties(events);
|
application.updateEnvironmentProperties(namespace, events);
|
||||||
// Properties envChangeCache = new Properties();
|
|
||||||
// Properties sourceChangeCache = new Properties();
|
|
||||||
// //props.forEach((k, v) -> application.updateEnvironmentProperty(k.toString(), v.toString().trim(), envChangeCache, sourceChangeCache));
|
|
||||||
// if (!envChangeCache.isEmpty()) {
|
|
||||||
// application.resourceFactory.register(envChangeCache, "", Environment.class);
|
|
||||||
// }
|
|
||||||
// if (!sourceChangeCache.isEmpty()) {
|
|
||||||
// application.updateSourceProperties(sourceChangeCache);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void reconfigLogging(Application application, Properties loggingProperties) {
|
protected void reconfigLogging(Application application, Properties loggingProperties) {
|
||||||
|
|||||||
Reference in New Issue
Block a user