springmvc+logback项目的日志搭建

一、重写HTMLLayout

两个自定义类:LzhHTMLLayoutBaseLzhHTMLLayout

LzhHTMLLayoutBase代码如下:

package top.liaozhenghan.logback.study.layout;

import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.liaozhenghan.util.dateutil.DateStyle;
import com.liaozhenghan.util.dateutil.DateUtil;

import ch.qos.logback.core.Context;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.LayoutBase;
import ch.qos.logback.core.html.CssBuilder;
import ch.qos.logback.core.pattern.Converter;
import ch.qos.logback.core.pattern.ConverterUtil;
import ch.qos.logback.core.pattern.parser.Node;
import ch.qos.logback.core.pattern.parser.Parser;
import ch.qos.logback.core.spi.ScanException;

public abstract class LzhHTMLLayoutBase extends LayoutBase{
    
    protected String pattern;

    protected Converter head;

    protected String title = "Logback Log Messages";

    // It is the responsibility of derived classes to set
    // this variable in their constructor to a default value.
    protected CssBuilder cssBuilder;

    // counter keeping track of the rows output
    protected long counter = 0;

    /**
     * Set the ConversionPattern  option. This is the string which controls
     * formatting and consists of a mix of literal content and conversion
     * specifiers.
     */
    public void setPattern(String conversionPattern) {
        pattern = conversionPattern;
    }

    /**
     * Returns the value of the ConversionPattern  option.
     */
    public String getPattern() {
        return pattern;
    }

    public CssBuilder getCssBuilder() {
        return cssBuilder;
    }

    public void setCssBuilder(CssBuilder cssBuilder) {
        this.cssBuilder = cssBuilder;
    }

    /**
     * Parses the pattern and creates the Converter linked list.
     */
    @Override
    public void start() {
        int errorCount = 0;

        try {
            Parser p = new Parser(pattern);
            p.setContext(getContext());
            Node t = p.parse();
            this.head = p.compile(t, getEffectiveConverterMap());
            ConverterUtil.startConverters(this.head);
        } catch (ScanException ex) {
            addError("Incorrect pattern found", ex);
            errorCount++;
        }

        if (errorCount == 0) {
            super.started = true;
        }
    }

    protected abstract Map getDefaultConverterMap();

    /**
     * Returns a map where the default converter map is merged with the map
     * contained in the context.
     */
    public Map getEffectiveConverterMap() {
        Map effectiveMap = new HashMap();

        // add the least specific map fist
        Map defaultMap = getDefaultConverterMap();
        if (defaultMap != null) {
            effectiveMap.putAll(defaultMap);
        }

        // contextMap is more specific than the default map
        Context context = getContext();
        if (context != null) {
            @SuppressWarnings("unchecked")
            Map contextMap = (Map) context.getObject(CoreConstants.PATTERN_RULE_REGISTRY);
            if (contextMap != null) {
                effectiveMap.putAll(contextMap);
            }
        }
        return effectiveMap;
    }

    /**
     * The Title  option takes a String value. This option sets the
     * document title of the generated HTML document.
     * 
     * 

* Defaults to 'Logback Log Messages'. */ public void setTitle(String title) { this.title = title; } /** * Returns the current value of the Title option. */ public String getTitle() { return title; } /** * Returns the content type output by this layout, i.e "text/html". */ @Override public String getContentType() { return "text/html"; } /** * Returns appropriate HTML headers. */ @Override public String getFileHeader() { StringBuilder sbuf = new StringBuilder(); sbuf.append("); sbuf.append(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); sbuf.append(LINE_SEPARATOR); sbuf.append(""); sbuf.append(LINE_SEPARATOR); sbuf.append(" "); sbuf.append(LINE_SEPARATOR); sbuf.append(" "<span style="color:#000000;">); sbuf.append(title); sbuf.append(</span>""); sbuf.append(LINE_SEPARATOR); cssBuilder.addCss(sbuf); sbuf.append(LINE_SEPARATOR); sbuf.append(" "); sbuf.append(LINE_SEPARATOR); sbuf.append(""); sbuf.append(LINE_SEPARATOR); return sbuf.toString(); } public String getPresentationHeader() { StringBuilder sbuf = new StringBuilder(); sbuf.append("


"); sbuf.append(LINE_SEPARATOR); sbuf.append("

日志启动时间: "); sbuf.append(DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD_HH_MM_SS_CN)); sbuf.append("

"); sbuf.append(LINE_SEPARATOR); sbuf.append(LINE_SEPARATOR); sbuf.append(""); sbuf.append(LINE_SEPARATOR); buildHeaderRowForTable(sbuf); return sbuf.toString(); } privatevoid buildHeaderRowForTable(StringBuilder sbuf) { Converter c = head; String name; sbuf.append(""); sbuf.append(LINE_SEPARATOR); while (c != null) { name = computeConverterName(c); if (name == null) { c = c.getNext(); continue; } sbuf.append(""); sbuf.append(LINE_SEPARATOR); c = c.getNext(); } sbuf.append(""); sbuf.append(LINE_SEPARATOR); } private String filterTableTitleName(String name) { String str = name.toLowerCase(); if ("level".equals(str)) { name = "级别"; } elseif ("date".equals(str)) { name = "执行时间"; } elseif ("callerdata".equals(str)) { name = "所在行"; } elseif ("message".equals(str)) { name = "信息"; } return name; } public String getPresentationFooter() { StringBuilder sbuf = new StringBuilder(); sbuf.append("
); sbuf.append(name); sbuf.append("\">"); sbuf.append(filterTableTitleName(name)); sbuf.append("
"); return sbuf.toString(); } /** * Returns the appropriate HTML footers. */ @Override public String getFileFooter() { StringBuilder sbuf = new StringBuilder(); sbuf.append(LINE_SEPARATOR); sbuf.append(""); return sbuf.toString(); } protected void startNewTableIfLimitReached(StringBuilder sbuf) { if (this.counter >= CoreConstants.TABLE_ROW_LIMIT) { counter = 0; sbuf.append(""); sbuf.append(LINE_SEPARATOR); sbuf.append("

"); sbuf.append(""); sbuf.append(LINE_SEPARATOR); buildHeaderRowForTable(sbuf); } } protected String computeConverterName(Converter c) { String name = null; String className = c.getClass().getSimpleName(); int index = className.indexOf("Converter"); if (index == -1) { name = className; } else { name = className.substring(0, index); } return name; } }View Code

 

LzhHTMLLayout代码如下:

package top.liaozhenghan.logback.study.layout;

import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;

import java.util.Map;

import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.html.DefaultCssBuilder;
import ch.qos.logback.classic.html.DefaultThrowableRenderer;
import ch.qos.logback.classic.pattern.MDCConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.helpers.Transform;
import ch.qos.logback.core.html.IThrowableRenderer;
import ch.qos.logback.core.pattern.Converter;

public class LzhHTMLLayout extends LzhHTMLLayoutBase{

    /**
     * Default pattern string for log output.
     */
    static final String DEFAULT_CONVERSION_PATTERN = "%date{HH:mm:ss}%level%caller{1}%msg";

    IThrowableRenderer throwableRenderer;

    /**
     * Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
     * 
     * The default pattern just produces the application supplied message.
     */
    public LzhHTMLLayout() {
        pattern = DEFAULT_CONVERSION_PATTERN;
        throwableRenderer = new DefaultThrowableRenderer();
        cssBuilder = new DefaultCssBuilder();
    }

    @Override
    public void start() {
        int errorCount = 0;
        if (throwableRenderer == null) {
            addError("ThrowableRender cannot be null.");
            errorCount++;
        }
        if (errorCount == 0) {
            super.start();
        }
    }

    protected Map getDefaultConverterMap() {
        return PatternLayout.defaultConverterMap;
    }

    public String doLayout(ILoggingEvent event) {
        StringBuilder buf = new StringBuilder();
        startNewTableIfLimitReached(buf);

        boolean odd = true;
        if (((counter++) & 1) == 0) {
            odd = false;
        }

        String level = event.getLevel().toString().toLowerCase();

        buf.append(LINE_SEPARATOR);
        buf.append("
); buf.append(level); if (odd) { buf.append(" odd\">"); } else { buf.append(" even\">"); } buf.append(LINE_SEPARATOR); Converter c = head; while (c != null) { appendEventToBuffer(buf, c, event); c = c.getNext(); } buf.append(""); buf.append(LINE_SEPARATOR); if (event.getThrowableProxy() != null) { throwableRenderer.render(buf, event); } return buf.toString(); } privatevoid appendEventToBuffer(StringBuilder buf, Converter c, ILoggingEvent event) { buf.append(""); buf.append(LINE_SEPARATOR); } public IThrowableRenderer getThrowableRenderer() { return throwableRenderer; } publicvoid setThrowableRenderer(IThrowableRenderer throwableRenderer) { this.throwableRenderer = throwableRenderer; } @Override protected String computeConverterName(Converter c) { if (c instanceof MDCConverter) { MDCConverter mc = (MDCConverter) c; String key = mc.getFirstOption(); if (key != null) { return key; } else { return "MDC"; } } else { return super.computeConverterName(c); } } } View Code

 

二、logback.xml配置


xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="3 seconds">
    
    <if condition='p("os.name").contains("Windows")'>
        <then>
            <property name="LOG_PATH" value="c:/logs" />
        then>
    if>
    <if condition='p("os.name").contains("Linux")'>
        <then>
            <property name="LOG_PATH" value="logs" />
        then>
    if>
    <property name="APP_NAME" value="study" />
    <property name="LOG_ROOT_LEVEL" value="debug" />
    <property name="maxHistory" value="30" />
    
    <contextName>${APP_NAME}contextName>

    <appender name="STDOUT"
        class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                
                [%-5level] %d{yyyy-MM-dd HH:mm:ss} [%thread] %logger{36} - %m%n
            pattern>
        encoder>
    appender>

    
    <appender name="FILE_ERROR"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}/ERROR.logfile>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
        encoder>
        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${LOG_PATH}/${APP_NAME}/ERROR.%d.log
            FileNamePattern>
            <MaxHistory>${maxHistory}MaxHistory>
        rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERRORlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>
    
    <appender name="FILE_WARN"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}/WARN.logfile>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
        encoder>
        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${LOG_PATH}/${APP_NAME}/WARN.%d.log
            FileNamePattern>
            <MaxHistory>${maxHistory}MaxHistory>
        rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARNlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>
    
    <appender name="FILE_INFO"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}/INFO.logfile>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
        encoder>
        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${LOG_PATH}/${APP_NAME}/INFO.%d.log
            FileNamePattern>
            <MaxHistory>${maxHistory}MaxHistory>
        rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFOlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>
    
    <appender name="FILE_DEBUG"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}/DEBUG.logfile>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
        encoder>
        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${LOG_PATH}/${APP_NAME}/DEBUG.%d.log
            FileNamePattern>
            <MaxHistory>${maxHistory}MaxHistory>
        rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUGlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    <root level="${LOG_ROOT_LEVEL}">
        
        <appender-ref ref="STDOUT" />
        
        <appender-ref ref="FILE_ERROR" />
        <appender-ref ref="FILE_WARN" />
        <appender-ref ref="FILE_INFO" />
        <appender-ref ref="FILE_DEBUG" />
    root>
configuration>
logback.xml

三、查看日志的jsp页面

用了三个页面:登录页面loglogin.jsp,日志级别选择页面logselect.jsp,日志显示页面log.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
DOCTYPE html>
<html lang="en">
<head>
    <title>日志系统登录title>
    <meta charset="UTF-8">
    
    <meta name="format-detection" content="telephone=no">
    <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="apple-touch-fullscreen" content="yes">
    
head>
<body style="width: 100%;">

    <form action="" method="post">
        <p>密码:p><input name="password"><br>
        <input type="submit" value="登录日志系统">
    form>
body>
html>
loglogin.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
DOCTYPE html>
<html lang="en">
<head>
    <title>日志记录title>
    <meta charset="UTF-8">
    
    <meta name="format-detection" content="telephone=no">
    <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="apple-touch-fullscreen" content="yes">
    <script src="js/jquery.min.js" type="text/javascript">script>
    
    <style type="text/css">
        .lzh_div td{
        }
    style>
    
head>
<body style="width: 100%;">

    <form action="" method="post">
        <input id="date" type="date" name="date">
        <select id="levels" name="level">
            
            <option value="DEBUG">DEBUGoption>
            <option value="INFO">INFOoption>
            <option value="WARN">WARNoption>
            <option value="ERROR">ERRORoption>
        select>
        <input type="submit" value="查看日志">
    form>
    <script type="text/javascript">
        var level = "${level}";
        var date = "${date}";
        $("#levels").val(level);
        $("#date").val(date);
    script>
    <div class="lzh_div" style="width: 100%;">${html}div>
body>
html>
logselect.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
${html}
log.jsp

四、LogController.java

package top.liaozhenghan.logback.study.controller;

import java.io.File;
import java.io.IOException;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.liaozhenghan.util.dateutil.DateStyle;
import com.liaozhenghan.util.dateutil.DateUtil;
import com.liaozhenghan.util.httputil.SrcUtil;

@Controller
public class LogController {
    
    final static Logger LOG = LoggerFactory.getLogger(LogController.class);
    final static String LOG_LOGIN = "LOG_LOGIN";

    @RequestMapping(value="/log")
    public String log(HttpServletRequest request, Model model) {
        
        String date = request.getParameter("date");
        String level = request.getParameter("level");
        String password = request.getParameter("password");
        String html = null;
        
        // 判断是否登录
        Object login = request.getSession().getAttribute(LOG_LOGIN);
        if (login == null) {
            String PASSWORD = "baofa2018";
            
            if (PASSWORD.equals(password)) {
                request.getSession().setAttribute(LOG_LOGIN, LOG_LOGIN);
            } else {
                return "logs/loglogin";
            }
        }
        
        // 1.判断参数是否为空
        if (StringUtils.isEmpty(level) && StringUtils.isEmpty(date)) {
            date = DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD);
            level = "ERROR";
            model.addAttribute("date", date);
            model.addAttribute("level", level);
            return "logs/logselect";
        }
        
        // 2.判断路径
        String filepath = "c:/logs/study/";
        String osName = System.getProperty("os.name");
        if (StringUtils.isEmpty(osName)) {
            html = "系统错误";
            model.addAttribute("date", date);
            model.addAttribute("level", level);
            model.addAttribute("html", html);
            return "logs/logselect";
        } else if (osName.contains("Window")) {
            filepath = "c:/logs/study/";
        } else if (osName.contains("Linux")) {
            filepath = "logs/study/";
        } else {
            html = "未识别的操作系统:" + osName;
            model.addAttribute("date", date);
            model.addAttribute("level", level);
            model.addAttribute("html", html);
            return "logs/logselect";
        }
        
        if (StringUtils.isNotEmpty(date) && !DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD).equals(date)) {
            filepath += level + "." + date + ".log";
        } else {
            filepath += level + ".log";
            date = DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD);
        }
        
        File file = new File(filepath);
        html = "无日志记录";
        if (file.exists()) {
            try {
                html = FileUtils.readFileToString(file, "UTF-8");
            } catch (IOException e) {
                LOG.error(DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD_HH_MM_SS) 
                        + "【文件名】" + filepath, e);
            }
        }
        
        LOG.debug("测试");
        LOG.info("测试");
        LOG.warn("测试");
        LOG.error("测试");
        
        model.addAttribute("html", html);
        model.addAttribute("date", date);
        model.addAttribute("level", level);
        return "logs/log";
    }
}
View Code

 注:logback.xml在tomcat环境下的日志目录可改为:

<property name="LOG_PATH" value="${catalina.base}/logs" />

在java代码中获取文件目录改为:

String catalina_base = System.getProperty("catalina.base");
String filepath = catalina_base + "/logs/study/";

 

转载于:https://www.cnblogs.com/liaozhenghan/p/9642207.html

你可能感兴趣的:(springmvc+logback项目的日志搭建)

); buf.append(computeConverterName(c)); buf.append("\">"); buf.append(Transform.escapeTags(c.convert(event))); buf.append("