package com.yanzuoguang.log; import com.yanzuoguang.util.cache.MemoryCache; import com.yanzuoguang.util.helper.StringHelper; import com.yanzuoguang.util.thread.ThreadNext; import com.yanzuoguang.util.vo.CloudConfig; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * 当前线程日志编写 * * @author 颜佐光 */ @Component public class LogLocal implements ThreadNext.Next, InitializingBean { /** * 一个请求最多保留60分钟 */ public static final int CLEAR_CACHE = 60 * 60; /** * 超时状态 */ public static final String MAX_TIME = "MAX_TIME"; public static final String MAX_TIME_NAME = "执行超时"; /** * 日志基础 */ private final LogBase logBase; private final CloudConfig cloudConfig; private final List<LogFilter> logFilters; private final LogCountTime logCountTime; /** * 缓存队列 */ protected volatile MemoryCache<Timeout<LogInfoVo>> cache = new MemoryCache<>(CLEAR_CACHE); public LogLocal(LogBase logBase, CloudConfig cloudConfig, List<LogFilter> logFilters, LogCountTime logCountTime) { this.logBase = logBase; this.cloudConfig = cloudConfig; this.logFilters = logFilters; this.logCountTime = logCountTime; } @Override public void afterPropertiesSet() { ThreadNext.start(this, "save log error"); } /** * 开始记录日志 * * @param log 日志对象 */ public void startLog(LogInfoVo log) { // 声明超时对象 Timeout<LogInfoVo> time = new Timeout<>(log); cache.put(log.getLogId(), time); } /** * 写入状态 * * @param log 日志对象 */ public void result(LogInfoVo log) { if (log == null) { return; } // 日志请求不记录,防止死循环递归 boolean isLog = isLog(log.getTag(), log.getUrl()); this.resultWrite(log); String fullUrl = String.format("%s:%s", tag, url); logCountTime.start(fullUrl); // 全路径 String fullUrl = String.format("%s:%s", tag, url); // 执行时间 long time = System.currentTimeMillis() - log.getStart(); // 记录请求时间 logCountTime.finish(fullUrl, time, isError); if (log == null || StringHelper.isEmpty(log.getLogId())) { return; } Timeout<LogInfoVo> timeout; // 判断是否延时结果 boolean isMaxTime = StringHelper.compare(status, MAX_TIME); if (isMaxTime) { timeout = cache.get(log.getLogId()); } else { timeout = cache.remove(log.getLogId()); } if (write) { logBase.addLog(log); } } /** * 是否属于日志服务 * * @param keys 是否需要写入 * @return 是否属于日志服务 */ public boolean isLog(String... keys) { List<String> list = new ArrayList<>(); list.add(this.cloudConfig.getApplicationName()); list.addAll(Arrays.asList(keys)); for (LogFilter k : logFilters) { if (k.logExpect(list)) { return true; } } for (LogFilter k : logFilters) { if (k.logFilter(list)) { return false; } } return true; } /** * 执行下一个函数,出现异常会继续执行 * * @return 是否继续执行 */ @Override public boolean next() { Collection<Timeout<LogInfoVo>> values = cache.getValues(); for (Timeout<LogInfoVo> timeout : values) { if (timeout == null) { continue; } // 判断是否达到超时时间 if (timeout.isMaxTime(this.cloudConfig.getLogTimeMax(), this.cloudConfig.getLogTimeSplit())) { this.result(timeout.getData()); } } return true; } /** * 沉睡时间 * * @return 下次执行时间 */ @Override public int getNextTime() { return 1000; } }