在ap.net Web项目中一直使用Elmah进行日志记录,
但一直有一个问题困扰我很久,那就是我如何自己生成一个错误并记录到Elmah里去。
你知道有时你需要在项目中生成一个错误用于一些特殊的需求
最开始之前我是这样处理的。
使用Sql语句自定义错误信息添加到Elmah的Sqlite数据库中,但这样做有一个问题,
如果Elmah更改存储方式非Sqlite(如Xml,txt,Mysql等)那么下面的方式就无效啦(错误信息无法在Elmah中显示)
public class CustomErrorSqlite{ static string UrlDecodeUtf( string _val) { return HttpUtility .UrlDecode(_val, System.Text. Encoding .UTF8); } static string StrDecode(string str) { return UrlDecodeUtf(str).Replace("&", "&").Replace("<br />", " ").Replace("<br>", " ").Replace("<", "<").Replace(">", ">").Replace(""", """).Replace("'", "'").Replace(")", ")").Replace("(", "(").Replace("{", "{").Replace("}", "}").Replace("/", "/"); } static string GetServerVariables { get { StringBuilder sb = new StringBuilder("<serverVariables>"); foreach (string str in HttpContext.Current.Request.ServerVariables) { sb.Append(string.Format("<item name='{0}'><value string='{1}'/></item>", str, StrDecode(HttpContext.Current.Request.ServerVariables[str]))); } sb.Append("</serverVariables>"); return sb.ToString(); } } /// <summary> /// 错误信息,错误地址,错误详细信息 /// AllXml列需要将@#等特殊字符进行处理,否则在查看Elmah详情时会出现 /// </summary> /// <param name="message">错误信息</param> /// <param name="source">错误来源</param> /// <param name="detailmessage">详细的错误信息</param> public static void AddLog(string message, string source, string detailmessage) { detailmessage = StrDecode(UrlDecodeUtf(detailmessage)); message = StrDecode(UrlDecodeUtf(message)); source = StrDecode(UrlDecodeUtf(source)); //使用Elmah的Sqlite数据库 //如果在配置文件中更改sqlite数据库位置或更改为其他存储方式 //下面的处理方式无效(数据无法在Elmah中显示和查看) string ConnectionString = string.Empty; foreach (ConnectionStringSettings str in ConfigurationManager.ConnectionStrings) { if (!str.Name.Contains("Elmah_SQLiteErrorLog")) continue; ConnectionString = str.ConnectionString; break; } using (SQLiteConnection sQLiteConnection = new SQLiteConnection(ConnectionString)) { using (SQLiteCommand sQLiteCommand = new SQLiteCommand("INSERT INTO Error (Application, Host, Type, Source, Message, User, StatusCode, TimeUtc, AllXml)VALUES (@Application, @Host, @Type, @Source, @Message, @User, @StatusCode, @TimeUtc, @AllXml);SELECT last_insert_rowid();", sQLiteConnection)) { SQLiteParameterCollection parameters = sQLiteCommand.Parameters; parameters.Add("@Application", DbType.String, 60).Value = "/"; parameters.Add("@Host", DbType.String, 30).Value = Environment.UserName; parameters.Add("@Type", DbType.String, 100).Value = "UserType"; parameters.Add("@Source", DbType.String, 60).Value = "UserType"; parameters.Add("@Message", DbType.String, 500).Value = message; parameters.Add("@User", DbType.String, 50).Value = Environment.UserName; parameters.Add("@StatusCode", DbType.Int64).Value = 300; parameters.Add("@TimeUtc", DbType.DateTime).Value = DateTime.Now; parameters.Add("@AllXml", DbType.String).Value = string.Format("<error type="UserType" message="{0}" source="{1}" detail=" {2} Source:{3} ">{4}</error>", message, source, detailmessage + " datetime:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss:ms"), source, GetServerVariables); try { sQLiteConnection.Open(); sQLiteCommand.ExecuteScalar(); } catch (Exception) { } finally { sQLiteCommand.Clone(); } } } } }
using System; using System.Web; using Elmah; namespace CustomErrorElmah { public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string querystr = " "; if (!string.IsNullOrEmpty(Request.QueryString.ToString())) querystr += Request.QueryString; //自定义错误 CustomErrorSqlite.AddLog("THIS IS TEST ,自定义Sql添加到Elmah的Sqlit数据库中", "Page_Load()", "自定义错误 自定义Sql添加到Elmah的Sqlit数据库中" + querystr); #region //创建一个Elmah的Error对象并写错误日志 Error error = new Error(); error.Message = "THIS IS TEST 使用Elmah的Error对象"; error.HostName = Request.Url.Host; error.StatusCode = 100; error.Time = DateTime.Now; error.User = Environment.UserName; error.Type = "Elmah 自定义类型"; error.Detail = "THIS IS TEST ,创建一个Elmah的Error对象并写错误日志 但没有Server Variables,cookie等信息" + querystr; error.Source = "Page_Load"; Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(error); #endregion //创建一个异常并写入错误日志,无法自定义错误的类型 Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("创建一个异常并写入错误日志" + querystr)); } } }
Web.config配置Elmah
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!--监控应用程序--> <sectionGroup name="elmah"> <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah"/> <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"/> <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah"/> </sectionGroup> </configSections> <!--Elmah连接数据库--> <elmah> <security allowRemoteAccess="yes"/> <errorLog type="Elmah.SQLiteErrorLog, Elmah" connectionStringName="Elmah_SQLiteErrorLog"/> </elmah> <connectionStrings> <!--监控应用程序 数据存储位置--> <add name="Elmah_SQLiteErrorLog" connectionString="Data Source=|DataDirectory|Error.db3"/> </connectionStrings> <system.web> <!--出现错误时的处理模块--> <httpHandlers> <add verb="POST,GET,HEAD" path="Elmah/Error.aspx" type="Elmah.ErrorLogPageFactory, Elmah"/> </httpHandlers> <httpModules> <!--出错时的处理模块--> <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/> <!--发送Email--> <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah"/> </httpModules> <customErrors defaultRedirect="/404.html" mode="Off"/> </system.web> </configuration>
有图有真相:
1.
2.
.
3.
之前一直想解决完全自定义错误信息的问题,但上面三个方法总不能让我完全满意(我需要Request的完整信息)
但第二个最接近我想要的效果,只是生成的错误信息没有Request信息见图2
在Bing.com和stackoverflow.com上搜索了半天也没有解决,无奈只好下载源码自己来处理
通过源码发现实现方法完全可以实现我要的效果(自动添加Request信息)
只需要将当前的HttpContext指向“Error ”对象既可
//创建一个Elmah的Error对象并写错误日志 //没有Request信息 Error error = new Elmah. Error ( ); //当前的HttpContext指向“Error ”,在生成的错误信息时会自动添加Request信息 Error error = new Elmah. Error ( new Exception (), HttpContext .Current); error.Message = "THIS IS TEST 使用Elmah的Error对象" ; error.HostName = Request.Url.Host; error.StatusCode = 100 ; error.Time = DateTime.Now; error.User = Environment.UserName; error.Type = "Elmah 自定义类型" ; error.Detail = "THIS IS TEST ,创建一个Elmah的Error对象并写错误日志 但没有Server Variables,cookie等信息" + querystr; error.Source = "Page_Load" ;
Elmah:http://code.google.com/p/elmah/
http://stackoverflow.com/questions/2108404/elmah-exceptions-without-httpcontext
http://stackoverflow.com/questions/3812538/elmah-add-message-to-error-logged-through-call-to-raisee
http://stackoverflow.com/questions/7441062/how-to-use-elmah-to-manually-log-errors