package com.yanzuoguang.cloud.aop; import com.yanzuoguang.util.helper.DateHelper; import com.yanzuoguang.util.helper.StringHelper; import com.yanzuoguang.util.thread.ThreadNext; import com.yanzuoguang.util.vo.LogVo; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.*; /** * 当前线程日志编写 * * @author 颜佐光 */ @Component public class LogLocal implements ThreadNext.Next, InitializingBean { /** * 缓存队列 */ protected volatile Map<String, Timeout<LogVo>> cache = new Hashtable<>(); @Value("${spring.application.name}") protected String applicationName; /** * 1个请求最长时间 */ @Value("${yzg.timeout:300000}") private int timeout; @Value("${yzg.log.notFilter:^.*login.*$}") private String notFilter; @Value("${yzg.log.filter:^.*log.*$}") private String filter; /** * 超时状态 */ public static final String MAX_TIME = "MAX_TIME"; public static final String MAX_TIME_NAME = "执行超时"; /** * 日志基础 */ @Autowired private LogBase logBase; /** * Invoked by a BeanFactory after it has set all bean properties supplied * (and satisfied BeanFactoryAware and ApplicationContextAware). * <p>This method allows the bean instance to perform initialization only * possible when all bean properties have been set and to throw an * exception in the event of misconfiguration. * * @throws Exception in the event of misconfiguration (such * as failure to set an essential property) or if initialization fails. */ @Override public void afterPropertiesSet() throws Exception { ThreadNext.start(this, "save log error"); } /** * 开始记录日志 * * @param actionKey 功能名称 * @param actionSubKey 子功能名称 = 服务名称 + 地址 * @param content 请求内容 * @return */ public LogVo startLog(String actionKey, String actionSubKey, String content) { if (isLog(actionKey, actionSubKey)) { return null; } // 生命日志对象爱嗯 LogVo log = new LogVo(); log.setLogId(StringHelper.getNewID()); log.setActionKey(actionKey); log.setActionSubKey(actionSubKey); log.setContent(content); // 声明超时对象 Timeout<LogVo> time = new Timeout<>(log); log.setCreateDate(DateHelper.getDateTimeString(new Date(time.getStart()))); cache.put(log.getLogId(), time); return log; } /** * 写入状态 * * @param status * @param result * @return */ public void result(LogVo log, String status, String result) { this.result(log, StringHelper.EMPTY, status, result); } /** * 写入状态 * * @param status * @param result * @return */ public void result(LogVo log, String name, String status, String result) { // 日志请求不记录,防止死循环递归 boolean isLog = isLog(name, log.getActionSubKey()); if (isLog) { this.remove(log); } else { Timeout<LogVo> timeout = cache.get(log.getLogId()); result(timeout, log, status, result, true); } } /** * 写入状态 * * @param status * @param result * @return */ private void result(Timeout timeout, LogVo log, String status, String result, boolean write) { if (timeout != null) { long useTime = System.currentTimeMillis() - timeout.getStart(); log.setUseTime((int) useTime); } log.setStatus(status); log.setResult(result); if (!StringHelper.compare(status, MAX_TIME)) { cache.remove(log.getLogId()); } if (write) { logBase.addLog(log); } } /** * 删除请求信息 * * @param log */ private void remove(LogVo log) { Timeout<LogVo> timeout = cache.get(log.getLogId()); result(timeout, log, StringHelper.EMPTY, StringHelper.EMPTY, false); } /** * 记录超时 * * @return */ private void writeTimeout(Timeout<LogVo> timeout) { result(timeout, timeout.getData(), MAX_TIME, MAX_TIME_NAME, true); } /** * 是否属于日志服务 * * @param keys * @return */ public boolean isLog(String... keys) { List<String> list = new ArrayList<>(); list.add(this.applicationName); for (String item : keys) { list.add(item); } // 是否排除 boolean notFilter = false; // 是否过滤 boolean filter = false; for (String item : list) { String lower = item.toLowerCase(); notFilter = notFilter || lower.matches(this.notFilter); filter = filter || lower.matches(this.filter); } if (notFilter) { return false; } return filter; } /** * 执行下一个函数,出现异常会继续执行 * * @return 是否继续执行 * @throws Exception 异常信息 */ @Override public boolean next() throws Exception { List<String> keys = new ArrayList<>(); keys.addAll(cache.keySet()); for (String key : keys) { Timeout<LogVo> timeout = cache.get(key); if (timeout == null || !timeout.isMaxTime(this.timeout)) { continue; } writeTimeout(timeout); } return true; } /** * 沉睡时间 * * @return */ @Override public int getNextTime() { return 100; } }