現在、ASP.NET MVCアプリケーションでlog4netを使用して例外をログに記録しています。これを行う方法は、すべてのコントローラーにBaseControllerクラスを継承させることです。 BaseControllerのOnActionExecutingイベントで、発生した可能性のある例外をログに記録します。
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Log any exceptions
ILog log = LogManager.GetLogger(filterContext.Controller.GetType());
if (filterContext.Exception != null)
{
log.Error("Unhandled exception: " + filterContext.Exception.Message +
". Stack trace: " + filterContext.Exception.StackTrace,
filterContext.Exception);
}
}
これは、コントローラーのアクション中に未処理の例外が発生した場合に役立ちます。
404エラーについては、次のようにweb.configでカスタムエラーを設定しています。
<customErrors mode="On">
<error statusCode="404" redirect="~/page-not-found"/>
</customErrors>
そして、「page-not-found」URLを処理するコントローラーアクションで、要求されている元のURLを記録します。
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult PageNotFound()
{
log.Warn("404 page not found - " + Utils.SafeString(Request.QueryString["aspxerrorpath"]));
return View();
}
そして、これも機能します。
私が抱えている問題は、.aspxページ自体にあるエラーをログに記録する方法です。例外をスローするページの1つまたはいくつかのインラインコードでコンパイルエラーがあるとします。
<% ThisIsNotAValidFunction(); %>
<% throw new Exception("help!"); %>
HandleError属性は、これをSharedフォルダー内のError.aspxページに正しく再ルーティングしているように見えますが、BaseControllerのOnActionExecutedメソッドによって確実にキャッチされていません。 Error.aspxページ自体にロギングコードを置くことができると考えていましたが、そのレベルでエラー情報を取得する方法がわかりません。
Elmah をプラグインして、Webアプリケーションを簡素化することを検討します。
Elmahアセンブリをプロジェクトに追加してから、web.configを構成します。次に、コントローラーまたはページレベルで作成された例外をログに記録します。さまざまな場所(SQL Server、電子メールなど)にログを記録するように構成できます。また、Webフロントエンドも提供するため、例外のログを参照できます。
私が作成したasp.net mvcアプリに最初に追加するものです。
私は今でもlog4netを使用していますが、デバッグ/情報のロギングに使用する傾向があり、すべての例外はElmahに任せています。
また、質問 ASP.NETアプリでエラー(例外)をログに記録する方法は? で詳細を確認することもできます。
Global.asaxのOnErrorイベントにフックできます。
このようなもの:
/// <summary>
/// Handles the Error event of the Application control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Application_Error(object sender, EventArgs e)
{
if (Server != null)
{
Exception ex = Server.GetLastError();
if (Response.StatusCode != 404 )
{
Logging.Error("Caught in Global.asax", ex);
}
}
}
MVC3
HandleErrorInfoAttributeを継承し、ロギングの選択を含む属性を作成します
public class ErrorLoggerAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
LogError(filterContext);
base.OnException(filterContext);
}
public void LogError(ExceptionContext filterContext)
{
// You could use any logging approach here
StringBuilder builder = new StringBuilder();
builder
.AppendLine("----------")
.AppendLine(DateTime.Now.ToString())
.AppendFormat("Source:\t{0}", filterContext.Exception.Source)
.AppendLine()
.AppendFormat("Target:\t{0}", filterContext.Exception.TargetSite)
.AppendLine()
.AppendFormat("Type:\t{0}", filterContext.Exception.GetType().Name)
.AppendLine()
.AppendFormat("Message:\t{0}", filterContext.Exception.Message)
.AppendLine()
.AppendFormat("Stack:\t{0}", filterContext.Exception.StackTrace)
.AppendLine();
string filePath = filterContext.HttpContext.Server.MapPath("~/App_Data/Error.log");
using(StreamWriter writer = File.AppendText(filePath))
{
writer.Write(builder.ToString());
writer.Flush();
}
}
Global.asax RegisterGlobalFiltersに属性を配置する
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// filters.Add(new HandleErrorAttribute());
filters.Add(new ErrorLoggerAttribute());
}
HandleError属性を拡張することを考えましたか?また、Scottには、コントローラー/アクションのフィルターインターセプターに関する良いブログ投稿があります here 。
Error.aspxビューは次のように定義されます。
namespace MvcApplication1.Views.Shared
{
public partial class Error : ViewPage<HandleErrorInfo>
{
}
}
HandleErrorInfoには次の3つのプロパティがあります。string ActionName string ControllerName Exception Exception
HandleErrorInfoにアクセスできるため、ビュー内の例外にアクセスできます。
HttpContext.Errorを調べることができますが、これについてはわかりません。