问题
We are designing a monitoring solution for our system, and we're looking into WMI as a possible option.
In short, we want to create a generic system where it shall be possible to subscribe to multiple changes in WMI data instances. We're looking into the __InstanceModificationEvent to do this:
The following prototype code monitors all changes on any instance of notepad:
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}"));
}
}
So whenever any instance of notepad is changes, we will get an output like this (excerpt)
PageFileBytes: 1499136
PageFileBytesPeak: 1740800
PercentPrivilegedTime: 0
PercentProcessorTime: 0
PercentUserTime: 0
PoolNonpagedBytes: 7040
PoolPagedBytes: 172856
This is fine, however we need to improve this a bit. For example, let's pretend we are only interested in the changes to PercentProcessorTime. With the current code, the event will be fired whenever anything in the object changes. This is not good enough, because we might monitor hundreds of processes across multiple computers.
Thus, we need a way to specify that we only want the event to be triggered whenever this or that property changes, not the entire instance
Is this possible using WMI? What's the best practice to achieve what we want?
Edit: I know that it is possible to write a query such as the one below and cycically poll for the value, however we were hoping to avoid that approach.
SELECT PercentProcessorTime
FROM Win32_PerfFormattedData_PerfProc_Process
WHERE Name = "notepad"
回答1:
The __InstanceModificationEvent
has a reference to the previous instance so you might be able to compare values between the PreviousInstance
and TargetInstance
. For example, to filter for PercentProcessorTime changes:
var query = "SELECT * "
+ "FROM __InstanceModificationEvent "
+ "WITHIN 1 "
+ "WHERE TargetInstance Isa \"Win32_PerfFormattedData_PerfProc_Process\" "
+ "AND TargetInstance.Name = \"notepad\" "
+ "AND PreviousInstance.PercentProcessorTime != TargetInstance.PercentProcessorTime ";
来源:https://stackoverflow.com/questions/17014765/wmi-instancemodificationevent-filtering