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

发布于 2024-09-07 15:33:48 字数 3926 浏览 5 评论 0原文

我想打印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>

来自网络。 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 上(来自pages.xml):

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

而这不会:

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

Using Facelets with Seam,有办法吗确定Logback的日志级别?

I would like to print the stack trace for the exception that was caught by pages.xml, but I only want to do so if the most granular logging level is more granular than warn. This way, testers can copy/paste the stack trace, but end users will never see it.

Environment details:

Here's how exceptions are currently being handled...

From 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>

From 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>

From 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>

With the ideal solution to this problem, this would cause a stack trace to be printed on /error.xhtml (from pages.xml):

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

Whereas this would not:

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

Using Facelets with Seam, is there a way to determine Logback's log levels?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼藏柔 2024-09-14 15:33:48

如果没有 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 上下文参数可能是更好的方法。

Without Seam it's possible with an error handler 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>");
    }
}

Anyway, I don't think this would be a good practice, very few people expect that changing the logging configuration influence the behaviour of the application. It could be problematic to have this kind of side effects in a production environment. A show-stacktraces web.xml context parameter maybe a better approach.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文