好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

性能计数器数据收集服务

性能计数器数据收集服务

性能计数器数据收集服务

 

Introducing Musketeer – the performance counter data collector  演示了一个Windows服务收集性能计数器的数据,将性能计数器数据写入Mysql数据库。参照这篇文章,将在Windows服务中直接连接数据库的代码抽离到一个WebAPI服务中,同时把数据库更改为Sql Server。下面简要介绍下我的改造,项目虽小,其中用到了众多的开源项目Topshelf、NLog、Dapper,ASP.NET Web API,Newtonsoft.Json等等:

1、数据库模型,以下是MS SQL Server的模型:

    1:    USE  [PerfmonCounter]
    2:    GO 
    3:   /******  Object :   Table  [dbo].[service_counter_snapshots]    Script  Date : 01/25/2013 22:40:20 ******/
    4:    SET  ANSI_NULLS  ON 
    5:    GO 
    6:    SET  QUOTED_IDENTIFIER  ON 
    7:    GO 
    8:    SET  ANSI_PADDING  ON 
    9:    GO 
   10:    CREATE   TABLE  [dbo].[service_counter_snapshots](
   11:       [Id] [ int ]  IDENTITY (1,1)  NOT   NULL ,
   12:       [ServiceCounterId] [ int ]  NOT   NULL ,
   13:       [SnapshotMachineName] [ varchar ](100)  NULL ,
   14:       [CreationTimeUtc] [datetime]  NOT   NULL ,
   15:       [ServiceCounterValue] [ float ]  NULL ,
   16:    PRIMARY   KEY   CLUSTERED  
   17:   (
   18:       [Id]  ASC 
   19:   ) WITH  (PAD_INDEX  =  OFF , STATISTICS_NORECOMPUTE  =  OFF , IGNORE_DUP_KEY =  OFF , ALLOW_ROW_LOCKS  =  ON , ALLOW_PAGE_LOCKS  =  ON )  ON  [ PRIMARY ]
   20:   )  ON  [ PRIMARY ]
   21:    GO 
   22:    SET  ANSI_PADDING  OFF 
   23:    GO 
   24:   /******  Object :   Table  [dbo].[services]    Script  Date : 01/25/2013 22:40:20 ******/
   25:    SET  ANSI_NULLS  ON 
   26:    GO 
   27:    SET  QUOTED_IDENTIFIER  ON 
   28:    GO 
   29:    SET  ANSI_PADDING  ON 
   30:    GO 
   31:    CREATE   TABLE  [dbo].[services](
   32:       [Name] [ varchar ](100)  NOT   NULL ,
   33:       [DisplayName] [ varchar ](1000)  NULL ,
   34:    PRIMARY   KEY   CLUSTERED  
   35:   (
   36:       [Name]  ASC 
   37:   ) WITH  (PAD_INDEX  =  OFF , STATISTICS_NORECOMPUTE  =  OFF , IGNORE_DUP_KEY =  OFF , ALLOW_ROW_LOCKS  =  ON , ALLOW_PAGE_LOCKS  =  ON )  ON  [ PRIMARY ]
   38:   )  ON  [ PRIMARY ]
   39:    GO 
   40:    SET  ANSI_PADDING  OFF 
   41:    GO 
   42:   /******  Object :   Table  [dbo].[service_counters]    Script  Date : 01/25/2013 22:40:20 ******/
   43:    SET  ANSI_NULLS  ON 
   44:    GO 
   45:    SET  QUOTED_IDENTIFIER  ON 
   46:    GO 
   47:    SET  ANSI_PADDING  ON 
   48:    GO 
   49:    CREATE   TABLE  [dbo].[service_counters](
   50:       [Id] [ int ]  IDENTITY (1,1)  NOT   NULL ,
   51:       [ServiceName] [ varchar ](100)  NOT   NULL ,
   52:       [MachineName] [ varchar ](100)  NULL ,
   53:       [CategoryName] [ varchar ](100)  NOT   NULL ,
   54:       [CounterName] [ varchar ](100)  NOT   NULL ,
   55:       [InstanceName] [ varchar ](100)  NULL ,
   56:       [DisplayName] [ varchar ](1000)  NULL ,
   57:       [DisplayType] [ varchar ](7)  NOT   NULL ,
   58:    PRIMARY   KEY   CLUSTERED  
   59:   (
   60:       [Id]  ASC 
   61:   ) WITH  (PAD_INDEX  =  OFF , STATISTICS_NORECOMPUTE  =  OFF , IGNORE_DUP_KEY =  OFF , ALLOW_ROW_LOCKS  =  ON , ALLOW_PAGE_LOCKS  =  ON )  ON  [ PRIMARY ]
   62:   )  ON  [ PRIMARY ]
   63:    GO 
   64:    SET  ANSI_PADDING  OFF 
   65:    GO 
   66:   /******  Object :   Default  [DF__service_c__Displ__08EA5793]    Script  Date : 01/25/2013 22:40:20 ******/
   67:    ALTER   TABLE  [dbo].[service_counters]  ADD    DEFAULT  ( 'table' )  FOR  [DisplayType]
   68:    GO 
   69:   /******  Object :  ForeignKey [FK__service_c__Servi__09DE7BCC]    Script  Date : 01/25/2013 22:40:20 ******/
   70:    ALTER   TABLE  [dbo].[service_counters]   WITH   CHECK   ADD   FOREIGN   KEY ([ServiceName])
   71:    REFERENCES  [dbo].[services] ([Name])
   72:    GO 

services表  存储我们需要监控的服务的进程。 每个服务都需要监控一系列的性能计数器 (存储在  service_counters  表)。数据收集服务在启动的时候根据 service_counters  表创建  System.Diagnostics.PerformanceCounter  class 的实例列表。 服务每隔一段时间收集一次性能计数器数据并把它存储到 service_counter_snapshots  表。

所有的数据操作通过一个Restful服务接口DataCollectorController 进行操作。

    1:    using  System;
    2:    using  System.Collections.Generic;
    3:    using  System.Linq;
    4:    using  System.Net;
    5:    using  System.Net.Http;
    6:    using  System.Web.Http;
    7:    using  PerformanceCounterCollect.Models;
    8:    using  PerformanceCounterCollect.Web.Models;
    9:    
   10:    namespace  PerformanceCounterCollect.Web.Controllers
   11:   {
   12:        public   class  DataCollectorController : ApiController
   13:       {
   14:            private  ServiceCounterRepository scRepository;
   15:            private  ServiceCounterSnapshotRepository scSnapshotReposity;
   16:    
   17:            public  DataCollectorController()
   18:           {
   19:               scRepository =  new  ServiceCounterRepository();
   20:               scSnapshotReposity =  new  ServiceCounterSnapshotRepository();
   21:           }
   22:    
   23:            // GET api/values/5 
   24:           [HttpGet]
   25:            public  IEnumerable<ServiceCounter> SelectServiceCounter( string  machineName)
   26:           {
   27:                return  scRepository.SelectServiceCounter(machineName);
   28:           }
   29:    
   30:            // POST api/values 
   31:           [HttpPost]
   32:            public  IEnumerable<ServiceCounterSnapshot> SaveServiceSnapshots([FromBody]IEnumerable<ServiceCounterSnapshot>  value )
   33:           {
   34:                return  scSnapshotReposity.SaveServiceSnapshots( value );
   35:           }
   36:       }
   37:         
   38:   }
数据操作使用到了 轻型的ORM类Dapper ,使用了Repository模式。

    1:    using  System;
    2:    using  System.Data;
    3:    using  System.Data.SqlClient;
    4:    using  System.Linq;
    5:    using  System.Web.Configuration;
    6:    using  Dapper;
    7:    
    8:    namespace  PerformanceCounterCollect.Web.Models
    9:   {
   10:        public   abstract   class  BaseRepository
   11:       {
   12:            protected   static   void  SetIdentity<T>(IDbConnection connection, Action<T> setId)
   13:           {
   14:               dynamic identity = connection.Query( "SELECT @@IDENTITY AS Id" ).Single();
   15:               T newId = (T)identity.Id;
   16:               setId(newId);
   17:           }
   18:    
   19:            protected   static  IDbConnection OpenConnection()
   20:           {
   21:               IDbConnection connection =  new  SqlConnection(WebConfigurationManager.ConnectionStrings[ "SqlDiagnosticsDb" ].ConnectionString);
   22:               connection.Open();
   23:                return  connection;
   24:           }
   25:       }
   26:   }
 

    1:    using  System;
    2:    using  System.Collections.Generic;
    3:    using  System.Data;
    4:    using  System.Linq;
    5:    using  System.Web;
    6:    using  Dapper;
    7:    using  PerformanceCounterCollect.Models;
    8:    
    9:    
   10:    namespace  PerformanceCounterCollect.Web.Models
   11:   {
   12:        public   class  ServiceCounterRepository : BaseRepository
   13:       {
   14:            public  IEnumerable<ServiceCounter> SelectServiceCounter( string  machineName)
   15:           {
   16:                using  (IDbConnection connection = OpenConnection())
   17:               {
   18:                    string  query =  "select Id,ServiceName,CategoryName,CounterName,InstanceName from service_counters where MachineName=@MachineName" ;
   19:                    return  connection.Query<ServiceCounter>(query,  new  { MachineName = machineName });
   20:               }
   21:           }
   22:    
   23:    
   24:       }
   25:   }

 

 

    1:    using  System;
    2:    using  System.Collections.Generic;
    3:    using  System.Data;
    4:    using  System.Linq;
    5:    using  System.Web;
    6:    using  Dapper;
    7:    using  PerformanceCounterCollect.Models;
    8:    
    9:    namespace  PerformanceCounterCollect.Web.Models
   10:   {
   11:        public   class  ServiceCounterSnapshotRepository: BaseRepository
   12:       {
   13:            public  IEnumerable<ServiceCounterSnapshot> SaveServiceSnapshots(IEnumerable<ServiceCounterSnapshot> snapshots)
   14:           {
   15:                using  (IDbConnection connection = OpenConnection())
   16:               {
   17:                    foreach  (var snapshot  in  snapshots)
   18:                   {
   19:                        // insert new snapshot to the database 
   20:                        int  retVal = connection.Execute(
   21:        @"insert into service_counter_snapshots(ServiceCounterId,SnapshotMachineName,CreationTimeUtc,ServiceCounterValue) values ( 
   22:           @ServiceCounterId,@SnapshotMachineName,@CreationTimeUtc,@ServiceCounterValue)", snapshot);
   23:                       SetIdentity< int >(connection, id => snapshot.Id = id);
   24:                   }
   25:               }
   26:                return  snapshots;
   27:           }
   28:       }
   29:   }

2、监控服务,也就是数据收集代理程序Monitoring Service:

    1:    using  System;
    2:    using  System.Collections.Generic;
    3:    using  System.Linq;
    4:    using  System.Text;
    5:    using  System.Threading;
    6:    using  System.Threading.Tasks;
    7:    using  Topshelf;
    8:    using  Topshelf.Logging;
    9:    
   10:    namespace  PerformanceCounterCollect.Services
   11:   {
   12:        class  PerfmonWorker: ServiceControl
   13:       {
   14:            private   readonly  LogWriter logger = HostLogger.Get<PerfmonWorker>();
   15:            public   static   bool  ShouldStop { get;  private  set; }
   16:            private  ManualResetEvent stopHandle;
   17:    
   18:            public   bool  Start(HostControl hostControl)
   19:           {
   20:               logger.Info( "Starting PerfmonWorker..." );
   21:    
   22:               stopHandle =  new  ManualResetEvent( false );
   23:    
   24:               ThreadPool.QueueUserWorkItem( new  ServiceMonitor().Monitor, stopHandle);
   25:    
   26:                return   true ;
   27:           }
   28:    
   29:            public   bool  Stop(HostControl hostControl)
   30:           {
   31:               ShouldStop =  true ;
   32:               logger.Info( "Stopping PerfmonWorker..." );
   33:                // wait for all threads to finish 
   34:               stopHandle.WaitOne(ServiceMonitor.SleepIntervalInMilliSecs + 10);
   35:    
   36:                return   true ;
   37:           }
   38:       }
   39:     
   40:   }

服务使用了Topshelf和NLog,具体参看《 使用Topshelf 5步创建Windows 服务 》。在服务启动的时候开启监控线程,执行方法 ServiceMonitor.Monitor:

    1:    using  System;
    2:    using  System.Collections.Generic;
    3:    using  System.Diagnostics;
    4:    using  System.Linq;
    5:    using  System.Text;
    6:    using  System.Threading;
    7:    using  System.Threading.Tasks;
    8:    using  PerformanceCounterCollect.Models;
    9:    using  Topshelf.Logging;
   10:    
   11:    namespace  PerformanceCounterCollect.Services
   12:   {
   13:        sealed   class  ServiceMonitor
   14:       {
   15:            public   const   int  SleepIntervalInMilliSecs = 50000;
   16:    
   17:            private   readonly  LogWriter logger = HostLogger.Get<ServiceMonitor>();
   18:            private  IList<Tuple< int , PerformanceCounter>> serviceCounters;
   19:    
   20:            public   void  Monitor( object  state)
   21:           {
   22:               ManualResetEvent stopHandle = (ManualResetEvent)state;
   23:               String machineName = Environment.MachineName;
   24:                try 
   25:               {
   26:                   Initialize(machineName);
   27:                   var snapshots =  new  ServiceCounterSnapshot[serviceCounters.Count];
   28:    
   29:                    while  (!PerfmonWorker.ShouldStop)
   30:                   {
   31:                       Thread.Sleep(SleepIntervalInMilliSecs);
   32:    
   33:                        // this would be our timestamp value by which we will group the snapshots 
   34:                       DateTime timeStamp = DateTime.UtcNow;
   35:                        // collect snapshots 
   36:                        for  ( int  i = 0; i < serviceCounters.Count; i++)
   37:                       {
   38:                           var snapshot =  new  ServiceCounterSnapshot();
   39:                           snapshot.CreationTimeUtc = timeStamp;
   40:                           snapshot.SnapshotMachineName = machineName;
   41:                           snapshot.ServiceCounterId = serviceCounters[i].Item1;
   42:                            try 
   43:                           {
   44:                               snapshot.ServiceCounterValue = serviceCounters[i].Item2.NextValue();
   45:                               logger.DebugFormat( "Performance counter {0} read value: {1}" , GetPerfCounterPath(serviceCounters[i].Item2),
   46:                                                   snapshot.ServiceCounterValue);
   47:                           }
   48:                            catch  (InvalidOperationException)
   49:                           {
   50:                               snapshot.ServiceCounterValue =  null ;
   51:                               logger.DebugFormat( "Performance counter {0} didn't send any value." , GetPerfCounterPath(serviceCounters[i].Item2));
   52:                           }
   53:                           snapshots[i] = snapshot;
   54:                       }
   55:                       SaveServiceSnapshots(snapshots);
   56:                   }
   57:               }
   58:                finally 
   59:               {
   60:                   stopHandle.Set();
   61:               }
   62:           }
   63:    
   64:            private   void  Initialize(String machineName)
   65:           {
   66:                try 
   67:               {
   68:                   var counters =  new  List<Tuple< int , PerformanceCounter>>();
   69:    
   70:                    foreach  (var counter  in  PerfmonClient.SelectServiceCounter(machineName))
   71:                   {
   72:                       logger.InfoFormat( @"Creating performance counter: {0}\{1}\{2}\{3}" , counter.MachineName ??  "." , counter.CategoryName,
   73:                                           counter.CounterName, counter.InstanceName);
   74:                       var perfCounter =  new  PerformanceCounter(counter.CategoryName, counter.CounterName, counter.InstanceName, counter.MachineName ??  "." );
   75:                       counters.Add( new  Tuple< int , PerformanceCounter>(counter.Id, perfCounter));
   76:                        // first value doesn't matter so we should call the counter at least once 
   77:                        try  { perfCounter.NextValue(); }
   78:                        catch  { }
   79:                   }
   80:                  
   81:    
   82:                   serviceCounters = counters;
   83:               }
   84:                catch  (Exception ex)
   85:               {
   86:                   logger.Error(ex);
   87:               }
   88:           }
   89:    
   90:            private   void  SaveServiceSnapshots(IEnumerable<ServiceCounterSnapshot> snapshots)
   91:           {
   92:               PerfmonClient.SaveServiceSnapshots(snapshots);
   93:           }
   94:    
   95:            private  String GetPerfCounterPath(PerformanceCounter cnt)
   96:           {
   97:                return  String.Format( @"{0}\{1}\{2}\{3}" , cnt.MachineName, cnt.CategoryName, cnt.CounterName, cnt.InstanceName);
   98:           }
   99:       }
  100:   }

在 Monitor  方法中初始化完要采集的性能计数器实例后开启一个主循环,定期的收集数据,如果相关的性能计数器实例没有运行,计数器将会抛出 InvalidOperationException  我们就把它设置为null。数据集的数据通过WebAPI发回服务器端存储,这样就可以实现性能计数器的集中存储了。

3、使用方法

使用很简单,首先定义我们要收集的数据

insert into services values ('notepad', 'notepad process test');

insert into service_counters values ( 'notepad', ‘GEFFZHANG-PC’, 'process', '% Processor Time', 'notepad', null, 'graph');

insert into service_counters values ( 'notepad', ‘GEFFZHANG-PC’, 'process', 'working set', 'notepad', null, 'graph');

然后启动我们的性能计数器收集服务

代码参见项目  https://github.com/geffzhang/PerformanceCounterCollect/tree/6279cfab351b0c1b92f65db36247fcb7371816c5

作者:  自由、创新、研究、探索……
出处: http://shanyou.cnblogs.com/
版权:本文版权归作者和博客园共有
转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】,谢谢
要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任 

翻译此页 阿拉伯语 爱沙尼亚语 白苗语 保加利亚语 波兰语 波斯语 朝鲜语 丹麦语 德语 俄语 法语 繁体中文 芬兰语 海地克里奥尔语 荷兰语 加泰隆语 捷克语 拉脱维亚语 立陶宛语 罗马尼亚 挪威语 葡萄牙语 日语 瑞典语 斯洛伐克语 斯洛文尼亚语 泰语 土耳其语 乌克兰语 西班牙语 希伯来语 希腊语 匈牙利语 意大利语 印地语 印度尼西亚语 英语 越南语

Microsoft ®  Translator

 

分类:  企业解决方案 ,  ASP.NET Web API

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于性能计数器数据收集服务的详细内容...

  阅读:33次