環境通過電子郵件
我跑了許多使用Servlet的,包括基於JSF和JAX-WS和我自己的一些定製的Servlet的那些應用程序登錄的servlet異常時需要更多信息。我使用Tomcat 7.x作爲我的Web容器。我使用java.util.logging來記錄消息。
現狀
用於記錄異常,我一直在使用SMTPHandler已經工作得很好。以下是我的logging.properties文件的相關摘錄:
handlers = {... other handlers ...},08SMTP.smtphandler.SMTPHandler
08SMTP.smtphandler.SMTPHandler.level=SEVERE
08SMTP.smtphandler.SMTPHandler.smtpHost=smtp.somedomain.com
[email protected]
[email protected]
08SMTP.smtphandler.SMTPHandler.subject=MyApplication error message
08SMTP.smtphandler.SMTPHandler.bufferSize=512
08SMTP.smtphandler.SMTPHandler.formatter=java.util.logging.SimpleFormatter
此設置的唯一問題是電子郵件只包含一個例外。沒有關於發生錯誤的上下文的其他信息。
我想看到的
我想的電子郵件包含從ServletRequest
/HttpServletRequest
對象的其它背景信息,如:
- 誰是登錄的用戶在?
- 什麼是請求的queryString,URL,URI,ContextPath,ServletPath和getMethod?
- 什麼是標題參數?
- 參數是什麼?
- 什麼是屬性名稱/值?
的嘗試性解決方案
記錄Handler
s數logging.properties
文件配置沒有訪問除通過靜態變量的應用程序的其他部分,所以我想我會嘗試創建一個記錄Handler
以編程方式。我試圖製作一個處理程序,但是沒有辦法讓它知道在異常時處於活動狀態的HttpServletRequest
。
我試圖創建自己的類,同時實現了ServletRequestListener
和ServletContextListener
,然後註冊一個自定義日誌Handler
它知道一個ThreadLocal<ServletRequest>
變量,然後設置並在ServletRequestListener
明確表示ThreadLocal
變量。在我web.xml
文件,該文件正確調用contextInitialized
和requestInitialized
,我的日誌Handler的publish
方法添加<listener>
引用後,當發生異常不會被調用。
這裏的代碼就在這裏。
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建議了一種類似於我所採取的方法,但沒有詳細信息。
下面是一個工作示例!事實證明,無論是我原來的ServletRequestListener,ServletContextListener方法還是您的servlet Filter方法都可以工作。你的例子有2個關鍵的改進,我的嘗試失敗了:1.使用Logger.getLogger(「」)而不是Logger.getGlobal(); 2.一定要在'Handler'上設置'Formatter'(我試圖使用它在「//代碼發送電子郵件到這裏」部分)!你爲子類化一個新的'Formatter'的方法也是一種優越的方法,我將利用它。周圍的好東西,我學到了很多,非常感謝! – Pixelstix