欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

asp.net mvc实现 错误异常记录功能

程序员文章站 2022-06-11 23:44:37
...

创建LogExceptionAttribute 类,继承HandleErrorAttribute 错误异常过滤器

using System;
using System.Web.Mvc;

namespace SXF.Utils.MVC
{
    /// <summary>
    /// 错误日志记录
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
    public class LogExceptionAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            if (!filterContext.ExceptionHandled)
            {
                #region 记录错误日志
                string controllerName = (string)filterContext.RouteData.Values["controller"];
                string actionName = (string)filterContext.RouteData.Values["action"];
                string msgTemplate = string.Format("在执行 controller[{0}] 的 action[{1}] 时产生异常", controllerName, actionName);
                EventLog.LogItem item = new EventLog.LogItem();
                item.Title = msgTemplate;
                LogManage.WriteException(filterContext.Exception, item);
                #endregion
            }
            base.OnException(filterContext);
        }
    }
}

此方法中用到了EventLog类中的方法,代码如下:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Text;
using System.Web;

namespace SXF.Utils
{
    /// <summary>
    /// 写日志
    /// 不想自动记录Context信息请调用Log(string message, string typeName, false)
    /// </summary>
    public class EventLog
    {
        /// <summary>
        /// 是否使用上下文信息写日志
        /// </summary>
        static bool UseContext = true;
        static string _thisDomain = "";


        #region LogItem
        [Serializable]
        public class LogItem
        {
            public DateTime Time
            {
                get;
                set;
            }
            public string Title
            {
                get;
                set;
            }
            public string Detail
            {
                get;
                set;
            }
            public string RequestUrl
            {
                get;
                set;
            }
            public string UrlReferrer
            {
                get;
                set;
            }
            public string HostIP
            {
                get;
                set;
            }
            public string UserAgent
            {
                get;
                set;
            }
            public override string ToString()
            {
                string s = Time.ToString("yyyy-MM-dd HH:mm:ss");
                if (string.IsNullOrEmpty(Title))
                {
                    Title = Detail;
                    Detail = "";
                }
                if (!string.IsNullOrEmpty(Title))
                {
                    s += "  " + Title;
                }
                if (!string.IsNullOrEmpty(RequestUrl))
                {
                    s += "\r\nUrl:" + RequestUrl;
                }
                if (!string.IsNullOrEmpty(UrlReferrer))
                {
                    s += "\r\nUrlReferrer:" + UrlReferrer;
                }
                if (!string.IsNullOrEmpty(HostIP))
                {
                    s += "\r\nHostIP:" + HostIP;
                }
                if (!string.IsNullOrEmpty(UserAgent))
                {
                    s += "\r\n" + UserAgent;
                }
                if (!string.IsNullOrEmpty(Detail))
                {
                    s += "\r\n" + Detail;
                }
                s += "\r\n";
                return s;
            }
        }
        #endregion


        static object lockObj = new object();
        /// <summary>
        /// 检查目录并建立
        /// </summary>
        /// <param name="path"></param>
        public static void CreateFolder(string path)
        {
            if (path.IsNullOrEmpty())
            {
                return;
            }
            string folder = "";
            string[] arry = path.Split('\\');
            for (int i = 0; i < arry.Length; i++)
            {
                folder += arry[i] + "\\";
                if (!Directory.Exists(folder))
                    Directory.CreateDirectory(folder);
            }
        }
        /// <summary>
        /// 自定义文件名前辍写入日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="typeName"></param>
        /// <param name="useContext"></param>
        /// <returns></returns>
        public static bool Log(string message, string typeName, bool useContext)
        {
            LogItem logItem = new LogItem();
            logItem.Detail = message;
            return Log(logItem, typeName, useContext);
        }
        public static bool Log(string message, string typeName)
        {
            return Log(message, typeName, true);
        }
        /// <summary>
        /// 指定日志类型名生成日志
        /// </summary>
        /// <param name="logItem"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static bool Log(LogItem logItem, string typeName)
        {
            return Log(logItem, typeName, true);
        }
        /// <summary>
        /// 指定日志类型名生成日志
        /// </summary>
        /// <param name="logItem"></param>
        /// <param name="typeName"></param>
        /// <param name="useContext">是否使用当前上下文信息</param>
        /// <returns></returns>
        public static bool Log(LogItem logItem, string typeName, bool useContext)
        {
            string fileName = DateTime.Now.ToString("yyyy-MM-dd");
            if (!string.IsNullOrEmpty(typeName))
            {
                fileName += "." + typeName;
            }
            HttpContext context = HttpContext.Current;
            logItem.Time = DateTime.Now;

            if (context != null)
            {
                try
                {
                    if (string.IsNullOrEmpty(_thisDomain))
                    {
                        _thisDomain = context.Request.Url.Host;
                    }
                    if (UseContext)
                    {
                        if (useContext)
                        {
                            logItem.HostIP = RequestHelper.GetCdnIP();

                            logItem.RequestUrl = context.Request.Url.ToString();
                            logItem.UserAgent = context.Request.UserAgent;
                            logItem.UrlReferrer = context.Request.UrlReferrer + "";
                        }
                    }
                }
                catch
                {
                }
            }
            return WriteLog(GetLogFolder(), logItem, fileName);
        }
        /// <summary>
        /// 生成日志,默认文件名
        /// </summary>
        /// <param name="message"></param>
        /// <param name="sendToServer">是否发送到服务器</param>
        /// <returns></returns>
        public static bool Log(string message, bool sendToServer)
        {
            //if (sendToServer)
            //{
            //    SendToServer(message, "");
            //}
            return WriteLog(message);
        }
        /// <summary>
        /// 生成日志,默认文件名
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool Log(string message)
        {
            return WriteLog(message);
        }
        /// <summary>
        /// 生成日志,文件名以Error开头
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool Error(string message)
        {
            return Log(message, "Error");
        }
        /// <summary>
        /// 生成日志,文件名以Info开头
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool Info(string message)
        {
            return Log(message, "Info");
        }
        /// <summary>
        /// 生成日志,文件名以Debug开头
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool Debug(string message)
        {
            return Log(message, "Debug");
        }
        /// <summary>
        /// 在当前网站目录生成日志
        /// </summary>
        /// <param name="message"></param>
        public static bool WriteLog(string message)
        {
            return Log(message, "");
        }


        static bool Writing = false;
        //static DateTime lastWriteTime = DateTime.Now;
        static Dictionary<string, LogItemArry> logCaches = new Dictionary<string, LogItemArry>();
        static System.Timers.Timer timer;
        private static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (!Writing)
            {
                WriteLogFromCache();
            }

        }
        /// <summary>
        /// 指定路径,文件名,写入日志
        /// </summary>
        /// <param name="path"></param>
        /// <param name="logItem"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool WriteLog(string path, LogItem logItem, string fileName)//建立日志
        {
            try
            {
                if (timer == null)
                {
                    timer = new System.Timers.Timer();
                    timer.Interval = 2000;
                    timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
                    timer.Start();
                }
                if (!System.IO.Directory.Exists(path))
                    CreateFolder(path);
                string filePath = "";

                filePath = path + fileName + ".txt";

                if (!logCaches.ContainsKey(filePath))
                    logCaches.Add(filePath, new LogItemArry() { savePath = filePath });

                logCaches[filePath].Add(logItem);
                return true;
            }
            catch
            {
                return false;
            }
        }
        public static string LastError;
        public static void WriteLogFromCache()
        {
            lock (lockObj)
            {
                Writing = true;
                //累加上次记录的日志
                if (logCaches.Count > 0)
                {
                    Dictionary<string, LogItemArry> list = new Dictionary<string, LogItemArry>(logCaches);
                    foreach (KeyValuePair<string, LogItemArry> entry in list)
                    {
                        LogItemArry logitemArry = entry.Value;
                        LastError = null;
                        try
                        {
                            WriteLine(logitemArry.ToString(), entry.Key);
                        }
                        catch (Exception ero)
                        {
                            LastError = ero.ToString();
                        }
                        logCaches.Remove(entry.Key);
                    }
                }
                //System.Threading.Thread.Sleep(6000);
                Writing = false;
            }
        }


        /// <summary>
        /// 写信息到指定文件
        /// </summary>
        /// <param name="message"></param>
        /// <param name="filePath"></param>
        private static void WriteLine(string message, string filePath)
        {

            using (FileStream fs = File.OpenWrite(filePath))
            {
                //根据上面创建的文件流创建写数据流
                StreamWriter w = new StreamWriter(fs, System.Text.Encoding.Default);
                //设置写数据流的起始位置为文件流的末尾
                w.BaseStream.Seek(0, SeekOrigin.End);
                //w.Write(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
                w.Write(message);
                w.Flush();
                w.Close();
            }
            Console.WriteLine(message);
        }
        static string secondFolder = null;
        /// <summary>
        /// 获取日志二级目录
        /// </summary>
        /// <returns></returns>
        public static string GetSecondFolder()
        {
            if (secondFolder == null)
            {
                string address = RequestHelper.GetServerIp();

                string[] arry = address.Split('.');
                secondFolder = arry[arry.Length - 1];
            }
            return secondFolder;
        }
        static string rootPath = null;
        /// <summary>
        /// 获取日志绝对目录
        /// </summary>
        /// <returns></returns>
        public static string GetLogFolder()
        {
            if (rootPath == null)
            {
                rootPath = System.Web.Hosting.HostingEnvironment.MapPath(@"\log\");
                if (string.IsNullOrEmpty(rootPath))
                {
                    rootPath = AppDomain.CurrentDomain.BaseDirectory + @"\log\";
                }
                rootPath += GetSecondFolder() + @"\";
                //如果节点有设置,则按节点设置读取
                NameValueCollection appSettings = ConfigurationManager.AppSettings;
                string settingPath = appSettings["EventLogFolder"];
                if (!string.IsNullOrEmpty(settingPath))
                {
                    rootPath = settingPath + @"\";
                }
            }
            return rootPath;
        }


        /// <summary>
        /// 项集合
        /// </summary>
        public class LogItemArry
        {
            public string savePath;
            List<LogItem> logs = new List<LogItem>();
            public void Add(LogItem log)
            {
                logs.Add(log);
            }
            public override string ToString()
            {
                StringBuilder sb = new StringBuilder();
                foreach (LogItem item in logs)
                {
                    sb.Append(item.ToString());
                }
                return sb.ToString() + "\r\n";
            }
        }
    }
}

用到了LogManage 类的方法,代码如下:

using System;
using System.Text;
using System.Web;


namespace SXF.Utils.MVC
{
    /// <summary>
    /// mvc日志管理
    /// </summary>
    public class LogManage
    {
        public static Exception GetInnerException(Exception exp)
        {
            if (exp.InnerException != null)
            {
                exp = exp.InnerException;
                return GetInnerException(exp);
            }
            return exp;
        }

        static long exceptionId = 0;
        static object lockObj = new object();


        /// <summary>
        /// 内部记录日志
        /// </summary>
        /// <param name="ero"></param>
        /// <returns></returns>
        static string InnerLogException(Exception ero, EventLog.LogItem item)
        {
            string host = HttpContext.Current.Request.Url.Host.ToUpper();
            string errorCode = host.Replace(".", "_");
            lock (lockObj)
            {
                exceptionId += 1;
                errorCode += ":" + EventLog.GetSecondFolder() + ":" + exceptionId;
            }

            ero = GetInnerException(ero);


            item.Title = item.Title + ",错误代码:" + errorCode;
            if (ero != null)
            {
                item.Detail = ero.Message + "\r\n" + ero.StackTrace + "\r\n";
            }
            EventLog.Log(item, "Error");
            if (host == "LOCALHOST")
            {
                return errorCode;
            }


            return errorCode;
        }

        /// <summary>
        /// 页面输出并写入错误日志
        /// </summary>
        /// <param name="ero"></param>
        public static void WriteException(Exception ero, EventLog.LogItem item)
        {
            //EventLog.Log("start1", "error");
            bool logError = true;
            if (ero is HttpException)
            {
                HttpException he = ero as HttpException;
                int code = he.GetHttpCode();
                if (code == 404)
                {
                    logError = false;
                }
            }
            if (ero is HttpRequestValidationException)
            {
                logError = false;
            }
            //EventLog.Log("start2", "error");
            string errorCode = string.Empty;
            if (logError)
            {
                //EventLog.Log("start6", "error");
                errorCode = InnerLogException(ero, item);
            }

        }



    }
}

写好后需要在FilterConfig 中注册:

public static class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            //错误处理
            filters.Add(new HandleErrorAttribute());
            //日志记录
            filters.Add(new SXF.Utils.MVC.LogExceptionAttribute());
           
        }
    }

global.asax.cs中已经在application_start中默认有调用代码:

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

另外 web.config 中设置:

<customErrors mode="Off" />


这样就设置好了,一旦在网站中出现mvc 错误,会在网站根目录的 log 文件夹下,自动创建一个类似这样的txt 日志文件:2017-08-02.Error.txt ,每天都会创建一个。若没创建,要么是没有log 文件夹,要么是log 文件夹网站默认用户没创建文件及文件夹的权限