The log4j2 log level cannot be changed
SpringBoot dynamically sets the logback log level
The above two articles are merely technical in that dynamic logging configuration is possible. However, there is no solution suitable for production environment. Today we introduce a dynamic configuration log level based on Nacos configuration center.
0x01: Install the Nacos configuration center
Configuration center Nacos official website
Liverpoolfc.tv: nacos. IO/useful – cn/docs /… Downloading the Installation package
It is important to note that Nacos requires a 64-bit operating system and a 64-bit JDK, and the following exceptions will occur if it is not started 64-bit.
at com.alipay.sofa.jraft.core.NodeImpl.init(NodeImpl.java:138) at com.alipay.sofa.jraft.RaftServiceFactory.createAndInitRaftNode(RaftServiceFactory.java:47) at com.alipay.sofa.jraft.RaftGroupService.start(RaftGroupService.java:129) at com.alibaba.nacos.core.distributed.raft.JRaftServer.createMultiRaftGroup(JRaftServer.java:268) at com.alibaba.nacos.core.distributed.raft.JRaftProtocol.addRequestProcessors(JRaftProtocol.java:163) at com.alibaba.nacos.naming.core.v2.service.impl.PersistentClientOperationServiceImpl.<init>(PersistentClientOperationServi ceImpl.java:92) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:175) ... 57 common frames omitted Caused by: java.lang.UnsupportedOperationException: Cannot determine JNI library name for ARCH='x86' OS='windows 10' name='rocksdb' at org.rocksdb.util.Environment.getJniLibraryName(Environment.java:88) at org.rocksdb.NativeLibraryLoader.<clinit>(NativeLibraryLoader.java:19) ... 74 common frames omittedCopy the code
Start the command
startup.cmd -m standalone
Copy the code
Because the startup script starts in cluster mode by default, to avoid the need to use commands, modify the startup script as follows
If the startup is successful, the following log is displayed
2021-05-14 22:00:34, 5 INFO: Exposing to the brilliant 16 2021-05-14 22:00:38, 2038 INFO Tomcat started on port(s): 8848 (HTTP) with context path ‘/nacos’ 2021-05-14 22:00:34,473 INFO nacos started successfully in stand alone mode. Use The embedded Storage accesses the Nacos configuration center with the corresponding account and password Nacos/Nacos
http://192.168.10.6:8848/nacos/index.html
0x02: Create the configuration file dynamics-log.json in the configuration center
The following
{
"logger": [
{
"name":"ROOT",
"level":"debug"
}
]
}
Copy the code
0x03: Pom.xml file introduces dependencies
The < 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" > < modelVersion > 4.0.0 < / modelVersion > < groupId > com. Olive < / groupId > < artifactId > valid - demo < / artifactId > < version > 0.0.1 - the SNAPSHOT < / version > < packaging > jar < / packaging > < the parent > < groupId > org. Springframework. Boot < / groupId > <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.8.RELEASE</version> <relativePath /> </parent> <name>valid-demo</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> < the groupId > com. Alibaba. Nacos < / groupId > < artifactId > nacos - client < / artifactId > < version > 0.5.0 < / version > < / dependency > </dependencies> </project>Copy the code
Nacos client (NACOS-client) dependency is mainly introduced
0x04: Compiler listener
To achieve dynamic effects, there are generally two methods: PUSH and PULL. Nacos provides listeners that can listen on different data-ids as long as the relevant methods are implemented. The general code is as follows:
import java.util.concurrent.Executor; import javax.annotation.PostConstruct; import org.springframework.context.annotation.Configuration; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; @configuration public class LoggerDynamicsConfig {private String serverAddr = "127.0.0.1:"; @configuration public class LoggerDynamicsConfig {private String serverAddr = "127.0.0.1:"; private String dataId = "dynamics-log.json"; private String group = "DEFAULT_GROUP"; private long timeoutMs = 50000L; @PostConstruct public void init() { try { ConfigService configService = NacosFactory.createConfigService(serverAddr); String configInfo = configService.getConfig(dataId, group, timeoutMs); System.out.println("configInfo = " + configInfo); configService.addListener(dataId, group, new Listener() { @Override public void receiveConfigInfo(String configInfo) { System.out.println("recieve configInfo : " + configInfo); } @Override public Executor getExecutor() { return null; }}); } catch (NacosException e) { e.printStackTrace(); }}}Copy the code
After the service is started, the console displays the following log, indicating that the configuration items of the Nacos configuration center can be obtained.
The 2021-05-14 22:13:56. 265. [the main] INFO c.a. libaba. Nacos. Client. The identify. CredentialWatcher - [] [] [] No credential found configInfo = { "logger": [ { "name":"ROOT", "level":"debug" } ] } recieve configInfo : { "logger": [ { "name":"ROOT", "Level" : "debug"}}] 22:13:56. 2021-05-14, 563 [main] INFO O.S.S cheduling. Concurrent. ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'Copy the code
In the Nacos configuration center, you can see that the console prints the following log, indicating that the service can dynamically listen for configuration changes.
recieve configInfo : {
"logger": [
{
"name":"ROOT",
"level":"debug"
}, {
"name":"com.spring",
"level":"info"
}
]
}
Copy the code
0x05: Description of dynamic log transformation
In the receiveConfigInfo() method, construct the configuration JSON string as an array of objects, such as LoggerConfig[].
Change LoggerController’s printAllLogger() method to a method that gets all log objects, based on SpringBoot dynamically setting logback log levels
public List<Logger> getAllLogger(){
//TODO
}
Copy the code
Dynamically update the LoggerConfig[] array constructed by configuration changes dynamically by traversing and comparing all log objects retrieved by calling getAllLogger()