环境我正在运行许多使用Servlet的应用程序,包括基于JSF和JAX-WS的应用程序以及一些自己的自定义Servlet。我正在使用Tomcat 7.x作为我的Web容器。我正在使用java.util.logging记录消息。现在的情况对于记录异常,我一直在使用SMTPHandler,它表现很好。以下是我的logging.properties文件的相关摘录:handlers = {... other handlers ...},08SMTP.smtphandler.SMTPHandler08SMTP.smtphandler.SMTPHandler.level=SEVERE08SMTP.smtphandler.SMTPHandler.smtpHost=smtp.somedomain.com08SMTP.smtphandler.SMTPHandler.to=developers@somedomain.com08SMTP.smtphandler.SMTPHandler.from=developers@somedomain.com08SMTP.smtphandler.SMTPHandler.subject=MyApplication error message08SMTP.smtphandler.SMTPHandler.bufferSize=51208SMTP.smtphandler.SMTPHandler.formatter=java.util.logging.SimpleFormatter此设置的唯一问题是电子邮件仅包含一个例外。没有关于错误发生的上下文的其他信息。我想看到的我希望电子邮件包含ServletRequest / HttpServletRequest对象的其他上下文信息,例如:谁是登录用户?请求的queryString,URL,URI,ContextPath,ServletPath和getMethod是什么?标头参数是什么?参数是什么?属性名称/值是什么?尝试的解决方案由Handler文件配置的记录logging.properties不能访问应用程序的其他部分,除非通过静态变量访问,所以我想我将尝试以编程方式创建记录Handler。我尝试过创建一个处理程序,但是没有办法让它了解异常发生时处于活动状态的HttpServletRequest。我试图创建自己的类,该类同时实现ServletRequestListener和ServletContextListener,然后注册一个了解Handler变量的自定义日志记录ThreadLocal<ServletRequest>,然后在。在正确地调用ThreadLocal和ServletRequestListener的<listener>文件中添加了web.xml引用之后,在发生异常时永远不会调用日志记录处理程序的contextInitialized方法。代码在这里。public class LoggingWebListener implements ServletRequestListener, ServletContextListener{ public static class FtSmtpHandler extends Handler { private final ServletContext sc; private final ThreadLocal<ServletRequest> servletReqLocal; public FtSmtpHandler(ServletContext servletContext, ThreadLocal<ServletRequest> servletReqLocal) { this.sc = servletContext; this.servletReqLocal = servletReqLocal; } @Override public void publish(LogRecord record) { if (record.getLevel().intValue() < Level.WARNING.intValue()) return; // Don't try to send email if the emailer fails and logs an exception if (record.getLoggerName().equals(MyEmailHelper.class.getName())) return; // CODE TO SEND EMAIL GOES HERE } @Override public void flush() { } @Override public void close() throws SecurityException { } } public static final Logger glogger = Logger.getGlobal(); public static final Logger logger = Logger.getLogger(LoggingWebListener.class.getName()); private final ThreadLocal<ServletRequest> servletReqLocal = new ThreadLocal<>(); private FtSmtpHandler handler; public LoggingWebListener() { } @Override public void contextInitialized(ServletContextEvent evt) { logger.log(Level.INFO, "Initializing context for " + getClass().getName()); ServletContext servletContext = evt.getServletContext(); handler = new FtSmtpHandler(servletContext, servletReqLocal); glogger.addHandler(handler); } @Override public void contextDestroyed(ServletContextEvent arg0) { glogger.removeHandler(handler); handler = null; } @Override public void requestInitialized(ServletRequestEvent evt) { ServletRequest servletRequest = evt.getServletRequest(); // logger.log(Level.INFO, "Initializing request for request " + servletRequest); servletReqLocal.set(servletRequest); } @Override public void requestDestroyed(ServletRequestEvent evt) { servletReqLocal.remove(); }}我的工作有小错误吗?这是完全错误的方法吗?是否有一个已经存在的模块可以执行我尚未找到的所需功能?还有另一种方法可以做我想做的事吗?This post提出了一种与我所采取的方法类似的方法,但是没有细节。 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 创建一个自定义servlet过滤器,该过滤器将为应用程序的所有调用触发。然后创建一个自定义格式化程序,该格式化程序知道如何格式化请求的属性。在过滤器内部,捕获当前请求,并将其发送到安装在SMTPHandler上的自定义格式化程序,以获取对请求对象的访问权限。 public class RequestContextFilter implements javax.servlet.Filter { private static final String CLASS_NAME = MdcFilter.class.getName(); private static final Logger logger = Logger.getLogger(""); private volatile Handler emailer; @Override public void init(FilterConfig filterConfig) throws ServletException { emailer = new SMTPHandler(); //etc... emailer.setFormatter(new ContextFormatter()); logger.addHandler(emailer); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ContextFormatter.CTX.set(request); try { chain.doFilter(request, response); } finally { ContextFormatter.CTX.remove(); } } @Override public void destroy() { logger.removeHandler(emailer); emailer.close(); } private static class ContextFormatter extends Formatter { static final ThreadLocal<ServletRequest> CTX = new ThreadLocal(); private final Formatter txt = new SimpleFormatter(); @Override public String format(LogRecord record) { HttpServletRequest req = (HttpServletRequest) CTX.get(); return req.getRequestURI() + " " + txt.format(record); } } }由于这使用的是本地线程,因此如果记录器和过滤器之间存在线程切换,则将无法使用。 (adsbygoogle = window.adsbygoogle || []).push({}); 08-03 12:30