65.9K
CodeProject 正在变化。 阅读更多。
Home

Easy Log Viewer。又一个日志查看器工具,但更简单。

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.67/5 (9投票s)

2015 年 6 月 3 日

Ms-RL

2分钟阅读

viewsIcon

53382

downloadIcon

1926

Easy Log Viewer是一个帮助开发人员更轻松地查看日志的工具,

引言

Easy Log Viewer 是一个帮助开发人员更轻松地查看日志的工具,它包含以下功能

1: 支持所有类型的日志(Windows 事件日志、CSV 日志、XML 日志、文本日志、数据库日志...)。

  • 打开 Windows 事件日志(应用程序)。

  • 打开 CSV 文件

  • 打开 XML 文件

  • 打开文本文件

2: 易于过滤和搜索,我想没有人希望查看器不支持此功能。

点击 查找上一个查找下一个查找内容: 之间导航

3: 该功能应该强大,应该支持包含、不包含、以…开始、等于、正则表达式…,这样我就可以更容易地过滤日志。

4: 基于过滤器的突出显示,有时我想突出显示感兴趣的项目。

5: 隐藏或显示一些日志记录,这将使我能够专注于我感兴趣的日志。

6: 书签支持。 就像 Visual Studio 一样,在书签中导航更容易。

7: 注释支持,有时我想向日志添加一些注释,这样当我将它们发送给其他人时,其他人就可以看到我的注释了。

8: 保存日志,它应该保存日志和日志的设置。

9: 用户界面应该愚蠢而简单,并且功能强大,它应该易于使用,易于重新排列,并支持全屏模式。

自由风格

全屏模式

背景

有很多日志记录框架,比如 log4j、log4net、NLog、Microsoft Enterprise Logging Framework...

这些日志记录框架帮助开发人员在应用程序中记录消息,有了这些框架,您可以将您的消息记录到数据库、控制台、文件、其他计算机,以及任何您想要的。

然而,我发现 没有 日志查看器工具支持所有类型的日志记录目标。

一些工具只支持一种日志格式,而有些工具没有我想要的功能,这就是我创建这个工具的原因!

使用代码

EasyLogViewer 支持插件,

例如,如果你想从其他地方读取你的日志条目,

  1. 创建一个项目,并将引用添加到 EasyLogViewer.IHandler.dll
  2. 实现 IReadLogFileHandler 接口,
  3. 将构建 bin 文件夹放到 Plugins 文件夹中,就像其他插件一样。
namespace EasyLogViewer.IHandler
{
    public interface IReadLogFileHandler : IBaseHandler
    {
        object Execute(string fileName, Action<IEnumerable<ExpandoObject>> newLogEntriesCallback, HandledEventArgs args);
    }
}

以下是如何编写文本文件读取器的示例

public class LineFileHandler : IReadLogFileHandler
{
	public int Priority
	{
		get { return Int32.MinValue; }
	}

	public object Execute(string fileName, Action> newLogEntriesCallback,HandledEventArgs args)
	{
		var result = new List<ExpandoObject>();
		using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
		{
			using (var sr = new StreamReader(fs))
			{
				while (sr.Peek() >= 0)
				{
					dynamic obj = new ExpandoObject();
					obj.Message = sr.ReadLine();

					result.Add(obj);
				}
			}
		}

		args.Handled = true;

		return result;
	}
}

您的插件将由 PluginManager 类执行。

public static class PluginManager
	{
		private static readonly Dictionary<object, object=""> pluginCache = new Dictionary<object, object="">();
		private static readonly List<type> pluginTypes = new List<type>();

		public static void LoadPlugins()
		{
			foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
			{
				LoadPlugins(assembly);
			}

			// load 3rd last.
			string[] pluginFolders = Directory.GetDirectories("Plugins");
			foreach (string pluginFolder in pluginFolders)
			{
				string[] files = Directory.GetFiles(pluginFolder, "*.dll");

				foreach (string file in files)
				{
					Assembly assembly = Assembly.LoadFrom(Environment.CurrentDirectory + "\\" + file);

					//Assembly assembly = AppDomain.CurrentDomain.Load(Environment.CurrentDirectory + "\\" + file);

					LoadPlugins(assembly);
				}
			}
		}

		public static object RunPlugins<t>(this object owner, params object[] handleArgs) where T : IBaseHandler
		{
			object result = null;

			var eventArgs = new HandledEventArgs(false);

			List<object>newArgs = handleArgs.ToList();
			newArgs.Add(eventArgs);
			object[] combineArgs = newArgs.ToArray();

			List<t> handlers = GetPlugins<t>(owner);
			MethodInfo methodInfo = null;
			foreach (T handler in handlers)
			{
				try
				{
					if (methodInfo == null)
					{
						methodInfo = typeof(T).GetMethod("Execute");
					}

					if (eventArgs.Handled == false)
					{
						result = methodInfo.Invoke(handler, combineArgs);

						if (eventArgs.Handled)
						{
							EventLogHelper.LogInformation(string.Format("Parse Log Success {0}", handler));
						}
					}
					else
					{
						break;
					}
				}
				catch (Exception ex)
				{
					//swallow this exception, do the next parser.
					EventLogHelper.LogError("This plugin has error,...", ex);
				}
			}

			return result;
		}

		private static List<t> GetPlugins<t>(object owner) where T : IBaseHandler
		{
			if (!pluginCache.ContainsKey(owner) ||
				!pluginCache[owner].OfType<t>().Any())
			{
				List<type> matchPluginTypes = pluginTypes.Where(t => t.Implements<t>()).ToList();

				List<object> plugins =
					(from matchPluginType in matchPluginTypes
					 where matchPluginType.IsClass
					 select Activator.CreateInstance(matchPluginType)).ToList();

				pluginCache[owner] = plugins;
			}

			return pluginCache[owner]
				.OfType<t>()
				.OrderByDescending(t => t.Priority)
				.ToList();
		}

		private static void LoadPlugins(Assembly assembly)
		{
			IList<type> types = assembly.TypesImplementing<ibasehandler>();
			foreach (Type type in types)
			{
				pluginTypes.Add(type);
			}
		}
	}

请注意 RunPlugins<T> 方法,此方法将参数传递给插件,并通过反射运行 Execute 方法。

那么接下来呢?

EasyLogViewer 仍待开发的功能

  • 以多种格式导出日志(CSV、XML 等)。
  • 突出显示方法 Enter 和 Exit,
  • 分组方法。
  • 分组过滤器,以便过滤器可以 And/Or。
  • 列显示插件。
  • 在查找日志之间快速导航。
  • 有什么想分享的想法吗? 告诉我。

关注点

https://logging.apache.ac.cn/log4net/

http://nlog-project.org/

历史

2015 年 5 月 30 日:版本 1.0

  • 初始发布。
© . All rights reserved.