一、重写HTMLLayout
两个自定义类:LzhHTMLLayoutBase和LzhHTMLLayout
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 LzhHTMLLayoutBaseextends 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(""); sbuf.append(title); sbuf.append(" "); 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(); } private void buildHeaderRowForTable(StringBuilder sbuf) { Converter c = head; String 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); while (c != null) { name = computeConverterName(c); if (name == null) { c = c.getNext(); continue; } sbuf.append(" "); sbuf.append(LINE_SEPARATOR); } private String filterTableTitleName(String name) { String str = name.toLowerCase(); if ("level".equals(str)) { name = "级别"; } else if ("date".equals(str)) { name = "执行时间"; } else if ("callerdata".equals(str)) { name = "所在行"; } else if ("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(" "); sbuf.append(LINE_SEPARATOR); c = c.getNext(); } 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代码如下:
View Codepackage 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 "); buf.append(LINE_SEPARATOR); if (event.getThrowableProxy() != null) { throwableRenderer.render(buf, event); } return buf.toString(); } private void appendEventToBuffer(StringBuilder buf, Converterc = head; while (c != null) { appendEventToBuffer(buf, c, event); c = c.getNext(); } buf.append(" c, ILoggingEvent event) { buf.append(" ); buf.append(computeConverterName(c)); buf.append("\">"); buf.append(Transform.escapeTags(c.convert(event))); buf.append(" "); buf.append(LINE_SEPARATOR); } public IThrowableRenderer getThrowableRenderer() { return throwableRenderer; } public void setThrowableRenderer(IThrowableRendererthrowableRenderer) { 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); } } }
二、logback.xml配置
logback.xmlxml 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>三、查看日志的jsp页面
用了三个页面:登录页面loglogin.jsp,日志级别选择页面logselect.jsp,日志显示页面log.jsp
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"> head> <body style="width: 100%;"> <form action="" method="post"> <p>密码:p><input name="password"><br> <input type="submit" value="登录日志系统"> form> 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+"/"; %> 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>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+"/"; %> ${html}四、LogController.java
View Codepackage 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"; } }注: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项目的日志搭建)