蛙蛙池塘  
人生价值的最好体现就是做好本职工作...
公告
  • 残荷听雨,梨花飞雪,落英缤纷时节。晓来谁染枫林醉?点点都是离人泪
    活着,就是快乐!自信,就是美丽! 有人爱,就是幸福。
    春天来了
    但愿野百合也有春天

    第三季度的计划



    木了
    怎么抓w3wp的dump? 10-11 14:36
日历
<2008年2月>
272829303112
3456789
10111213141516
17181920212223
2425262728291
2345678
统计
  • 随笔 - 194
  • 文章 - 2
  • 评论 - 1775
  • 引用 - 68

导航

与我联系

搜索

 

常用链接

留言簿(45)

我参加的小组

我参与的团队

我的标签

随笔分类

随笔档案

相册

朋友

积分与排名

  • 积分 - 419725
  • 排名 - 51

最新评论

阅读排行榜

评论排行榜

60天内阅读排行

 

蛙蛙推荐:编写一个服务监控的软件

如果一个服务被部署到了几十台机器上,我们往往需要每天花费很多的时间去查看每台机器上的服务的运行状况,虽然微软有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(@"\\.\root\CIMV2"
);
    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}次采样\r\n"
, i);
                
foreach (PerformanceCounter pc in
 pcs)
                
{
                    text.AppendFormat(
"{0} \t{1}\t{2} \r\n"
,pc.CounterName,pc.InstanceName, pc.NextValue());
                }

                
if (i > 3break;
            }

        }

        
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);