XXL-Job调用说明相关, 将log日志同步输出到XXL-JOB调度日志中

 

https://blog.csdn.net/zack_GZ/article/details/124974986

 

 

通常我们需要将日志打印到xxl-job的调度日志中时,会使用xxl-job提供的接口 XxlJobLogger.log("message xxxxxxxxxx")

但是这种方式不会将日志打印到spring应用输出的日志中,这就会导致程序出现缺陷时我们需要结合xxl-job后台的调度日志和spring的log日志,两边对照排查问题。

还有一种情况就是调度平台的模块a依赖xxl-job,可以正常使用

XxlJobLogger.log("message xxxxxxxxxx")

接口输出日志。但是如果另一个业务模块b被a依赖,而b没有导入xxl-job依赖,就会导致模块b无法使用接口XxlJobLogger.log输出日志。

 

 

依赖关系
模块a中打印日志时可以同时使用sl4j和XxlJobLogger,模块b中只能使用sl4j,导致模块b中的日志信息无法记录到xxl-job调度平台中。

为了集中管理日志信息,统一日志输出信息,希望一个接口就能同时将日志信息记录到spring的log文件中以及xxl-job的调度日志中。

解决方案:sl4j + cglib代理

因为原有业务模块(例如模块b)都是使用sl4j日志框架,沿用该框架对原有代码改动最小,只需要覆盖类里面原有的log对象。

再者就是如果有一个模块c调用模块b,则不需要将日志信息记录到xxl-job中,所以只需要模块a调用模块b时开启cglib代理即可。

实现方式:

使用cglib创建Logger代理类,代理info、debug、error方法,在方法拦截中判断参数模式并输出。

在方法拦截中获取到常规的logger对象并输出日志到spring的log日志中,再通过XxlJobLogger输出到xxl-job中。这一步是在模块a(依赖了xxl-job)中做的,所以可以使用xxl-job的日志接口。

使用createLogger方法创建log代理对象: 

public class LoggerEnhancer {
 
    private static final Map<Class<?>, Logger> LOGGER_CACHE = new HashMap<>();
 
    private final static List<String> ENHANCE_METHOD_LIST = Arrays.asList("info", "debug", "error");
 
    private static Logger getLogger(Class<?> clazz) {
        if (LOGGER_CACHE.containsKey(clazz)) {
            return LOGGER_CACHE.get(clazz);
        }
        Logger logger = LoggerFactory.getLogger(clazz);
        LOGGER_CACHE.put(clazz, logger);
        return logger;
    }
 
    public static Logger createLogger(Class<?> clazz) {
        Object proxy = Enhancer.create(Logger.class, new LoggerMethodInterceptor(clazz));
        return (Logger) proxy;
    }
 
    public static class LoggerMethodInterceptor implements MethodInterceptor{
 
        private final Class<?> clazz;
 
        public LoggerMethodInterceptor(Class<?> clazz) {
            this.clazz = clazz;
        }
 
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            if (ENHANCE_METHOD_LIST.contains(method.getName()) && objects != null && objects.length  > 0) {
                Object[] args = new Object[0];
                if (objects.length > 1) {
 
                    // 超过3个参数时 logger 通过不定参数形式重载
                    if (method.getParameterCount() == 2 && method.getParameters()[1].getType().isArray()) {
                        args = (Object[]) objects[1];
                    }else {
                        args = new Object[objects.length - 1];
                        System.arraycopy(objects, 1, args, 0, args.length);
                    }
                }
                String temp = (String) objects[0];
                log(method.getName(), temp, args);
            }
            return null;
 
        }
 
        public void log(String methodName, String str, Object... args) {
            Logger logger = getLogger(clazz);
            switch (methodName) {
                case "log":
                    logger.info(str, args);
                    XxlJobLogger.log(str, args);
                    break;
                case "debug":
                    logger.debug(str, args);
                    XxlJobLogger.log(str, args);
                    break;
                case "error":
                    logger.error(str, args);
                    logError(str, args);
                    break;
                default:
                    logger.info(str, args);
                    XxlJobLogger.log(str, args);
            }
        }
 
        public static void logError(String str, Object... args) {
            for (Object arg : args) {
                if (arg instanceof Throwable) {
                    XxlJobLogger.log((Throwable)arg);
                    return;
                }
            }
            XxlJobLogger.log(str, args);
        }
    }
}

在xxl-job的调度入口JobHandler实现中将创建的log代理对象传入其他模块中,覆盖原有的log对象:

public class DemoHandler extends IJobHandler {
 
    @Autowired
    private LogTestService logTestService;
 
    private static final Logger log = LoggerEnhancer.createLogger(DemoHandler.class);
 
    @Override
    public ReturnT<String> execute(String param) throws Exception {
        // 创建LogTestService的代理logger并覆盖原有logger对象
        LogTestService.setLog(LoggerEnhancer.createLogger(LogTestService.class));
        
        Date date = new Date();
        log.info("现在时间是:{}", date);
        XxlJobLogger.log("这行日志不会打印到控制台,但是会打印到XXL-JOB后台调度日志中");
 
        logTestService.logMessage();
        return ReturnT.SUCCESS;
    }
}

LogTestService:

@Service
public class LogTestService {
    private static Logger log = LoggerFactory.getLogger(LogTestService.class);
 
    public static void setLog(Logger log){
        LogTestService.log = log;
    }
 
    public void logMessage(){
        log.info("LogTestService : 输出一些日志信息");
    }
}

 

通过xxl-job调度执行demoHandler效果:

xxl-job调度日志:

 

 

 

posted @ 2023-01-13 16:38  kelelipeng  阅读(8415)  评论(0)    收藏  举报