【发布时间】:2013-06-09 22:25:42
【问题描述】:
我们正在为我们的系统设计一个监控解决方案,并且我们正在研究 WMI 作为一个可能的选项。
简而言之,我们希望创建一个通用系统,在该系统中可以订阅 WMI 数据实例中的多个更改。我们正在研究 __InstanceModificationEvent 来执行此操作:
以下原型代码监视任何记事本实例上的所有更改:
void StartMonitor()
{
var query = "SELECT * "
+ "FROM __InstanceModificationEvent "
+ "WITHIN 1 "
+ "WHERE TargetInstance Isa \"Win32_PerfFormattedData_PerfProc_Process\" "
+ "AND TargetInstance.Name = \"notepad\"";
var scope = new ManagementScope(@"root\cimv2", null);
scope.Connect();
EventQuery qry = new EventQuery(query);
ManagementEventWatcher w = new ManagementEventWatcher(scope, qry);
w.EventArrived += EventArrived;
w.Start();
}
void EventArrived(object sender, EventArrivedEventArgs e)
{
var targetInstance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (var p in targetInstance.Properties)
{
Console.WriteLine(p.Name + ":\t" + (p.Value != null ? p.Value.ToString() : "{null}"));
}
}
所以每当记事本的任何实例发生变化时,我们都会得到这样的输出(摘录)
PageFileBytes: 1499136
PageFileBytesPeak: 1740800
PercentPrivilegedTime: 0
PercentProcessorTime: 0
PercentUserTime: 0
PoolNonpagedBytes: 7040
PoolPagedBytes: 172856
这很好,但是我们需要稍微改进一下。例如,假设我们只对 PercentProcessorTime 的更改感兴趣。使用当前代码,只要对象中的 anything 发生更改,就会触发该事件。这还不够好,因为我们可能会监控多台计算机上的数百个进程。
因此,我们需要一种方法来指定我们只希望在这个或那个属性发生变化时触发事件,而不是整个实例
这可以使用 WMI 吗?实现我们想要的最佳实践是什么?
编辑:我知道可以编写如下所示的查询并循环轮询该值,但我们希望避免这种方法。
SELECT PercentProcessorTime
FROM Win32_PerfFormattedData_PerfProc_Process
WHERE Name = "notepad"
【问题讨论】:
-
为什么要避免轮询?无论如何,您基本上都是在使用
WITHIN 1子句进行轮询。 -
System.Management 已经提供了一个通用系统,您可以在其中订阅 WMI 中的更改。我不得不问为什么您要尝试编写一个附加层,该层必须在已经存在的情况下处理任何可能的数据需求。除非您的目标用户是没有 WMI 知识的用户,但听上去您不是。在需要允许您的应用程序只请求他们需要的东西的地方使用 System.Management 有什么问题?尝试为此类功能编写通用接口通常会导致复杂或返回大量不必要的数据,或两者兼而有之。
-
@mikez 说得很好,您可能会注意到我也在询问最佳实践。
-
@Ashigore 数据需要集成到客户端不了解 WMI 的服务器系统中。数据源是在配置时基于通用数据收集器指定的。我们正在使用 WMI 制作一个这样的数据收集器。我们没有这样的“用户”
-
@havardhu 既然如此,你不是已经知道要返回什么数据了吗?因此,仅运行生成该信息所需的 WMI 查询并不是最有效的做法。由于为新数据源编写后端代码的是您,而不是“客户”,您可以利用框架提供的 WMI 接口。
标签: c# .net events wmi monitoring