代码之家  ›  专栏  ›  技术社区  ›  Christopher Parker

根据日志级别,使用Facelets、Seam和Logback在错误页上有条件地打印堆栈跟踪

  •  3
  • Christopher Parker  · 技术社区  · 16 年前

    我想打印pages.xml捕获的异常的堆栈跟踪,但我只想在最细粒度日志记录级别比 warn . 这样,测试人员可以复制/粘贴堆栈跟踪,但最终用户永远看不到它。

    环境详细信息:

    以下是目前处理异常的方式。。。

    来自pages.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <pages xmlns="http://jboss.com/products/seam/pages" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
    
        <!-- ... -->
    
        <exception class="javax.faces.application.ViewExpiredException">
            <end-conversation />
            <redirect view-id="/exceptionSessionTimeout.xhtml" />
        </exception>
    
        <!--
             Prevent the Facelets error page from appearing.
             This is where I want to conditionally print the stack trace.
             Currently it's more or less just a generic error page.
        -->
        <exception>
            <end-conversation />
            <redirect view-id="/exception.xhtml" />
        </exception>
    </pages>
    

    从web.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="2.5" 
            xmlns="http://java.sun.com/xml/ns/javaee" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    
        <!-- ... -->
    
        <!-- Fallback static HTML page -->
        <error-page>
            <exception-type>java.lang.Exception</exception-type>
            <location>/unhandledException.html</location>
        </error-page>
    </web-app>
    

    从logback.xml:

    <?xml version="1.0" encoding="UTR-8"?>
    <configuration scan="true">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>[%date] [%thread] [%level] [%mdc] [%logger:%method:%line]: %msg%n</pattern>
            </encoder>
        </appender>
    
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>/path/to/app-logs-dir/AppName.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>/path/to/app-logs-dir/AppName.%d{yyyy-MM-dd-a}.gz</fileNamePattern>
            </rollingPolicy>
            <encoder>
                <pattern>[%date] [%thread] [%level] [%mdc] [%logger:%method:%line]: %msg%n</pattern>
            </encoder>
        </appender>
    
        <logger name="com.example" level="trace" />
        <logger name="com.example.auth" level="error" />
    
        <root level="warn">
            <appender-ref ref="FILE" />
            <appender-ref ref="CONSOLE" />
        </root>
    </configuration>
    

    对于这个问题的理想解决方案,这将导致在/error.xhtml(from pages.xml)上打印堆栈跟踪:

    <logger name="com.example" level="trace" />
    

    鉴于这不会:

    <logger name="com.example" level="warn" />
    

    使用带有Seam的Facelets,有没有办法确定Logback的日志级别?

    1 回复  |  直到 16 年前
        1
  •  2
  •   palacsint    15 年前

    如果没有Seam,则可以使用错误处理程序servlet:

    web.xml :

    <servlet>
        <servlet-name>ErrorHandlerServlet</servlet-name>
        <servlet-class>com.example.ErrorHandlerServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>ErrorHandlerServlet</servlet-name>
        <url-pattern>/ErrorHandlerServlet</url-pattern>
    </servlet-mapping>
    
    <error-page>
        <exception-type>java.lang.Exception</exception-type>
        <location>/ErrorHandlerServlet</location>
    </error-page>
    

    'ErrorHandlerServlet.java':

    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class ErrorHandlerServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
        private static final Logger logger = LoggerFactory
                .getLogger(ErrorHandlerServlet.class);
    
        @Override
        protected void doGet(final HttpServletRequest request,
                final HttpServletResponse response)
                throws ServletException, IOException {
            logger.info("handler");
    
            final Object errorMessage = request
                    .getAttribute(RequestDispatcher.ERROR_MESSAGE);
            final Object throwableObj = request
                    .getAttribute(RequestDispatcher.ERROR_EXCEPTION);
            logger.warn("error message: {}", errorMessage, throwableObj);
    
            final Logger appLogger = LoggerFactory
                    .getLogger("com.example");
            if (!appLogger.isInfoEnabled()) {
                final RequestDispatcher requestDispatcher = 
                        request.getRequestDispatcher("/error.html");
                requestDispatcher.forward(request, response);
                return;
            }
    
            final PrintWriter writer = response.getWriter();
            writer.println("<pre>");
    
            if (throwableObj != null && throwableObj instanceof Throwable) {
                final Throwable throwable = (Throwable) throwableObj;
                throwable.printStackTrace(writer);
            }
            writer.println("</pre>");
        }
    }
    

    无论如何,我认为这不是一个好的实践,很少有人期望更改日志配置会影响应用程序的行为。在生产环境中产生这种副作用可能是有问题的。一个 show-stacktraces web.xml文件 上下文参数可能是更好的方法。