servlet解析演进(5)-添加日志

每一个servlet容器都需要去定位问题,那日志肯定是必不可少的。我们平时启动系统的时候发现日志一直在打印一些信息,信息或是来自容器系统中,或是来自我们的应用系统。下面介绍简单的文件日志系统搭建。

日志文件搭建主要包含以下几个部分:

1、日志文件搭建

2、将日志文件配置到容器中。

3、连接器获得容器的logger实例写信息

4、HttpProcessor通过连接器获得容器的logger实例写信息

1、日志文件搭建:

日志文件的接口关系如图:

180754_uEaP_166980.png

public interface Logger {
   /**
     * 详细的日志等级信息常亮
     */
    public static final int FATAL = Integer.MIN_VALUE;
    public static final int ERROR = 1;
    public static final int WARNING = 2;
    public static final int INFORMATION = 3;
    public static final int DEBUG = 4;
//获取容器
    public Container getContainer();
//设置容器
    public void setContainer(Container container);
//获得关于日志实现和对应版本号的详细信息
   public String getInfo();
//返回日志等级,比该等级高的日志信息会被忽略
     public int getVerbosity();
//设置日志的等级信息,比该等级高的日志信息会被忽略
    public void setVerbosity(int verbosity);
//添加该属性变化该组件的属性变化监听
    public void addPropertyChangeListener(PropertyChangeListener listener);
//给servlet日志文件写特殊的信息,通常是一个环境日志。servlet日志的名字和类型对于容器来说是指定的具体的。该种类的信息被无条件的被记录。
    public void log(String message);
//写错误信息给servlet日志文件。该方法的实现最终由log(msg, exception)实现
    public void log(Exception exception, String msg);
//为servlet日志文件写入异常信息和堆栈信息
    public void log(String message, Throwable throwable);
//为servlet日志文件写入特定信息,通常是事件日志,记录日志等级比verbosity设置的高或者相等的信息。
 public void log(String message, int verbosity);
    public void log(String message, Throwable throwable, int verbosity);
//删除属性变更监听器
    public void removePropertyChangeListener(PropertyChangeListener listener);
}
------------------------------
package org.apache.catalina.logger;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import org.apache.catalina.Container;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Logger;
public abstract class LoggerBase
    implements Logger {
   //与日志关联的容器
    protected Container container = null;
//debug等级
    protected int debug = 0;
    //包描述信息
    protected static final String info =
        "org.apache.catalina.logger.LoggerBase/1.0";
//容器的属性变更support实例   
    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
    //日志信息过滤级别,高于该级别的信息被记录下来    
    protected int verbosity = ERROR;
    public Container getContainer() {
        return (container);
    }
//容器设置
    public void setContainer(Container container) {
        Container oldContainer = this.container;
        this.container = container;
        support.firePropertyChange("container", oldContainer, this.container);
    }
//返回容器debugging详细级别。
    
    public int getDebug() {
        return (this.debug);
    }
    public void setDebug(int debug) {
        this.debug = debug;
    }
    public String getInfo() {
        return (info);
    }
    public int getVerbosity() {
        return (this.verbosity);
    }
    public void setVerbosity(int verbosity) {
        this.verbosity = verbosity;
    }
    public void setVerbosityLevel(String verbosity) {
        if ("FATAL".equalsIgnoreCase(verbosity))
            this.verbosity = FATAL;
        else if ("ERROR".equalsIgnoreCase(verbosity))
            this.verbosity = ERROR;
        else if ("WARNING".equalsIgnoreCase(verbosity))
            this.verbosity = WARNING;
        else if ("INFORMATION".equalsIgnoreCase(verbosity))
            this.verbosity = INFORMATION;
        else if ("DEBUG".equalsIgnoreCase(verbosity))
            this.verbosity = DEBUG;
    }
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        support.addPropertyChangeListener(listener);
    }
//抽象方法 具体的日志系统去实现
    public abstract void log(String msg);
    public void log(Exception exception, String msg) {
        log(msg, exception);
    }
//打印出错servlet的堆栈信息
   
    public void log(String msg, Throwable throwable) {
        CharArrayWriter buf = new CharArrayWriter();
        PrintWriter writer = new PrintWriter(buf);
        writer.println(msg);
        throwable.printStackTrace(writer);
        Throwable rootCause = null;
        if (throwable instanceof LifecycleException)
            rootCause = ((LifecycleException) throwable).getThrowable();
        else if (throwable instanceof ServletException)
            rootCause = ((ServletException) throwable).getRootCause();
        if (rootCause != null) {
            writer.println("----- Root Cause -----");
            rootCause.printStackTrace(writer);
        }
        log(buf.toString());
    }
//高于verbosity的信息被写打印出来
    public void log(String message, int verbosity) {
        if (this.verbosity >= verbosity)
            log(message);
    }
//高于verbosity的错误信息被写打印出来
    public void log(String message, Throwable throwable, int verbosity) {
        if (this.verbosity >= verbosity)
            log(message, throwable);
    }
//删除属性变更监听器
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        support.removePropertyChangeListener(listener);
    }
}
文件日志
public class FileLogger
    extends LoggerBase
    implements Lifecycle {
//日期字段
    private String date = "";
    /**
     * 目录字段
     */
    private String directory = "logs";
    /**
     * 文件名称/版本号信息,即该日志实现的详细信息
     */
    protected static final String info =
        "org.apache.catalina.logger.FileLogger/1.0";
    /**
     * 观察者
     */
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
    /**
     * 日志前缀
     */
    private String prefix = "catalina.";
    /**
     * 是否启动flag
     */
    private boolean started = false;
    //日志文件后缀
    private String suffix = ".log";
     //是否有时间戳
     
    private boolean timestamp = false;
 
    private PrintWriter writer = null;
    public void setDirectory(String directory) {
        String oldDirectory = this.directory;
        this.directory = directory;
//如果目录文件有改变触发属性变更监听器
        support.firePropertyChange("directory", oldDirectory, this.directory);
    }
    public void setPrefix(String prefix) {
        String oldPrefix = this.prefix;
        this.prefix = prefix;
        support.firePropertyChange("prefix", oldPrefix, this.prefix);
    }
    public void setSuffix(String suffix) {
        String oldSuffix = this.suffix;
        this.suffix = suffix;
        support.firePropertyChange("suffix", oldSuffix, this.suffix);
    }
    public boolean getTimestamp() {
        return (timestamp);
    }   
    public void setTimestamp(boolean timestamp) {
        boolean oldTimestamp = this.timestamp;
        this.timestamp = timestamp;
        support.firePropertyChange("timestamp", new Boolean(oldTimestamp),
                                   new Boolean(this.timestamp));
    }
    public void log(String msg) {
        // 创建一个时间戳
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        String tsString = ts.toString().substring(0, 19);
        //截取日期信息
        String tsDate = tsString.substring(0, 10);
        // 如果日期和原信息不一致
        if (!date.equals(tsDate)) {
//线程安全的重新生成新的日志文件
            synchronized (this) {
                if (!date.equals(tsDate)) {
                    close();
                    date = tsDate;
                    open();
                }
            }
        }
        // 想日志里面写信息
        if (writer != null) {
//如果设置了时间戳标识,则写时间戳信息+信息
            if (timestamp) {
                writer.println(tsString + " " + msg);
            } else {
//如果没有设置时间戳,则直接写信息
                writer.println(msg);
            }
        }
    }
    private void close() {
//将输出流的信息全部写入文件,并关闭输出流
        if (writer == null)
            return;
        writer.flush();
        writer.close();
        writer = null;
        date = "";
    }
    private void open() {
        // 根据目录信息写文件
        File dir = new File(directory);
//如果dir不是绝对路径
        if (!dir.isAbsolute())
//则获取容器安装目录,再通过directory定位文件绝对位置
            dir = new File(System.getProperty("catalina.base"), directory);
//创建目录
        dir.mkdirs();
        // Open the current log file
        try {
//拼文件名称
            String pathname = dir.getAbsolutePath() + File.separator +
                prefix + date + suffix;
//为文件设置写出流。
            writer = new PrintWriter(new FileWriter(pathname, true), true);
        } catch (IOException e) {
            writer = null;
        }
    }
//增加监听信息
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }
//返回日志系统所有的监听器
    public LifecycleListener[] findLifecycleListeners() {
        return lifecycle.findLifecycleListeners();
    }
//删除某监听器
    public void removeLifecycleListener(LifecycleListener listener) {
        lifecycle.removeLifecycleListener(listener);
    }
 //启动日志系统
    public void start() throws LifecycleException {
        // Validate and update our current component state
        if (started)
            throw new LifecycleException
                (sm.getString("fileLogger.alreadyStarted"));     
   lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;
    }
//关闭日志系统
    public void stop() throws LifecycleException {
        // Validate and update our current component state
        if (!started)
            throw new LifecycleException
                (sm.getString("fileLogger.notStarted"));
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;
        close();
    }
}

2、将日志文件配置到容器中

Context context = new SimpleContext();
FileLogger logger = new FileLogger();
logger.setPrefix("FileLog_");
logger.setSuffix(".txt");
logger.setTimestamp(true);
logger.setDirectory("webroot");
context.setLogger(logger);

3、连接器获得容器的logger实例写信息

private void log(String message) {
    Logger logger = container.getLogger();
    String localName = threadName;
    if (localName == null)
        localName = "HttpConnector";
    if (logger != null)
        logger.log(localName + " " + message);
    else
        System.out.println(localName + " " + message);
}


4、HttpProcessor通过连接器获得容器的logger实例写信息

private void log(String message) {
    Logger logger = connector.getContainer().getLogger();
    if (logger != null)
        logger.log(threadName + " " + message);
}


转载于:https://my.oschina.net/zjItLife/blog/613135

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值