asp.net mvc 5.0 환경에서 오류를 실시간으로 모니터링
asp.net mvc 5.0 환경에서 sentry 를 사용하기 위해서는 nuget 에서 아래 목록 3가지를 다운받습니다.
sentry.io/ 사이트를 가입하셔서 key 값을 아래의 SentryDsn 에 할당합니다.
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<!-- Sentry DSN, replace this with your own -->
<add key="SentryDsn" value="https://f648f0653ad64xxxxxxxxx@o467342.ingest.sentry.io/xxxxxxx" />
</appSettings>
global.asax 에서 sentry 를 사용하기 위해서 SentrySdk.Init() 함수를 Application_Start() 함수에 할당하며, 어플리케이션에서 오류가 발생하면 실행되는 Application_Error() 함수에 SentrySdk.CaptureException(exception); 을 사용하여 Exceiption 을 전송합니다.
using System;
using Sentry;
//using Sentry.EntityFramework;
using System.Configuration;
using System.Web.Mvc;
using System.Web.Routing;
namespace AspNetMvc5Ef6
{
public class MvcApplication : System.Web.HttpApplication
{
private IDisposable _sentry;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// We add the query logging here so multiple DbContexts in the same project are supported
//SentryDatabaseLogging.UseBreadcrumbs();
// Set up the sentry SDK
_sentry = SentrySdk.Init(o =>
{
// We store the DSN inside Web.config; make sure to use your own DSN!
o.Dsn = new Dsn(ConfigurationManager.AppSettings["SentryDsn"]);
// Get Entity Framework integration
//o.AddEntityFramework();
});
}
// Global error catcher
protected void Application_Error()
{
var exception = Server.GetLastError();
// Capture unhandled exceptions
SentrySdk.CaptureException(exception);
}
protected void Application_End()
{
// Close the Sentry SDK (flushes queued events to Sentry)
_sentry?.Dispose();
}
}
}
controller 에서 오류가 발생하면 전송하는 방법을 여러가지 제시하는데요. 파라미터가 없어서 오류 발생시키는 ArgumentNullException() 함수 그리고 강제로 오류를 발생시키는 throw new Exception() 함수를 사용하기도 합니다.
if (@params == null)
{
throw new ArgumentNullException(nameof(@params), "Param is null!!!..999");
}
throw new Exception();
사용자가 직접 오류를 기재해서 전송하는 방법도 제공하는데요. model 을 만들어서 아래와 같이 사용하기도 합니다.
catch (Exception e)
{
var ioe = new InvalidOperationException("Bad POST! See Inner exception for details...99.", e);
ioe.Data.Add("inventory",
// The following object gets serialized:
new Extra
{
SmallPotion = 9,
BigPotion = 0,
CheeseWheels = 512
});
throw ioe;
}
전체코드는 아래와 같습니다.
using System;
using System.Web.Mvc;
using AspNetMvc5Ef6.Models;
namespace AspNetMvc5Ef6.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
// Example: An exception that goes unhandled by the app will be captured by Sentry:
[HttpPost]
public ActionResult PostIndex(string @params)
{
try
{
if (@params == null)
{
throw new ArgumentNullException(nameof(@params), "Param is null!!!..999");
}
throw new Exception();
}
catch (Exception e)
{
var ioe = new InvalidOperationException("Bad POST! See Inner exception for details...99.", e);
ioe.Data.Add("inventory",
// The following object gets serialized:
new Extra
{
SmallPotion = 9,
BigPotion = 0,
CheeseWheels = 512
});
throw ioe;
}
}
// Example: An entity validation exception that goes unhandled by the app will be captured by Sentry:
[HttpPost]
public ActionResult ThrowEntityFramework()
{
using (var db = new ApplicationDbContext())
{
var user = new ApplicationUser();
db.Users.Add(user);
// This will throw a DbEntityValidationException
db.SaveChanges();
}
// This never gets called
return View("Index");
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
[Serializable]
public class Extra
{
public int SmallPotion { get; set; }
public int BigPotion { get; set; }
public int CheeseWheels { get; set; }
}
}
}
오류 로그는 issues 메뉴에서 확인이 가능하며, 오류를 그룹핑해서 목록을 보여줍니다.
그룹핑 내부에 오류 이벤트가 9개 발생되어 있는것을 보여주며, 오류 상세 내역을 여기서 볼 수 있습니다. 오류 코드 라인이나 model 로 보낸 데이터 까지 로그내용이 보입니다.
무료 경우는 한달 기준 5천건을 제공하며, 그 이상이 필요하면 유료로 전환하여 사용하셔야 할듯 싶습니다.