蛙蛙推荐:编写一个服务监控及管理的软件
点击次数:26 次 发布日期:2008-11-26 22:26:29 作者:源代码网
|
源代码网推荐 蛙蛙推荐:编写一个服务监控的软件 源代码网推荐 源代码网推荐 如果一个服务被部署到了几十台机器上,我们往往需要每天花费很多的时间去查看每台机器上的服务的运行状况,虽然微软有MOM(Microsoft Operations Manager)和SMS(Systems Management Server),但处于成本上及其它方面的考虑,好多时候我们还用不上这些东西,其实微软公开了好多管理和监控方面的API和工具,比如WMIC,System.Managerment等,把这些零散的API和工具集中起来,便可以开发一些满足自定义需求的小软件。 源代码网推荐 源代码网推荐 我们要实现以下任务 源代码网推荐 1、确认指定的进程已启动 源代码网推荐 2、获取指定机器,指定进程的CPU、内存、线程使用情况 源代码网推荐 3、确认指定机器的指定端口在监听 源代码网推荐 4、获取指定机器指定计数器的情况 源代码网推荐 5、获取指定机器上的系统日志/应用日志 源代码网推荐 6、获取指定服务相关trace 源代码网推荐 7、确认指定服务的功能拨测能通过 源代码网推荐 8、抓取指定机器指定进程的dump 源代码网推荐 9、在指定机器上进行网络抓包 源代码网推荐 10、重启指定机器上的某服务,某应用程序进程池等 源代码网推荐 源代码网推荐 下面来一一考虑一下 源代码网推荐 1、确认指定的进程已启动 源代码网推荐 可以用WMI接口来获取远程机器的进程列表,然后遍历这个列表,确认指定服务的进程名字是否在这个列表里,核心代码(来自网络)如下: 源代码网推荐 源代码网推荐 源代码网推荐 public static DataTable RunningProcesses() 源代码网推荐 { 源代码网推荐 源代码网推荐 // The second way of constructing a query 源代码网推荐 string queryString = 源代码网推荐 "Select Name, ProcessId, Caption, ExecutablePath" + 源代码网推荐 " FROM Win32_Process"; 源代码网推荐 源代码网推荐 SelectQuery query = new SelectQuery(queryString); 源代码网推荐 ConnectionOptions options = new ConnectionOptions(); 源代码网推荐 options.Username = @"administrator"; 源代码网推荐 options.Password = ""; 源代码网推荐 源代码网推荐 源代码网推荐 ManagementScope scope = new System.Management.ManagementScope(@"\. ootCIMV2"); 源代码网推荐 scope.Connect(); 源代码网推荐 源代码网推荐 ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query); 源代码网推荐 ManagementObjectCollection processes = searcher.Get(); 源代码网推荐 源代码网推荐 DataTable result = new DataTable(); 源代码网推荐 result.Columns.Add("Name", Type.GetType("System.String")); 源代码网推荐 result.Columns.Add("ProcessId", Type.GetType("System.Int32")); 源代码网推荐 result.Columns.Add("Caption", Type.GetType("System.String")); 源代码网推荐 result.Columns.Add("Path", Type.GetType("System.String")); 源代码网推荐 源代码网推荐 foreach (ManagementObject mo in processes) 源代码网推荐 { 源代码网推荐 DataRow row = result.NewRow(); 源代码网推荐 row["Name"] = mo["Name"].ToString(); 源代码网推荐 row["ProcessId"] = Convert.ToInt32(mo["ProcessId"]); 源代码网推荐 if (mo["Caption"] != null) 源代码网推荐 row["Caption"] = mo["Caption"].ToString(); 源代码网推荐 if (mo["ExecutablePath"] != null) 源代码网推荐 row["Path"] = mo["ExecutablePath"].ToString(); 源代码网推荐 result.Rows.Add(row); 源代码网推荐 } 源代码网推荐 return result; 源代码网推荐 } 源代码网推荐 2、获取指定机器,指定进程的CPU、内存、线程使用情况 源代码网推荐 这几样数据,我们用计数器来获取,具体表格如下 源代码网推荐 某进程的CPU使用量:process类别下的% Processor Time,实例名是你服务的进程名字(不加后缀名) 源代码网推荐 某进程的内存使用量:process类别下的Private Bytes,实例名是你服务的进程名字(不加后缀名) 源代码网推荐 某进程的内存使用量:process类别下的Thread Count,实例名是你服务的进程名字(不加后缀名) 源代码网推荐 其它的计数器的说明请打开perfmon工具一个一个看每个计数器的说明文字 源代码网推荐 关于获取某机器某计数器数值的代码大约如下 源代码网推荐 源代码网推荐 源代码网推荐 public class PerfCounter 源代码网推荐 { 源代码网推荐 public PerfCounter(string categoryName, 源代码网推荐 string counterName, 源代码网推荐 string instanceName, 源代码网推荐 string machineName 源代码网推荐 ) 源代码网推荐 { 源代码网推荐 this.categoryName = categoryName; 源代码网推荐 this.counterName = counterName; 源代码网推荐 this.instanceName = instanceName; 源代码网推荐 this.machineName = machineName; 源代码网推荐 } 源代码网推荐 源代码网推荐 public string categoryName; 源代码网推荐 public string counterName; 源代码网推荐 public string instanceName; 源代码网推荐 public string machineName; 源代码网推荐 } 源代码网推荐 public class PerfCounterHelper 源代码网推荐 { 源代码网推荐 public static string GetPerfCount(List<PerfCounter> counters) 源代码网推荐 { 源代码网推荐 List<PerformanceCounter> pcs = new List<PerformanceCounter>(); 源代码网推荐 foreach (PerfCounter counter in counters) 源代码网推荐 { 源代码网推荐 pcs.Add(new PerformanceCounter(counter.categoryName, 源代码网推荐 counter.counterName, 源代码网推荐 counter.instanceName, 源代码网推荐 counter.machineName)); 源代码网推荐 } 源代码网推荐 StringBuilder text = new StringBuilder(); 源代码网推荐 try 源代码网推荐 { 源代码网推荐 int i = 0; 源代码网推荐 while(true) 源代码网推荐 { 源代码网推荐 Thread.Sleep(1000); 源代码网推荐 i++; 源代码网推荐 text.AppendFormat("第{0}次采样 ", i); 源代码网推荐 foreach (PerformanceCounter pc in pcs) 源代码网推荐 { 源代码网推荐 text.AppendFormat("{0} {1} {2} ",pc.CounterName,pc.InstanceName, pc.NextValue()); 源代码网推荐 } 源代码网推荐 if (i > 3) break; 源代码网推荐 } 源代码网推荐 } 源代码网推荐 catch (Exception ex) 源代码网推荐 { 源代码网推荐 Trace.WriteLine(ex); 源代码网推荐 } 源代码网推荐 finally 源代码网推荐 { 源代码网推荐 foreach (PerformanceCounter pc in pcs) 源代码网推荐 { 源代码网推荐 pc.Close(); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 return text.ToString(); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 使用如下 源代码网推荐 源代码网推荐 源代码网推荐 List<PerfCounter> counters = new List<PerfCounter>(); 源代码网推荐 counters.Add(new PerfCounter("Processor", "% Processor Time", "_Total", ".")); 源代码网推荐 counters.Add(new PerfCounter("Memory", "Pages/sec", "", ".")); 源代码网推荐 Console.WriteLine(PerfCounterHelper.GetPerfCount(counters)); 源代码网推荐 源代码网推荐 源代码网推荐 其实获取每个进程的内存,线程,CPU等信息,用WMI查询Win32_Process也可以得到,但像CPU等信息还要往出算,所以简单的办法就是通过计数器获取了 源代码网推荐 源代码网推荐 3、确认指定机器的指定端口在监听 源代码网推荐 一般提供网络接口的服务都要监听一个或者几个端口,我们手工来确认端口是否监听的时候一般是登录到那台机器上运行netstat -na | find "LISTENING"来查看输出,或者在本机上用telnet 192.168.0.1 80来看是否能打开,其实我们用程序也能调用者两个命令,但是调用远程机器上的netstat命令,你一般没办法获取它的输出,通常的办法是把输出结果用命名管道重定向到某个文件,然后以编程的方式去访问网络路径去取这个文本文件并读取文本,这种方式太麻烦。而以编程的方式调用telnet需要交互,也很麻烦,所以我们用socket来建立一个连接来测试远程端口是否在监听,大约如下 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 public static bool IsListenPort(string remoteHost, int port) 源代码网推荐 { 源代码网推荐 Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 源代码网推荐 try 源代码网推荐 { 源代码网推荐 s.Connect(Dns.GetHostAddresses(remoteHost)[0], port); 源代码网推荐 } 源代码网推荐 catch (Exception ex) 源代码网推荐 { 源代码网推荐 return false; 源代码网推荐 } 源代码网推荐 finally 源代码网推荐 { 源代码网推荐 s.Close(); 源代码网推荐 } 源代码网推荐 return true; 源代码网推荐 } 源代码网推荐 调用ping和telnet的代码大概如下,其中telnet可能没价值,如果真要模拟telnet,可以下载个开源的telnet client的.net实现 源代码网推荐 源代码网推荐 源代码网推荐 public static string ping(string remoteHost) 源代码网推荐 { 源代码网推荐 Process proc = new Process(); 源代码网推荐 proc.StartInfo.FileName = "ping.exe"; 源代码网推荐 proc.StartInfo.Arguments = remoteHost; 源代码网推荐 proc.StartInfo.UseShellExecute = false; 源代码网推荐 proc.StartInfo.RedirectStandardOutput = true; 源代码网推荐 proc.Start(); 源代码网推荐 return proc.StandardOutput.ReadToEnd(); 源代码网推荐 } 源代码网推荐 public static string Telnet(string remoteHost, int port) 源代码网推荐 { 源代码网推荐 Process proc = new Process(); 源代码网推荐 proc.StartInfo.FileName = "telnet.exe"; 源代码网推荐 proc.StartInfo.Arguments = string.Format("{0} {1}",remoteHost, port); 源代码网推荐 proc.StartInfo.UseShellExecute = false; 源代码网推荐 proc.StartInfo.RedirectStandardOutput = true; 源代码网推荐 proc.Start(); 源代码网推荐 return proc.StandardOutput.ReadToEnd(); 源代码网推荐 } 源代码网推荐 源代码网推荐 源代码网推荐 如果要获取某台机器上的网络链接情况,可以调用GetTcpTable的win32 API,因为执行这个任务我们一般是用netstat命令,而且我没有找到使用wmi获取类似netstat输出的接口,当然,GetTcpTable也不能远程执行。如果谁找到在A机器上执行B机器上的命令行程序并获取标准输出的方法请告诉我。 源代码网推荐 源代码网推荐 4、获取指定机器指定计数器的情况 源代码网推荐 具体做法上面已经发过了,只是有时候我们要查看一些服务的业务逻辑方面的计数器,关于创建自定义计数器,可以参考以下链接 源代码网推荐 http://www.cnblogs.com/onlytiancai/archive/2007/09/24/902310.html 源代码网推荐 源代码网推荐 5、获取指定机器上的系统日志/应用日志 源代码网推荐 我们一般获取最近一段时间的日志来看是否正常,代码如下(用WMI也可以应该) 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 public class EventLogHelper 源代码网推荐 { 源代码网推荐 public string GetEventLog(List<string> machines) 源代码网推荐 { 源代码网推荐 StringBuilder sb = new StringBuilder(); 源代码网推荐 源代码网推荐 foreach (string mache in machines) 源代码网推荐 { 源代码网推荐 try 源代码网推荐 { 源代码网推荐 getLog(sb, mache); 源代码网推荐 Console.WriteLine("process {0} finished", mache); 源代码网推荐 } 源代码网推荐 catch (Exception ex) 源代码网推荐 { 源代码网推荐 Console.WriteLine(ex); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 return sb.ToString(); 源代码网推荐 } 源代码网推荐 源代码网推荐 private void getLog(StringBuilder sb, string machine) 源代码网推荐 { 源代码网推荐 sb.AppendFormat("<h3>{0} "s EventLog</h3>", machine); 源代码网推荐 EventLog myLog = new EventLog("Application", machine); 源代码网推荐 源代码网推荐 for (int x = myLog.Entries.Count - 1; x >= 0; x--) 源代码网推荐 { 源代码网推荐 EventLogEntry entry = myLog.Entries[x]; 源代码网推荐 源代码网推荐 if (entry.TimeGenerated < DateTime.Now.AddDays(-1)) 源代码网推荐 { 源代码网推荐 break; 源代码网推荐 } 源代码网推荐 switch (entry.EntryType) 源代码网推荐 { 源代码网推荐 case EventLogEntryType.Error: 源代码网推荐 sb.AppendFormat("<p><font color="red">{0}-{1}</font></p>", entry.TimeGenerated, entry.Message); 源代码网推荐 break; 源代码网推荐 case EventLogEntryType.Warning: 源代码网推荐 sb.AppendFormat("<p><font color="yellow">{0}-{1}</font></p>", entry.TimeGenerated, entry.Message); 源代码网推荐 break; 源代码网推荐 default: 源代码网推荐 sb.AppendFormat("<p><font color="black">{0}-{1}</font></p>", entry.TimeGenerated, entry.Message); 源代码网推荐 break; 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 源代码网推荐 6、获取指定服务相关trace 源代码网推荐 trace一般都是写入本机的一些文本文件或者集中写入的一个trace数据库,trace一般都会有机器名,服务名等,根据这些条件去找到文本trace的路径然后用streamreader读取,或者用SqlDataAdapter来获取数据库里的trace记录。具体代码就不写了。 源代码网推荐 源代码网推荐 7、确认指定服务的功能测试能通过 源代码网推荐 我们可以把功能测试的代码封装成一个console程序,然后以编程的方式去执行,然后获取这些输出,输出结果应类似:“a用例通过,b用例出错。。。”,关于执行外部程序可以参考上文中调用ping的代码,如果你的服务只能在本机测试,要先部署在远程机器上,然后用WMI远程执行它,并把测试结果用网络API发给你。 源代码网推荐 源代码网推荐 8、抓取指定机器指定进程的dump 源代码网推荐 这需要执行远程机器上的程序,实现在所有的服务器上装好windbg,并约定好路径,抓网络包也要实现装好Wireshark。用WMI执行程序的代码大约如下,下面的代码没有写管理作用域,如果要加的话参考上面的代码 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 public static void Execute(string command) 源代码网推荐 { 源代码网推荐 //Get the object on which the method will be invoked 源代码网推荐 ManagementClass processClass = new ManagementClass("Win32_Process"); 源代码网推荐 源代码网推荐 //Get an input parameters object for this method 源代码网推荐 ManagementBaseObject inParams = processClass.GetMethodParameters("Create"); 源代码网推荐 源代码网推荐 //Fill in input parameter values 源代码网推荐 inParams["CommandLine"] = command; 源代码网推荐 源代码网推荐 //Execute the method 源代码网推荐 ManagementBaseObject outParams = processClass.InvokeMethod("Create",inParams, null); 源代码网推荐 源代码网推荐 Console.WriteLine(outParams.GetText(TextFormat.Mof)); 源代码网推荐 //Display results 源代码网推荐 //Note: The return code of the method is provided in the "returnvalue" property of the outParams object 源代码网推荐 Console.WriteLine("Creation of calculator process returned: " + outParams["returnvalue"]); 源代码网推荐 Console.WriteLine("Process ID: " + outParams["processId"]); 源代码网推荐 } 源代码网推荐 源代码网推荐 源代码网推荐 可以先用Wmi获取远程机器上服务的PID,然后远程执行"adplus -hang -p 2233 -quiet -o d:dumps",然后可以以编程的方式通过网络共享把dump拷贝到本地。 源代码网推荐 源代码网推荐 9、在指定机器上进行网络抓包 源代码网推荐 具体方式和抓dump差不多,实现要在远程机器上装好Wireshark,命令行模式抓包大概如下 源代码网推荐 at 14:33 "C:Program FilesWiresharkdumpcap.exe" -i 2 -a duration:604800 -b files:1000 -f "host 10.0.0.1 and port 8081" -b filesize:10240 -w d: etwork_dump1.cap 源代码网推荐 源代码网推荐 具体参数参考wireshare的帮助,这是起一个任务去抓,你可以把at命令去了,也许你的服务器有多个网卡,所以实现要指定好要抓包的网卡,获取远程机器网卡信息的vbs代码如下,请自己修改为C# 源代码网推荐 源代码网推荐 On Error Resume Next 源代码网推荐 源代码网推荐 strComputer = "." 源代码网推荐 Set objWMIService = GetObject("winmgmts:" _ 源代码网推荐 & "{impersonationLevel=impersonate}!\" & strComputer & " ootcimv2") 源代码网推荐 源代码网推荐 Set colItems = objWMIService.ExecQuery("Select * from Win32_NetworkAdapter where NetConnectionStatus =2") 源代码网推荐 源代码网推荐 For Each objItem in colItems 源代码网推荐 Wscript.Echo "Name: " & objItem.Name 源代码网推荐 Next 源代码网推荐 dumpcap.exe的-i参数解释如下,有了网络适配器的名字或者索引就可以抓包了 源代码网推荐 -i <interface> name or idx of interface (def: first none loopback) 源代码网推荐 源代码网推荐 源代码网推荐 10、重启指定机器上的某服务,某应用程序进程池等 源代码网推荐 重启服务可以先停止,后启动,wmic命令如下,可用程序来执行 源代码网推荐 ::停止spooler服务 源代码网推荐 wmic SERVICE where name="Spooler" call stopservice 源代码网推荐 ::运行spooler服务 源代码网推荐 wmic SERVICE where name="Spooler" call startservice 源代码网推荐 获取某web应用的应用程序池的代码如下 源代码网推荐 源代码网推荐 strComputer = "." 源代码网推荐 Set objWMIService = GetObject("winmgmts:\" & strComputer & " ootMicrosoftIISv2") 源代码网推荐 Set colItems = objWMIService.ExecQuery( _ 源代码网推荐 "SELECT * FROM IIsWebVirtualDirSetting",,48) 源代码网推荐 For Each objItem in colItems 源代码网推荐 Wscript.Echo "Name: " & objItem.Name & " -> Pool: " & objItem.AppPoolId 源代码网推荐 Next 源代码网推荐 获取后就可以进行对指定应用程序池的回收操作了,回收应用程序进程池代码大约如下,来自网络,未测试 源代码网推荐 源代码网推荐 源代码网推荐 internal class RecycleAppPool 源代码网推荐 { 源代码网推荐 private static void Main(string[] args) 源代码网推荐 { 源代码网推荐 ManagementScope scope = new ManagementScope("root\MicrosoftIISv2"); 源代码网推荐 scope.Connect(); 源代码网推荐 ManagementObject appPool = 源代码网推荐 new ManagementObject(scope, 源代码网推荐 new ManagementPath("IIsApplicationPool.Name="W3SVC/AppPools/DefaultAppPool""), null); 源代码网推荐 appPool.InvokeMethod("Recycle", null, null); 源代码网推荐 Console.WriteLine("Recycled DefaultAppPool"); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 源代码网推荐 更多的IIS管理操作可以使用Adsutil.vbs 源代码网推荐 源代码网推荐 这以上的一切都是为了集中的管理,而不用一个一个的登录到远程机器上去操作。综合以上这些东西,可以写一个综合的管理工具,在一条机器上就可以管理几十台机器,获取某几台机器的运行状况报表,远程重启多台服务器的某服务等。 源代码网推荐 源代码网推荐 WMIC:从命令行对Windows的全面管理 源代码网推荐 http://www.yesky.com/20030424/1665552.shtml 源代码网推荐 WMIC Process Call Create 源代码网推荐 http://wmug.co.uk/blogs/r0b/archive/2007/10/12/wmic-process-call-create.aspx 源代码网推荐 WMIC 全新的超级命令行管理工具 源代码网推荐 http://tech.sina.com.cn/other/2003-05-20/1702189076.shtml 源代码网推荐 一些wmic例子 源代码网推荐 http://blog.vkill.net/read.php?41 源代码网推荐 Can one recycle an application from a script in IIS 6.0? 源代码网推荐 http://blogs.iis.net/chrisad/archive/2006/08/30/Recycling-Application-Pools-using-WMI-in-IIS-6.0.aspx 源代码网推荐 关于 WMIC 的使用 源代码网推荐 http://bbs.hackerxfiles.net/viewthread.php?tid=91580 源代码网推荐 源代码网推荐 源代码网推荐 做人要厚道,请注明转自酷网动力(www.ASPCOOL.COM)。 源代码网推荐 源代码网供稿. |
