上次寫了一個通用logback(下面的鏈接),log信息是全面,但有很多運行log對開發運營人員是無用,這些冗餘log影響開發人員閱讀。
https://blog.csdn.net/thankna/article/details/105936016
這次按照項目需求,springboot中logback只輸出指定log
一種攔截自動輸出每個request的log,通俗講就是一個controller一個
一種只輸出class中手動加入的log【模仿log4j】)
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<property name="logs" value="./logs" />
<property name="ROOT_LEVEL" value="INFO" />
<statusListener
class="ch.qos.logback.core.status.NopStatusListener" />
<appender name="CONSOLE_OUT"
class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
%-15(%d{HH:mm:ss.SSS}) [%thread]%-5level%logger{80}[%line] - %msg%n
</pattern>
</layout>
</appender>
<appender name="ACCESS_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<file>${logs}/access.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<file>${logs}/access.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logs}/access_%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} %logger - %msg%n
</pattern>
</encoder>
</appender>
<appender name="JSON_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<file>${logs}/josn.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
${logs}/json_%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="jp.co.pia.ticket.sports.hawks.seasonseat.common.util.common.JsonLogLayout" />
</encoder>
</appender>
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<file>${logs}/error.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
${logs}/error_%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<!-- <pattern>%d{yyyy-MMM-dd HH:mm:ss.SSS} %-5level [%t] [%X{client}] [%X{sessionId}] %msg%n</pattern> -->
<pattern>%d{yyyy-MMM-dd HH:mm:ss.SSS} %-5level [%t] %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="OPERATE_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<file>${logs}/operate.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<file>${logs}/operate.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logs}/operate_%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} %logger - %msg%n
</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="CONSOLE_OUT" />
<appender-ref ref="ERROR" />
<appender-ref ref="JSON_LOG" />
</root>
<logger name="ACCESS" level="INFO" additivity="false">
<appender-ref ref="ACCESS_LOG" />
</logger>
<logger name="OPERATE" level="INFO" additivity="false">
<appender-ref ref="OPERATE_LOG" />
</logger>
</configuration>
其中CONSOLE_OUT、ERROR、JSON_LOG是常規log。配置如下
<root level="info">
<appender-ref ref="CONSOLE_OUT" />
<appender-ref ref="ERROR" />
<appender-ref ref="JSON_LOG" />
</root>
第一種ACCESS_LOG是request級別log。配置如下
<logger name="ACCESS" level="INFO" additivity="false">
<appender-ref ref="ACCESS_LOG" />
</logger>
log攔截器配置如下
import java.security.Principal;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import xxx.LogConfig;
public class LogInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger("ACCESS");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
JSONObject json = new JSONObject();
// セッションID
json.put(LogConfig.SESSION_ID, request.getSession().getId());
// ユーザーID
Principal auth = request.getUserPrincipal();
String userId = null;
if (auth != null) {
userId = auth.getName();
}
if (StringUtils.isEmpty(userId)) {
json.put(LogConfig.AUTH_NAME, LogConfig.NONE_STR);
} else {
json.put(LogConfig.AUTH_NAME, userId);
}
// クライアントIP
json.put(LogConfig.IP, request.getRemoteAddr());
// httpメソッド
json.put(LogConfig.HTTP_METHOD, request.getMethod());
// URL
json.put(LogConfig.URL, request.getRequestURI());
// ステータスコード
json.put(LogConfig.HTTP_STATUS_CODE, response.getStatus());
// ログ種類(開始)
json.put(LogConfig.LOG_TYPE, LogConfig.START);
// // 出力メッセージ
// Map<String, String[]> map = request.getParameterMap();
// map.forEach((key, value) -> {
// json.put(key, request.getParameter(key));
// });
logger.info(json.toString());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView)
throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
JSONObject json = new JSONObject();
// セッションID
json.put(LogConfig.SESSION_ID, request.getSession().getId());
// ユーザーID
Principal auth = request.getUserPrincipal();
String userId = null;
if (auth != null) {
userId = auth.getName();
}
if (StringUtils.isEmpty(userId)) {
json.put(LogConfig.AUTH_NAME, LogConfig.NONE_STR);
} else {
json.put(LogConfig.AUTH_NAME, userId);
}
// クライアントIP
json.put(LogConfig.IP, request.getRemoteAddr());
// httpメソッド
json.put(LogConfig.HTTP_METHOD, request.getMethod());
// URL
json.put(LogConfig.URL, request.getRequestURI());
// ステータスコード
json.put(LogConfig.HTTP_STATUS_CODE, response.getStatus());
// ログ種類(終了)
json.put(LogConfig.LOG_TYPE, LogConfig.END);
logger.info(json.toString());
}
}
import java.util.HashMap;
import java.util.Map;
public interface LogConfig {
/** セッションID */
String SESSION_ID = "sessionId"; // jsessionidに設定された値
/** IPアドレス */
String IP = "ip"; // ユーザのIPアドレス
/** URL */
String URL = "url"; // アクセス先のURL
/** ユーザID */
String AUTH_NAME = "userId"; // ログインユーザのユーザID
/** httpメソッド */
String HTTP_METHOD = "httpMethod";
/** ステータスコード */
String HTTP_STATUS_CODE = "httpStatusCode";
/** 固定文言 */
String NONE_STR = "未設定";
String LOG_TYPE = "logType";
String START = "START";
String END = "END ";
String TRACE_ID = "traceId";
/** 畫面名 */
Map<String,String> GAMEN_NAME_MAP = new HashMap<String, String>() {
private static final long serialVersionUID = 1L;
{
put("HSP01002", "xxx");
}
};
}
TraceId攔截器配置如下
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import jp.co.pia.ticket.sports.hawks.seasonseat.common.util.component.LogConfig;
public class TraceIdInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String traceId = UUID.randomUUID().toString().replace("-", "");
MDC.put(LogConfig.TRACE_ID, traceId);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView)
throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
攔截器追加註冊
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class ControllerConfiger implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TraceIdInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
}
第二種OPERATE_LOG類似log4j只打印手動輸出。配置如下
<logger name="OPERATE" level="INFO" additivity="false">
<appender-ref ref="OPERATE_LOG" />
</logger>
個別部打印畫面項目
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import jit.wxs.demo.component.LogConfig;
@Component
public class OperateLog {
/**
* 機能概要:toJsonLog
* @param HttpServletRequest request
* @param HashMap<String, String> parmap
* @return String logmsg
*/
public String toJsonLog(HttpServletRequest request, HashMap<String, String> parmap) throws IOException {
String logmsg = CommonConst.STRING_BLANK;
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
// 共通部
String[] arr = request.getRequestURI().split(CommonConst.SLASH);
String gamenId = arr[1];
map.put(CommonConst.OPERATELOG_GAMENID, gamenId);
String name = LogConfig.GAMEN_NAME_MAP.get(gamenId);
map.put(CommonConst.OPERATELOG_GAMENNAME, name);
map.put(CommonConst.OPERATELOG_UPDDATETIME, parmap.get(CommonConst.OPERATELOG_UPDDATETIME));
map.put(CommonConst.OPERATELOG_USERID, SecurityUtils.getUserId());
map.put(CommonConst.OPERATELOG_USERNAME, SecurityUtils.getUsername());
map.put(CommonConst.OPERATELOG_OPERATION, parmap.get(CommonConst.OPERATELOG_OPERATION));
// 個別部
Map<String, String[]> entmap = request.getParameterMap();
entmap.forEach((key, value) -> {
map.put(key, request.getParameter(key));
});
ObjectMapper mapper = new ObjectMapper();
logmsg = mapper.writeValueAsString(map);
return logmsg;
}
}
@Service
@Slf4j
@Scope("session")
public class HSP01002Service {
@Autowired
private DocumentRequestMapper documentRequestMapper;
/** 操作履歴 */
@Autowired
private OperateLog opLog;
/** log名 */
private Logger logger = LoggerFactory.getLogger(CommonConst.OPERATELOG_LOGNAME);
public int insertDocumentRequest(HSP01002InputEntity tHSP01002InputEntity, HttpServletRequest request) throws Exception {
int num = documentRequestMapper.insertDocumentRequest(documentRequestEntity);
HashMap<String, String>parmap = new HashMap<String, String>();
// 更新日時
parmap.put(CommonConst.OPERATELOG_UPDDATETIME, DateUtil.toDateStringMilliSecByDate(documentRequestEntity.getUpdate_tim()));
// 操作
parmap.put(CommonConst.OPERATELOG_OPERATION, CommonConst.OPERATELOG_INSERT);
// 操作履歴
logger.info(opLog.toJsonLog(request, parmap));
log.debug(this.getClass().getName() + "■insertDocumentRequest end:");
}
logger輸出的是在operate log文件中。沒有任何系統自己出的log。
log輸出在通用的log中,混在一堆log裏。