本文装载自:http://it.dianping.com/using_attribute_wrapping_performance_counter.htm
为要使用性能计数器对程序做监控,所以去MSDN查了一下性能计数器的实现,看完第一个感觉就是。。好麻烦。。如果要用计数器,要实现以下几步:
- 新建计数器分类
- 新建计数器集
- 新建计数器
- 创建计数器实例
- 初始化计数器实例
- 使用计数器实例
我想如果对于开发人员来说,为了实现监控,要写那么一大坨初始化代码,肯定晕倒。。所以有必要对性能计数器的实现做一下封装,让开发变得更加方便简单。
网上也看了很多种计数器的封装实现,大多是用工厂模式进行的封装,但感觉还是会有一定的冗余代码。于是尝试了一下使用Attribute方式进行封装,感觉效果还不错,所以和大家分享一下。
我预期的效果是这样的,首先是定义计数器集:
Code
[CounterCategory("test")]
class XCounters
{
[CounterUnit("x", "value x", PerformanceCounterType.NumberOfItems64)]
public PerformanceCounter x;
[CounterUnit("y", "value y", PerformanceCounterType.RateOfCountsPerSecond64)]
public PerformanceCounter y;
}
通过Attribute,我希望达到以上这样的结果,即可以定义计数器分类名,以及分类下每个计数器的名字,描述和计数器类型。
然后是使用:
Code
CounterContainer.Register<XCounters>();
XCounters counter = DPCounterContainer.Resolve<XCounters>();
for (int i = 0; i < 10000000; i++)
{
counter.x.Increment();
counter.y.Increment();
Thread.Sleep(300);
}
第一句话是将XCounter在Container里注册,由Container负责把XCounter里定义的计数器分类,计数器集进行创建初始化绑定工作。
第二句话是从Container里获取到XCounter计数器集的实例。
第三第四句话就是对计数器的使用。每隔0.3秒,x,y计数器加1。最后运行的效果如下:
所以进行了封装以后,开发人员需要关注只是计数器集的定义和使用,而不必关心那一大坨恶心的初始化代码。
那以上的效果实现的话,Container到底是如何实现的呢,我们再继续讨论下去:
其实最关键的就是Container的Register函数了,请看实现:
Code
public static bool Register<T>() where T : class, new()
{
//取得category名字
object[] attribs = typeof(T).GetCustomAttributes(typeof(CounterCategoryAttribute), false);
if (attribs.Length == 0) return false;
CounterCategoryAttribute attr = (CounterCategoryAttribute)attribs[0];
string category = attr.Name;
//检查category是否已存在
bool countersExist = PerformanceCounterCategory.Exists(category);
//如果不存在,需要创建
if (countersExist == false)
{
//创建一个计数器集
CounterCreationDataCollection list = new CounterCreationDataCollection();
foreach (FieldInfo prop in typeof(T).GetFields())
{
attribs = prop.GetCustomAttributes(typeof(CounterUnitAttribute), false);
foreach (CounterUnitAttribute fieldAttrib in attribs)
{
//创建计数器
CounterCreationData data = new CounterCreationData();
data.CounterName = fieldAttrib.Name;
data.CounterHelp = fieldAttrib.Help;
data.CounterType = fieldAttrib.Type;
//加入计数器集
list.Add(data);
}
}
//创建category和计数器集
PerformanceCounterCategory.Create(category, "", PerformanceCounterCategoryType.SingleInstance, list);
}
//创建并绑定计数器实例
T instance = new T();
foreach (FieldInfo prop in typeof(T).GetFields())
{
attribs = prop.GetCustomAttributes(typeof(CounterUnitAttribute), false);
foreach (CounterUnitAttribute fieldAttrib in attribs)
{
PerformanceCounter pc = new PerformanceCounter(category, fieldAttrib.Name, "",false);
pc.RawValue = 0;
prop.SetValue(instance, pc);
}
}
//存入hash表中,供Resolve函数读取
_cntList.Add(typeof(T),instance);
return true;
}
通过这样的封装,大部分的重复代码都被包起来了,使用起来会方便很多。具体的代码我附在参考资料里,供大家学习研究,望多提宝贵意见:)
本文转载自:http://it.dianping.com/using_attribute_wrapping_performance_counter.htm
参考资料下载: http://it.dianping.com/using_attribute_wrapping_performance_counter.htm