背景
项目需要快速跟踪方法调用链与当前节点信息
- 开发模式使用debug
- 生产模式使用日志
需要达到几点要求
- 项目上线时不需要临时修改配置文件打包应用(临时切换参数往往造成上线升级失败),而是通过打包命令(如maven -Ppro )或是启动命令来指定(启动脚本)
- 日志中能体现服务名称 & 端口 。便于nginx日志快速定位到服务节点。
[pro-recharge-txp-8091]07-24 05:59:55.806
[pro-recharge-txp-8191]07-24 05:59:55.745
[pro-recharge-boss]07-24 06:39:26.042
// 上面三个内容分别是代表 txp二个节点; boss一个节点
- 单个日志文件不能过大,太大不便于view.自动按指定的大小进行切割归档。
- 日志服务调用链唯一标识
单体应用
指非微服务模式,支持高可用分布式部署(多机或是一机多包)。通过nginx时转发ip与端口快速定位节点,另nginx开启请求内容输出更方便。
103.45.248.43 - - [25/Jul/2022:06:44:16 +0800] "POST /api/v1.1.0/query HTTP/1.1" 200 424 "-" "-" "-" ["customerNo=1000055&outTradeNo=202207258884409924×tamp=2
0220725064415&sign=450DF9FEA5C851B4CDB00568C8BA92B4"] "103.92.132.118:8191" "200" "0.099" "0.042"
-- 此处有请求内容唯一标识 & 对应转发节点信息
springmvc+tomcat
springmvc项目很多跑在独立tomcat服务器上,对外提供的端口由tomcat指定。springmvc项目启动需要获取tomcat指定端口注入到日志框架(logback.xml)
以下为结合片段
- 启动服务时,获取tomcat的端口
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* 配合logback.xml 获取web服务器(如tomcat) 的端口。
* @author xiaoming
* @date 2019/5/14 11:37
* @description
*/
public class LogPortConfig extends ClassicConverter {
private static final Logger logger = LoggerFactory.getLogger(LogPortConfig.class);
private static String webPort;
static {
try {
List<MBeanServer> serverList = MBeanServerFactory.findMBeanServer(null);
for (MBeanServer server : serverList) {
Set<ObjectName> names = new HashSet<ObjectName>();
names.addAll(server.queryNames(new ObjectName("Catalina:type=Connector,*"), null));
Iterator<ObjectName> it = names.iterator();
while (it.hasNext()) {
ObjectName oName = (ObjectName) it.next();
String pValue = (String) server.getAttribute(oName, "protocol");
if (StringUtils.equals("HTTP/1.1", pValue) || StringUtils.contains(pValue,"Http11NioProtocol")) {
webPort = ObjectUtils.toString(server.getAttribute(oName, "port"));
}
}
}
} catch (Exception e) {
logger.error("获取port失败,影响logback的文件拼接", e);
webPort = null;
}
}
@Override
public String convert(ILoggingEvent event) {
return webPort;
}
}
- 在logback.xml中进行配置: 查看tport用法
```
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<property name="logPath" value="${catalina.base}/logs"/>
<conversionRule conversionWord="tport" converterClass="com.dx.exiaoka.recharge.txp.config.LogPortConfig"/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按日期与小时来进行配置 -->
<appender name="infoFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/recharge_txp.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件的路径与名称,{yyyy-MM-dd.HH}精确到小时,则按小时分割保存${logPath}/recharge_txp.%d{yyyy-MM-dd.HH}.log ; 分为${logPath}/recharge_txp.%d{yyyy-MM-dd.HH.mm}.log -->
<fileNamePattern>${logPath}/recharge_txp.%d{yyyy-MM-dd-HH}.log</fileNamePattern>
<!-- 如果当前是按小时保存,则保存72小时(=3天)内的日志 -->
<maxHistory>72</maxHistory>
</rollingPolicy>
<encoder>
<pattern>[dev-recharge-txp-%tport] %d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger:[%M] %line - %msg%n
</pattern>
</encoder>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="infoFile"/>
</appender>
<appender name="warnFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/warn_recharge_txp.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/warn_recharge_txp.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<appender name="errorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/error_recharge_txp.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/error_recharge_txp.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<!-- <logger name="com.dx" level="INFO" />-->
<logger name="com.alisoft" level="WARN"/>
<logger name="com.google.code.yanf4j" level="WARN"/>
<logger name="net.rubyeye" level="WARN"/>
<logger name="com.ibatis.common.jdbc" level="debug"/>
<logger name="Java.sql" level="debug"/>
<logger name="org.springframework.scheduling.quartz" level="info" additivity="false"/>
<logger name="org.quartz.impl" level="info" additivity="false"/>
<logger name="httpclient" level="INFO" additivity="false"/>
<root level="debug">
<appender-ref ref="console"/>
<!-- <appender-ref ref="ASYNC"/>-->
<appender-ref ref="infoFile"/>
<appender-ref ref="warnFile"/>
<appender-ref ref="errorFile"/>
</root>
</configuration>
微服务
....