日志监视器






4.71/5 (19投票s)
2007 年 6 月 5 日
4分钟阅读

129303

6464
本文介绍了如何编写一个应用程序来监视文本日志文件。
引言
我经常需要监视基于文本的日志文件,例如服务或 IIS 日志。 我厌倦了必须在我的编辑器中刷新文件,或者必须关闭并重新打开文件才能看到最新的更改。 因此,我编写了一个工具,它可以为我完成这项工作,并不断向我显示日志文件的最新添加内容。 该应用程序功能相当全面。 它支持以下功能
- 可以同时打开多个日志文件。
- 文件名可以作为参数传递给应用程序,以便在启动时加载。
- 使用 TabControl 在正在监视的日志文件之间切换。
- 文件可以拖放到应用程序上。
- 日志可以通过计时器或立即使用 FileSystemWatcher 进行更新。
- 更新可以暂停。
- 为了优化性能,只读取自上次更新以来添加到日志中的行。
- 如果文件太大,则仅读取日志的末尾。
- 正确处理仅使用换行符终止行的日志文件。
- 设置和窗口位置保存在配置文件中。
使用代码
要使用源代码,只需解压缩 源文件 并打开 LogMonitor.sln 解决方案文件。 这是完全使用 C# 在 .NET 2.0 中编写的。
关注点
LogMonitorControl 用户控件
此应用程序中的主要工作类是 LogMonitorControl
,它是一个用户控件,用于监视单个日志文件。 TabControl
用于保存多个 LogMonitorControl
实例。
线程问题
一个棘手的问题是 LogMonitorControl
可以使用 Timer
或 FileSystemWatcher
来监视日志文件。 它们在线程方面表现不同。 使用 Timer
时,计时器滴答回调发生在主线程上。 但是,当使用 FileSystemWatcher
方法时,回调发生在另一个线程上。 因此,更新子控件涉及通过 InvokeRequired
属性检查是否应使用 Invoke。 匿名委托对此有很大帮助。 但是,如果要为控件执行大量代码,那么编写一个执行这些操作的方法也很方便。 然后或者 Invoke 该方法,或者直接调用它。 下面是一个需要它的示例。 请注意,方法 DoScrollToEnd
是 LogMonitorControl
类的 一个方法,而不是控件的一个成员 调用方法
public void ScrollToEnd()
{
if (_textBoxContents.InvokeRequired)
{
_textBoxContents.Invoke(new MethodInvoker(DoScrollToEnd));
}
else
{
DoScrollToEnd();
}
}
拖放支持
(嗯,只是拖放支持而已。)
添加拖放支持非常容易,只包含 2 个方法。 代码如下
private void tabControl_DragDrop(object sender, DragEventArgs e)
{
// Accept files dropped and create new a tab each file.
IDataObject data = e.Data;
// Only accept file drops
if (data.GetDataPresent(DataFormats.FileDrop))
{
// Get the list of files dropped and create tabs for each
string[] filesToDrop =
(string[])e.Data.GetData(DataFormats.FileDrop, false);
for (int idx = 0; idx < filesToDrop.Length; idx++)
{
MonitorNewFile(filesToDrop[idx]);
}
}
}
private void tabControl_DragEnter(object sender, DragEventArgs e)
{
IDataObject data = e.Data;
// Only accept file drops
if (data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
FileSystemWatcher
FileSystemWatcher
类位于 System.IO
命名空间中,用于监视对文件或目录中任何文件的更改。 构造函数接受路径和文件名模式。 LogMonitor 应用程序使用文件名作为模式调用构造函数,以监视单个文件。 我们对该类可以引发的所有更改事件感兴趣,因此我们注册了所有这些事件。 我们实际上可以通过重命名来跟踪此文件,并继续监视日志文件,但我选择简单地继续监视相同的文件。 然后,如果文件被重命名回去,我们将检测到这一点。 同样,如果使用相同的文件名创建另一个文件,也将被检测到。 关于 FileSystemWatcher
类,有一件事并不完全明显。 也就是说,如果您注册了文件事件,除非将属性 EnableRaisingEvents
设置为 true,否则您将永远不会收到它们。
_watcher = new System.IO.FileSystemWatcher(path, baseName);
FileSystemEventHandler handler = new FileSystemEventHandler(watcher_Changed);
_watcher.Changed += handler;
_watcher.Created += handler;
_watcher.Deleted += handler;
_watcher.Renamed += watcher_Renamed;
// Without setting EnableRaisingEvents nothing happens
_watcher.EnableRaisingEvents = true;
以最小的锁定打开文件
某些应用程序在执行期间保持日志文件打开状态,例如 IIS。 为了使 LogMonitor 能够最好地使用这些类型的应用程序,它使用可能最友好的设置打开日志文件。 在 .NET 中读取文本文件的最简单方法是使用 File.ReadAllText()
方法。 但是,这并不能使用正确的共享标志打开文件。 因此,我使用 File.Open
打开文件并指定访问和共享模式。 然后打开一个 StreamReader
并在该流上使用 ReadToEnd
。 以下是用于读取文件的代码,其中一些与此无关的行已被删除
string newFileLines = "";
using (FileStream stream = File.Open(_fileName,
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader reader = new StreamReader(stream))
{
newFileLines = reader.ReadToEnd();
}
}
历史
- 2007 年 6 月 5 日 - 发布原始版本
- 2007 年 6 月 6 日 - 版本 1.0.0.1
- 修复了大型文件修剪文本的错误。(感谢 s_mom 的捕捉)。