在我们使用log4j2或者logback打印日志时,输出的内容中通常是一定要加上服务名的。以log4j2为例:
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="server-case %d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n"/>
Console>
服务名为server-case,输出的内容为
server-case 2023-09-15 17:44:38 INFO ServerCaseApplication:648 - No active profile set, falling back to default profiles: default
server-case 2023-09-15 17:44:39 INFO TomcatWebServer:108 - Tomcat initialized with port(s): 7081 (http)
server-case 2023-09-15 17:44:39 INFO Http11NioProtocol:173 - Initializing ProtocolHandler ["http-nio-7081"]
server-case 2023-09-15 17:44:39 INFO StandardService:173 - Starting service [Tomcat]
...
一般而言都是这么配置就可以完整日志的打印了。但事实却不是,会存在这样一种情况,有的业务是需要去操作合作方他们那边的数据的,包括查询和更新。比如物流网、售票业务、挂号业务、等等。这些数据合作方会提供接口来调用。而在乙方这边,会有一个专门的服务来直连这些接口,其他的服务如果需要合作方的数据或者更新了,就会通过微服务调用这个专门对接数据的服务。
当开发的项目时间长了后,就会有不同的合作方,而这些不同的合作方会部署到同一套环境中,就比如说注册中心,用的是同一个,而为了保护这个直连接口的服务,防止某一个服务宕机后,会影响其他的合作方,就会把这个服务按照合作方不同,部署成多个不同的实例。
比如说合作方A B C,那么这个服务的实例就会有ADataService、BDataService、CDataService
这就有个问题,因为都是用的是一套代码,那怎么才能实现在同一套代码上能部署成不同的实例呢?其实可以从jenkins上修改,
先把spring.application.name配置的值,使用占位符设置,比如#spring.application.name#,然后在jenkins部署的使用,执行脚本,按照不同的合作方,来替换掉#spring.application.name#,这样就实现了可以有不同的示例名了
但上述的日志打印服务名还没有解决呢?我们就来解决这个问题
有的人可能会想到直接设置一个对象实现EnvironmentAware接口中的setEnvironment(Environment environment),来获取environment来获取spring.application.name
但这样有问题,设置的这个对象是要在spring上下文中进行加载后才能获得environment,所以在这个对象加载之前的日志输出还是拿不到environment的
@Component
public class Test implements EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(final Environment environment) {
this.environment = environment;
System.setProperty("applicationName", Objects.requireNonNull(environment.getProperty("spring.application.name")));
}
}
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${sys:applicationName} %d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n"/>
Console>
${sys:applicationName} 2023-09-18 10:18:34 INFO ServerCaseApplication:55 - Starting ServerCaseApplication on lukuan with PID 21472 (D:\idea_work_my\gitee\cook-frame\server\server-case\target\classes started by lukuan in D:\idea_work_my\gitee\cook-frame)
${sys:applicationName} 2023-09-18 10:18:34 INFO ServerCaseApplication:648 - No active profile set, falling back to default profiles: default
${sys:applicationName} 2023-09-18 10:18:34 INFO TomcatWebServer:108 - Tomcat initialized with port(s): 7081 (http)
${sys:applicationName} 2023-09-18 10:18:34 INFO Http11NioProtocol:173 - Initializing ProtocolHandler ["http-nio-7081"]
${sys:applicationName} 2023-09-18 10:18:34 INFO StandardService:173 - Starting service [Tomcat]
${sys:applicationName} 2023-09-18 10:18:34 INFO StandardEngine:173 - Starting Servlet engine: [Apache Tomcat/9.0.46]
${sys:applicationName} 2023-09-18 10:18:34 INFO [/]:173 - Initializing Spring embedded WebApplicationContext
${sys:applicationName} 2023-09-18 10:18:34 INFO ServletWebServerApplicationContext:285 - Root WebApplicationContext: initialization completed in 795 ms
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.5.1
service-case 2023-09-18 10:18:35 INFO ThreadPoolTaskExecutor:181 - Initializing ExecutorService 'applicationTaskExecutor'
service-case 2023-09-18 10:18:35 INFO PropertySourcedRequestMappingHandlerMapping:69 - Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
service-case 2023-09-18 10:18:35 INFO Http11NioProtocol:173 - Starting ProtocolHandler ["http-nio-7081"]
service-case 2023-09-18 10:18:35 INFO TomcatWebServer:220 - Tomcat started on port(s): 7081 (http) with context path ''
可以看到比较靠前的日志输出中的applicationName变量是没有被替换成真正的服务名的。
那怎么办呢?
所以我们要从SpringBoot的启动过程入手
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty()