C#写Windows系统日志(EventLog)

 

.NET framework 2.0开始,可以使用 EventLog构造函数在Windows日志里添加内容,一切看上去是如此的简单。只是……

会涉及到一点点的权限问题,必须要注意一下。

使用 EventLog时,涉及到一个叫做“来源”(source)的参数(一般用来记录消息的出处)。比如将该参数设为“MyEXE”,那么写系统日志的时候,EventLog.WriteEntry就会去注册表里找这个叫做“MyEXE”的节点,如果找不到,那它会创建一个 MyEXE”节点作为来源,然后开始写入系统日志。的确是很人性化的处理办法。只是,要在注册表里建立一个节点,没有相当的权限是不行的,比如说系统管理员的权限。偏偏写系统日志的通常是一些服务账户(例如:NET SERVICE),这些账户往往不会有这么大的权限。

解决方案的话。

1. 事先在注册表里创建要使用的事件源。
  1. 点击“开始”,再点击“运行”。
  2. 在“打开”框中输入“regedit”。
  3. 找到下列子键:
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLogs\Application
  4. 右击“Application”点击“新建”再点“项”(各个参数可以参照同层的其他节点。)
  5. 关闭注册表编辑器

2. 代码中模拟管理员权限(个人不是很喜欢,因为要输入密码……

 

下面是使用 EventLog的一个例子。

using System;

using System.Diagnostics;

using System.Collections.Generic;

using System.Security;

using System.Text;

 

namespace ConsoleApplication2

{

    /// <summary>

    /// 写系日志

    /// </summary>

    public class AppLog

    {

        /// <summary>

        /// 日志所在的主机名。当前定:本地电脑

        /// </summary>

        public const string MACHINE_NAME = ".";

        /// <summary>

        /// 日志名。当前定:用程序

        /// </summary>

        public const string LOG_NAME = "Application";

        /// <summary>

        /// 消息事件型。当前定:无

        /// 该值为0候分类为

        /// </summary>

        public const short CATEGORY = 0;

 

        /// <summary>

        /// 消息事件的种类:信息(Information),警告(Warning),重大错误(Error)

        /// </summary>       

        public enum LogType

        {

            /// <summary>

            /// 重大错误

            /// </summary>

            Error = 1,

            /// <summary>

            /// 警告

            /// </summary>

            Warning = 2,

            /// <summary>

            /// 情報

            /// </summary>

            Information = 4

        }

 

        /// <summary>

        ///

        /// </summary>

        static AppLog()

        {

        }

 

        /// <summary>

        /// 向日志管理器写入系日志

        /// </summary>

        /// <param name="source">消息事件来源</param>

        /// <param name="message">要在消息事件中写入的信息</param>

        /// <param name="type">消息事件</param>       

        /// <param name="eventID">消息事件的事件ID。(0~65535)</param>

        /// <exception cref="System.ComponentModel.Win32Exception">日志存不足</exception>

        /// <exception cref="System.Security.SecurityException">操作系日志限不足</exception>

        static public void WriteEntry(string source, string message, LogType type, int eventID)

        {

            try

            {

                if (!EventLog.SourceExists(source))

                {

                    EventLog.CreateEventSource(source, LOG_NAME);                   

                }

                EventLog.WriteEntry(source, message, GetLogEntryType(type), eventID, CATEGORY);

            }

            catch (SecurityException)

            {

                //碰到限不无法操作系日志的情况时,模本地管理员权行操作。

                //提示:当注册表中没有消息事件来源,会例外

                //ImpersonateAccount的代参考鄙人另一篇文章C#模拟AD用户
                //不要指望可以使用System.Diagnostics.EventLogInstaller类,使用它也需要本地系统管理员的权限

                using (ImpersonateAccount sa = new ImpersonateAccount("<>", "<域>", "<>"))

                {

                    if (!EventLog.SourceExists(source))

                    {

                        EventLog.CreateEventSource(source, LOG_NAME);

                    }

                    EventLog.WriteEntry(source, message, GetLogEntryType(type), eventID, CATEGORY);

                }

            }

        }

 

        /// <summary>

        /// 向日志管理器写入系日志

        /// </summary>

        /// <param name="source">消息事件来源</param>       

        /// <param name="ex">要在消息事件中写入的信息</param>

        /// <param name="eventID">消息事件的事件ID。(0~65535)</param>       

        static public void WriteEntry(string source, Exception ex, int eventID)

        {

            StringBuilder sb = new StringBuilder();

            if (ex != null)

            {

                sb.AppendFormat("[Message]"n{0}"n", ex.Message);

                sb.AppendFormat("[Source]"n{0}"n", ex.Source);

                sb.AppendFormat("[TargetSite]"n{0}"n", ex.TargetSite);

                sb.AppendFormat("[ToString]"n{0}"n", ex.ToString());

                if (ex.Data.Count > 0)

                {

                    sb.Append("[Data]"n");

                    foreach (System.Collections.DictionaryEntry var in ex.Data)

                    {

                        sb.AppendFormat(""t[{0}]:{1}"n", var.Key, var.Value);

                    }

                }

            }

            WriteEntry(source, sb.ToString(), LogType.Error, eventID);

        }

 

        /// <summary>

        /// 将LogType转换EventLogEntryType

        /// </summary>

        /// <param name="type">LogType</param>

        /// <returns>EventLogEntryType</returns>

        /// <exception cref="System.ApplicationException">转换错误时抛出例外</exception>

        static private EventLogEntryType GetLogEntryType(LogType type)

        {

            Type t = typeof(EventLogEntryType);

            if (Enum.IsDefined(t, (int)type))

            {

                return (EventLogEntryType)Enum.Parse(t, ((int)type).ToString());

            }

            else

            {

                StringBuilder sb = new StringBuilder();

                sb.Append("LogType型无法转换为EventLogEntryType");

                sb.AppendFormat("(LogType:{0})", type);

                throw new ApplicationException(sb.ToString());

            }

        }

    }

}

 

posted on 2009-08-03 10:51  阿米巴原虫  阅读(2780)  评论(0编辑  收藏  举报