輔助紀錄的 API - LogAPI

這個是我撰寫的 API ,透過這個 API ,將系統的錯誤訊息全存到指定的 log
並且會排出版面來顯示錯誤資訊
由於打算放到共用類別庫,所以所有的參考都僅參考 .Net Framework 內已定義的類別庫 並透過 StackTrace 及 StackFrame 取得發生例外的函式名稱!
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;

namespace WCT.Common
{
    public class LogAPI : IDisposable
    {
        private struct BY_HANDLE_FILE_INFORMATION
        {
            public UInt32 FileAttributes;
            public System.Runtime.InteropServices.ComTypes.FILETIME
                CreationTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME
                LastAccessTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME
                LastWriteTime;
            public UInt32 VolumeSerialNumber;
            public UInt32 FileSizeHigh;
            public UInt32 FileSizeLow;
            public UInt32 NumberOfLinks;
            public UInt32 FileIndexHigh;
            public UInt32 FileIndexLow;
        }

        [DllImport("kernel32.dll")]
        private static extern bool AllocConsole();
        [DllImport("kernel32.dll")]
        private static extern bool AttachConsole(UInt32 dwProcessId);

        [DllImport("kernel32.dll")]
        private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle, out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions);

        [DllImport("kernel32.dll")]
        private static extern bool FreeConsole();

        [DllImport("kernel32.dll")]
        private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("kernel32.dll")]
        private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out UInt32 lpdwProcessId);

        [DllImport("kernel32.dll")]
        private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);


        private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
        private const UInt32 STD_INPUT_HANDLE = 0xFFFFFFF6;
        private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
        private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
        private const UInt32 DUPLICATE_SAME_ACCESS = 2;

        private static LogAPI mInstance = null;
        private static string mDirectory;
        private System.DateTime mDate;

        private string mFileName;
        private string mEntryFileName;
        private System.DateTime mStartTime;

        private System.Diagnostics.Stopwatch mStopWatch;

        private int ErrorCount;
        private int ReConnectionErrorCount;
        private StringBuilder ProgramInfo = new StringBuilder();
        private StringBuilder LogMessage = new StringBuilder();
        private StringBuilder ErrorMessage = new StringBuilder();

        private StringBuilder EntryMessage = new StringBuilder();

        private bool m_isSend = false;

        private bool m_isCmd = false;

        private string mFuncName = "TestLogAPI";

        private LogAPI()
        {
            mDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Log\\");
            mStartTime = DateTime.Now;
            mStopWatch = new System.Diagnostics.Stopwatch();
            mStopWatch.Start();
            ErrorCount = 0;
            ReConnectionErrorCount = 0;

            if (!Directory.Exists(mDirectory))
            {
                Directory.CreateDirectory(mDirectory);
            }
            else
            {
                // 清理超過一個月的 Log 紀錄檔
                try
                {
                    DirectoryInfo dirInfo = new DirectoryInfo(mDirectory);
                    DateTime today = DateTime.Today;
                    foreach (FileInfo FInfo in dirInfo.GetFiles("*.log"))
                    {
                        // 檔案保留 30 天
                        if (today.Subtract(FInfo.CreationTime) > new TimeSpan(30, 0, 0, 0))
                        {
                            FInfo.Delete();
                        }
                    }
                }
                catch
                {
                }
            }

            //IntPtr ptr = GetForegroundWindow();
            //UInt32 processId;
            //GetWindowThreadProcessId(ptr, out processId);
            //Process process = Process.GetProcessById(Convert.ToInt32(processId));

            //if (process.ProcessName == "cmd" || process.ProcessName == "command")
            //    m_isCmd = true;

            if (Console.Out != null)
                m_isCmd = true;

            ProgramInfo.AppendLine(string.Format("Assembly FullName:   {0}", Assembly.GetEntryAssembly().FullName));
            ProgramInfo.AppendLine(string.Format("Assembly CodeBase:   {0}", Assembly.GetEntryAssembly().CodeBase));
            ProgramInfo.AppendLine(string.Format("Assembly Location:   {0}", Assembly.GetEntryAssembly().Location));
            ProgramInfo.AppendLine(string.Format("Computer Name    :   {0}", Environment.MachineName));
            ProgramInfo.Append(getEntryPointAndCommandArgsInfo);
            ProgramInfo.AppendLine(string.Format("Run as           :   {0}", System.Security.Principal.WindowsIdentity.GetCurrent().Name));
            ProgramInfo.AppendLine(string.Format("Run Time         :   {0:yyyy/MM/dd HH:mm:ss.fff}", System.DateTime.Now));

        }

        public static LogAPI GetInstance()
        {
            if (mInstance == null)
            {
                mInstance = new LogAPI();
                mInstance.mDate = System.DateTime.Today;
                mInstance.mFileName = string.Format("{0:yyyyMMdd}.log", mInstance.mDate);
                mInstance.mEntryFileName = string.Format("{0:yyyyMMdd}_Entry.log", mInstance.mDate);
            }
            else
            {
                if (mInstance.mDate != System.DateTime.Today)
                {
                    mInstance.mDate = System.DateTime.Today;
                    mInstance.mFileName = string.Format("{0:yyyyMMdd}.log", mInstance.mDate);
                }
            }
            return mInstance;
        }

        public void SetSMTP(string SMTP, string SMTPID, string SMTPPW, string SMTPSender, string SMTPSenderName)
        {
            this.isSend = true;
            this.SMTP = SMTP;
            this.SMTPID = SMTPID;
            this.SMTPPW = SMTPPW;
            this.SMTPSender = SMTPSender;
            this.SMTPSenderName = SMTPSenderName;
        }

        public void SetSMTPEnabled()
        {
            this.isSend = true;
        }

        public void SetSMTPDisabled()
        {
            this.isSend = false;
        }

        public bool isSend
        {
            get { return m_isSend; }
            private set { m_isSend = value; }
        }

        public string CurrentEnvironment
        {
            get;
            set;
        }

        public string SMTP
        {
            get;
            private set;
        }

        public string SMTPID
        {
            get;
            private set;
        }

        public string SMTPPW
        {
            get;
            private set;
        }

        public string SMTPSender
        {
            get;
            private set;
        }

        public string SMTPSenderName
        {
            get;
            private set;
        }

        public string FuncName
        {
            get { return mFuncName; }
            set { mFuncName = value; }
        }

        public void TakeEntryMethod(params object[] value)
        {
            System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
            System.Diagnostics.StackFrame frame = trace.GetFrame(1);
            var parameters = frame.GetMethod().GetParameters();
            bool pflag = true;
            StringBuilder _sb = new StringBuilder();
            StringBuilder goalsb;
#if DEBUG
            goalsb = EntryMessage;
#else
            goalsb = LogMessage;
#endif
            lock (goalsb)
            {
                _sb.Append(string.Format("[Entry][{0:HH:mm:ss.fff}][", System.DateTime.Now));
                MethodInfo mi = frame.GetMethod() as MethodInfo;
                if (mi != null)
                    _sb.Append(string.Format("{0} {1}.{2}(", mi.ReturnType.FullName, mi.ReflectedType.FullName, mi.Name));
                else
                    _sb.Append(string.Format("{0}.{1}(", frame.GetMethod().ReflectedType.FullName, frame.GetMethod().Name));
                for (int i = 0; i < parameters.Length; i++)
                {
                    if (pflag)
                        pflag = false;
                    else
                        _sb.Append(",");
                    if (i < value.Length)
                    {
                        _sb.Append(string.Format("{0}=", parameters[i].ToString()));
                        if (value[i] == null)
                            _sb.Append("NULL");
                        else if (value[i].Equals(DBNull.Value))
                            _sb.Append("DBNull");
                        else if (value[i] is DateTime)
                        {
                            if (((DateTime)value[i]).ToString("HHmmssfff") == "000000000")
                                _sb.AppendFormat("{0:yyyy/MM/dd}", value[i]);
                            else
                                _sb.AppendFormat("{0:yyyy/MM/dd HH:mm:ss.fff}", value[i]);
                        }
                        else
                            _sb.Append(value[i].ToString());
                    }
                    else
                        _sb.Append(string.Format("{0}", parameters[i].ToString()));
                }
                _sb.AppendLine(")]");

                if (m_isCmd)
                    Console.Write(_sb.ToString());

                goalsb.Append(_sb.ToString());
            }
        }

        public void InfoMsg(string msg)
        {
            InfoMsg(msg, false);
        }

        public void InfoMsg(string format, params object[] args)
        {
            InfoMsg(string.Format(format, args));
        }

        public void InfoMsg(string msg, bool showStackFrame)
        {
            if (showStackFrame)
            {
                string currentMethod = System.Reflection.MethodBase.GetCurrentMethod().Name;
                System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
                System.Diagnostics.StackFrame frame = trace.GetFrame(1);
                var parameters = frame.GetMethod().GetParameters();
                bool pflag = true;
                StringBuilder sb = new StringBuilder();
                lock (LogMessage)
                {
                    sb.Append(string.Format("[Info.][{0:HH:mm:ss.fff}][{1}+{2}(", System.DateTime.Now, frame.GetMethod().ReflectedType.FullName, frame.GetMethod().Name));
                    foreach (var para in parameters)
                    {
                        if (pflag)
                            pflag = false;
                        else
                            sb.Append(",");
                        sb.Append(para.ToString());
                    }
                    sb.AppendLine(string.Format(")]{0}", msg));
                    Console.WriteLine(sb.ToString());
                    LogMessage.Append(sb.ToString());
                }
            }
            else
            {
                lock (LogMessage)
                {
                    string AppendMsg = string.Format("[Info.][{0:HH:mm:ss.fff}]{1}", System.DateTime.Now, msg);
                    LogMessage.AppendLine(AppendMsg);
                    Console.WriteLine(AppendMsg);
                }
            }
        }

        public void ErrorMsg(string msg, Exception ex)
        {
            if (ex == null)
            {
                return;
            }

            System.DateTime LogTime = System.DateTime.Now;

            lock (LogMessage)
            {
                StringBuilder sbLogMessage = new StringBuilder();
                StringBuilder sbErrorMessage = new StringBuilder();

                ErrorCount += 1;
                var sex = ex as System.Data.SqlClient.SqlException;
                if (sex != null && sex.ErrorCode == -2146232060)
                    ReConnectionErrorCount += 1;

                sbLogMessage.AppendLine(string.Format("[Error][{0:HH:mm:ss.fff}][{2:00}]{1}", LogTime, msg, ErrorCount));
                sbErrorMessage.AppendLine(string.Format("DetailID = {0}", ErrorCount));
                sbErrorMessage.AppendLine(string.Format("\tType:     {0}", ex.GetType().FullName));
                var w32ex = ex as System.ComponentModel.Win32Exception;
                if (w32ex != null)
                {
                    sbErrorMessage.AppendLine(string.Format("\tErr. Code:{0}", w32ex.ErrorCode));
                }
                sbErrorMessage.AppendLine(string.Format("\tMessage:  {0}", ex.Message));

                if (!string.IsNullOrEmpty(ex.StackTrace))
                {
                    sbErrorMessage.AppendLine("\tStack:");
                    bool flag = true;
                    foreach (string s in ex.StackTrace.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        sbErrorMessage.Append("\t\t");
                        if (flag)
                            flag = false;
                        else
                            sbErrorMessage.Append("   ");
                        sbErrorMessage.AppendLine(s);
                    }
                }

                Console.Write(sbLogMessage.ToString());
                Console.Write(sbErrorMessage.ToString());

                LogMessage.Append(sbLogMessage.ToString());
                ErrorMessage.Append(sbErrorMessage.ToString());
            }
        }

        public string getEntryPointAndCommandArgsInfo
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(string.Format("Assembly EntryPoint: {0}+{2} {1}(", Assembly.GetEntryAssembly().EntryPoint.DeclaringType, Assembly.GetEntryAssembly().EntryPoint.Name, Assembly.GetEntryAssembly().EntryPoint.ReturnType));
                int pCount = 0;
                foreach (var p in Assembly.GetEntryAssembly().EntryPoint.GetParameters())
                {
                    if (pCount > 0)
                    {
                        sb.Append(",");
                    }
                    sb.Append(p.ToString());
                    pCount += 1;
                }
                sb.AppendLine(")");
                if (System.Environment.GetCommandLineArgs().Length > 1)
                {
                    sb.AppendLine("CommandLine Args :");
                    pCount = 0;
                    foreach (string arg in System.Environment.GetCommandLineArgs())
                    {
                        sb.AppendLine(string.Format("\t{0,2}=>\t{1}", pCount, arg));
                        pCount += 1;
                    }
                }
                return sb.ToString();
            }
        }

        public string getFileDetails()
        {
            return getFileDetails(false);
        }

        public string getFileDetails(bool FileExists)
        {

            StringBuilder sb = new StringBuilder();
            if (FileExists)
            {
                sb.AppendLine("");
                sb.AppendLine("=======================");
                sb.AppendLine(string.Format("Log Start Time:      {0:yyyy/MM/dd HH:mm:ss.fff}", mStartTime));
                sb.Append(getEntryPointAndCommandArgsInfo);
                sb.AppendLine(string.Format("Current Environment: {0}", CurrentEnvironment));
                sb.AppendLine("=======================");
            }
            else
            {
                sb.AppendLine("***********************");
                sb.AppendLine("*    FILE DETAILS     *");
                sb.AppendLine("***********************");
                sb.Append(ProgramInfo.ToString());
                sb.AppendLine(string.Format("Current Environment: {0}", CurrentEnvironment));
            }

            return sb.ToString();
        }

        public string getLogMessageDetails
        {
            get
            {
                if (LogMessage.Length > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine("***********************");
                    sb.AppendLine("* LOG MESSAGE DETAILS *");
                    sb.AppendLine("***********************");
                    sb.Append(LogMessage.ToString());
                    return sb.ToString();
                }
                else
                {
                    return "";
                }
            }
        }

        public string getEntryMessageDetails
        {
            get
            {
                if (LogMessage.Length > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine("***********************");
                    sb.AppendLine("* ENTRY MSG. DETAILS  *");
                    sb.AppendLine("***********************");
                    sb.Append(EntryMessage.ToString());
                    return sb.ToString();
                }
                else
                {
                    return "";
                }
            }
        }

        public string getExceptionDetails
        {
            get
            {
                if (ErrorMessage.Length > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine("***********************");
                    sb.AppendLine("*  EXCEPTION DETAILS  *");
                    sb.AppendLine("***********************");
                    sb.Append(ErrorMessage.ToString());
                    return sb.ToString();
                }
                else
                {
                    return "";
                }
            }
        }

        public string getFooter(DateTime current, double runSeconds)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("***********************");
            sb.AppendLine(string.Format("Log Write Time:   {0:yyyy/MM/dd HH:mm:ss.fff}", current));
            sb.AppendLine(string.Format("本次執行花費時間: {0} 秒", runSeconds));
            sb.AppendLine("***********************");
            return sb.ToString();
        }

        public void SaveLog()
        {
            try
            {
                mStopWatch.Stop();
                bool logExists = File.Exists(Path.Combine(mDirectory, mFileName));
                bool logEntryExists = File.Exists(Path.Combine(mDirectory, mEntryFileName));
                DateTime currentdt = DateTime.Now;

                using (FileStream fs = File.Open(Path.Combine(mDirectory, mFileName), FileMode.Append))
                {
                    using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.Default))
                    {

                        sw.Write(getFileDetails(logExists));
                        sw.Write(getLogMessageDetails);
                        sw.Write(getExceptionDetails);
                        sw.Write(getFooter(currentdt, mStopWatch.Elapsed.TotalSeconds));

                        sw.Close();
                    }
                    fs.Close();
                }

                if (EntryMessage.Length >= 0)
                {
                    using (FileStream fs = File.Open(Path.Combine(mDirectory, mEntryFileName), FileMode.Append))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.Default))
                        {

                            sw.Write(getFileDetails(logEntryExists));
                            sw.Write(getEntryMessageDetails);
                            sw.Write(getFooter(currentdt, mStopWatch.Elapsed.TotalSeconds));

                            sw.Close();
                        }
                        fs.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        ~LogAPI()
        {
            Dispose();
        }

        public new void Dispose()
        {
            try
            {
                SaveLog();

                try
                {
                    if (isSend && ErrorCount - ReConnectionErrorCount > 0)
                    {
                        SmtpClient smtp = new SmtpClient();
                        smtp.Host = SMTP;
                        smtp.Credentials = new System.Net.NetworkCredential(SMTPID, SMTPPW);

                        StringBuilder sb = new StringBuilder();
                        sb.Append(getFileDetails(false));
                        sb.Append(getLogMessageDetails);
                        sb.Append(getExceptionDetails);
                        sb.AppendLine("***********************");
                        sb.AppendLine(string.Format("Log Write Time:   {0:yyyy/MM/dd HH:mm:ss.fff}", System.DateTime.Now));
                        sb.AppendLine(string.Format("本次執行花費時間: {0} 秒", mStopWatch.Elapsed.TotalSeconds));
                        sb.AppendLine("***********************");

                        MailMessage msg = new MailMessage();
                        msg.From = new MailAddress(SMTPSender, SMTPSenderName);
                        msg.To.Add(new MailAddress("n960477@mail.hosp.ncku.edu.tw"));
                        msg.Subject = string.Format("{0} 執行結果", mFuncName);
                        msg.Body = sb.ToString();
                        smtp.Send(msg);
                    }
                }
                catch
                {
                }

                ProgramInfo.Remove(0, ProgramInfo.Length);
                LogMessage.Remove(0, LogMessage.Length);
                EntryMessage.Remove(0, EntryMessage.Length);
                ErrorMessage.Remove(0, ErrorMessage.Length);

                ErrorCount = ReConnectionErrorCount = 0;

                GC.SuppressFinalize(this);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

留言

這個網誌中的熱門文章

DB 資料庫呈現復原中

Outlook 刪除大量重覆信件

[VB.Net] If vs IIf ,兩者的差異