问题描述
监控系统
新系统起步,旨在监控原有系统的各种问题。主要的一部分,就是监视原有系统的日志。
日志,是Java
企业级应用开发必不可少的一部分,市场上有诸多日志框架。我们选用slf4j
。
日志有以下级别:
TRACE, DEBUG, INFO, WARN, ERROR
我们期待,当系统运行时打印了WARN
或ERROR
级别的日志时,向我们的服务器推送消息。使得我们可以分析日志,构造更完整的系统。
实现
思考
日志问题与之前的Hibernate
映射问题不同。
Hibernate
映射问题是默认用这个类,然后我们可以利用Spring Boot
为我们提供的配置,当去映射名称的时候调用我这个类。
我们的日志是这么写的:
private static final Logger logger = LoggerFactory.getLogger(xxxx.class);
对象都是从LoggerFactory
那创建出来的,我们根本没办法从配置中下手。
自定义日志
新建日志类YunzhiLogger
,去实现org.slf4j.Logger
接口。
这是Logger
接口的源码,一共有61
个方法,我们一一去实现是不现实的,根据面向对象大法,我们应该去找一个合适的父类去继承,然后重写不符合我们要求的方法。
package org.slf4j;
public interface Logger {
final public String ROOT_LOGGER_NAME = "ROOT";
public String getName();
public boolean isTraceEnabled();
public void trace(String msg);
public void trace(String format, Object arg);
public void trace(String format, Object arg1, Object arg2);
public void trace(String format, Object... arguments);
public void trace(String msg, Throwable t);
public boolean isTraceEnabled(Marker marker);
public void trace(Marker marker, String msg);
public void trace(Marker marker, String format, Object arg);
public void trace(Marker marker, String format, Object arg1, Object arg2);
public void trace(Marker marker, String format, Object... argArray);
public void trace(Marker marker, String msg, Throwable t);
public boolean isDebugEnabled();
public void debug(String msg);
public void debug(String format, Object arg);
public void debug(String format, Object arg1, Object arg2);
public void debug(String format, Object... arguments);
public void debug(String msg, Throwable t);
public boolean isDebugEnabled(Marker marker);
public void debug(Marker marker, String msg);
public void debug(Marker marker, String format, Object arg);
public void debug(Marker marker, String format, Object arg1, Object arg2);
public void debug(Marker marker, String format, Object... arguments);
public void debug(Marker marker, String msg, Throwable t);
public boolean isInfoEnabled();
public void info(String msg);
public void info(String format, Object arg);
public void info(String format, Object arg1, Object arg2);
public void info(String format, Object... arguments);
public void info(String msg, Throwable t);
public boolean isInfoEnabled(Marker marker);
public void info(Marker marker, String msg);
public void info(Marker marker, String format, Object arg);
public void info(Marker marker, String format, Object arg1, Object arg2);
public void info(Marker marker, String format, Object... arguments);
public void info(Marker marker, String msg, Throwable t);
public boolean isWarnEnabled();
public void warn(String msg);
public void warn(String format, Object arg);
public void warn(String format, Object... arguments);
public void warn(String format, Object arg1, Object arg2);
public void warn(String msg, Throwable t);
public boolean isWarnEnabled(Marker marker);
public void warn(Marker marker, String msg);
public void warn(Marker marker, String format, Object arg);
public void warn(Marker marker, String format, Object arg1, Object arg2);
public void warn(Marker marker, String format, Object... arguments);
public void warn(Marker marker, String msg, Throwable t);
public boolean isErrorEnabled();
public void error(String msg);
public void error(String format, Object arg);
public void error(String format, Object arg1, Object arg2);
public void error(String format, Object... arguments);
public void error(String msg, Throwable t);
public boolean isErrorEnabled(Marker marker);
public void error(Marker marker, String msg);
public void error(Marker marker, String format, Object arg);
public void error(Marker marker, String format, Object arg1, Object arg2);
public void error(Marker marker, String format, Object... arguments);
public void error(Marker marker, String msg, Throwable t);
}
找父类
粗略地阅读了一下LoggerFactory
中getLogger
的源代码。
里面有很多的条件,先根据条件获取ILoggerFactory
,该接口一共有三个实现类,实现类中再去定义不同的getLogger
方法,不同的工厂获取出来的日志对象是不同的。
因为对日志框架不是很了解,如果我们随便找一个类继承,那slf4j
的判断就失去意义了,所以此种方法行不通。
装饰器模式
我们想到了装饰器模式。
将一个对象进行装饰,完善其方法。
先将Logger
中的方法都实现掉,然后定义私有变量logger
,定义有参构造函数。
定义logger
用YunzhiLogger
对该日志对象进行装饰。
private static final Logger logger = new YunzhiLogger(LoggerFactory.getLogger(xxxx.class));
借此,也理解了装饰器模式的应用场景。原来就想,装饰器实现的功能用继承不就能实现吗?为什么还要去装饰对象呢?直接继承父类然后调用super
上的方法再加新功能不和这一样吗?
现在也明白了,有时候,我们找不到合适的父类(因为创造出的日志对象是根据不同条件new
不同的类创造出来的),然后我们又想去给这个对象添加方法,没办法,只能修饰对象了。
或者有时候,找到父类,但是父类是final
,没法继承,才用的装饰器模式。
装饰方法
首先,调用原logger
方法进行默认实现。
package com.mengyunzhi.measurement.log;
import org.slf4j.Logger;
import org.slf4j.Marker;
/**
* @author zhangxishuo on 2018/11/15
*/
public class YunzhiLogger implements Logger {
private Logger logger;
public YunzhiLogger(Logger logger) {
this.logger = logger;
}
@Override
public String getName() {
return this.logger.getName();
}
@Override
public boolean isTraceEnabled() {
return this.logger.isTraceEnabled();
}
@Override
public void trace(String msg) {
this.logger.trace(msg);
}
@Override
public void trace(String format, Object arg) {
this.logger.trace(format, arg);
}
@Override
public void trace(String format, Object arg1, Object arg2) {
this.logger.trace(format, arg1, arg2);
}
@Override
public void trace(String format, Object... arguments) {
this.logger.trace(format, arguments);
}
@Override
public void trace(String msg, Throwable t) {
this.logger.trace(msg, t);
}
@Override
public boolean isTraceEnabled(Marker marker) {
return this.logger.isTraceEnabled(marker);
}
@Override
public void trace(Marker marker, String msg) {
this.logger.trace(marker, msg);
}
@Override
public void trace(Marker marker, String format, Object arg) {
this.logger.trace(marker, format, arg);
}
@Override
public void trace(Marker marker, String format, Object arg1, Object arg2) {
this.logger.trace(marker, format, arg1, arg2);
}
@Override
public void trace(Marker marker, String format, Object... argArray) {
this.logger.trace(marker, format, argArray);
}
@Override
public void trace(Marker marker, String msg, Throwable t) {
this.logger.trace(marker, msg, t);
}
@Override
public boolean isDebugEnabled() {
return this.logger.isDebugEnabled();
}
@Override
public void debug(String msg) {
this.logger.debug(msg);
}
@Override
public void debug(String format, Object arg) {
this.logger.debug(format, arg);
}
@Override
public void debug(String format, Object arg1, Object arg2) {
this.logger.debug(format, arg1, arg2);
}
@Override
public void debug(String format, Object... arguments) {
this.logger.debug(format, arguments);
}
@Override
public void debug(String msg, Throwable t) {
this.logger.debug(msg, t);
}
@Override
public boolean isDebugEnabled(Marker marker) {
return this.logger.isDebugEnabled(marker);
}
@Override
public void debug(Marker marker, String msg) {
this.logger.debug(marker, msg);
}
@Override
public void debug(Marker marker, String format, Object arg) {
this.logger.debug(marker, format, arg);
}
@Override
public void debug(Marker marker, String format, Object arg1, Object arg2) {
this.logger.debug(marker, format, arg1, arg2);
}
@Override
public void debug(Marker marker, String format, Object... arguments) {
this.logger.debug(marker, format, arguments);
}
@Override
public void debug(Marker marker, String msg, Throwable t) {
this.logger.debug(marker, msg, t);
}
@Override
public boolean isInfoEnabled() {
return this.logger.isInfoEnabled();
}
@Override
public void info(String msg) {
this.logger.info(msg);
}
@Override
public void info(String format, Object arg) {
this.logger.info(format, arg);
}
@Override
public void info(String format, Object arg1, Object arg2) {
this.logger.info(format, arg1, arg2);
}
@Override
public void info(String format, Object... arguments) {
this.logger.info(format, arguments);
}
@Override
public void info(String msg, Throwable t) {
this.logger.info(msg, t);
}
@Override
public boolean isInfoEnabled(Marker marker) {
return this.logger.isInfoEnabled(marker);
}
@Override
public void info(Marker marker, String msg) {
this.logger.info(marker, msg);
}
@Override
public void info(Marker marker, String format, Object arg) {
this.logger.info(marker, format, arg);
}
@Override
public void info(Marker marker, String format, Object arg1, Object arg2) {
this.logger.info(marker, format, arg1, arg2);
}
@Override
public void info(Marker marker, String format, Object... arguments) {
this.logger.info(marker, format, arguments);
}
@Override
public void info(Marker marker, String msg, Throwable t) {
this.logger.info(marker, msg, t);
}
@Override
public boolean isWarnEnabled() {
return this.logger.isWarnEnabled();
}
@Override
public void warn(String msg) {
this.logger.warn(msg);
}
@Override
public void warn(String format, Object arg) {
this.logger.warn(format, arg);
}
@Override
public void warn(String format, Object... arguments) {
this.logger.warn(format, arguments);
}
@Override
public void warn(String format, Object arg1, Object arg2) {
this.logger.warn(format, arg1, arg2);
}
@Override
public void warn(String msg, Throwable t) {
this.logger.warn(msg, t);
}
@Override
public boolean isWarnEnabled(Marker marker) {
return this.logger.isWarnEnabled(marker);
}
@Override
public void warn(Marker marker, String msg) {
this.logger.warn(marker, msg);
}
@Override
public void warn(Marker marker, String format, Object arg) {
this.logger.warn(marker, format, arg);
}
@Override
public void warn(Marker marker, String format, Object arg1, Object arg2) {
this.logger.warn(marker, format, arg1, arg2);
}
@Override
public void warn(Marker marker, String format, Object... arguments) {
this.logger.warn(marker, format, arguments);
}
@Override
public void warn(Marker marker, String msg, Throwable t) {
this.logger.warn(marker, msg, t);
}
@Override
public boolean isErrorEnabled() {
return this.logger.isErrorEnabled();
}
@Override
public void error(String msg) {
this.logger.error(msg);
}
@Override
public void error(String format, Object arg) {
this.logger.error(format, arg);
}
@Override
public void error(String format, Object arg1, Object arg2) {
this.logger.error(format, arg1, arg2);
}
@Override
public void error(String format, Object... arguments) {
this.logger.error(format, arguments);
}
@Override
public void error(String msg, Throwable t) {
this.logger.error(msg, t);
}
@Override
public boolean isErrorEnabled(Marker marker) {
return this.logger.isErrorEnabled(marker);
}
@Override
public void error(Marker marker, String msg) {
this.logger.error(marker, msg);
}
@Override
public void error(Marker marker, String format, Object arg) {
this.logger.error(marker, format, arg);
}
@Override
public void error(Marker marker, String format, Object arg1, Object arg2) {
this.logger.error(marker, format, arg1, arg2);
}
@Override
public void error(Marker marker, String format, Object... arguments) {
this.logger.error(marker, format, arguments);
}
@Override
public void error(Marker marker, String msg, Throwable t) {
this.logger.error(marker, msg, t);
}
}
这是我为装饰器添加的默认实现,如有错误,欢迎批评指正。
然后就可以在相应的方法中添加我们的逻辑,如在error
的方法中向我们的日志监控服务推送消息。
总结
- 通过对
slf4j
源码的学习大致学习了日志框架slf4j
的运行原理。 - 通过找接口与父类理解了装饰器模式的应用场景。
- 本文只是实现了基本的功能,因为
error
方法与warn
方法有很多重载的方法,所以我们期待可以实现对该日志类中所有名为error
与warn
的方法进行切面处理。