本文翻译自 – http://www.tigase.org/content/component-implementation-lesson-5-statistics
大多数情况,你都想从组件中拿到一些运行时的统计信息,并依据它们来检查组件的运行情况,或者找到可能的性能瓶颈和拥堵。所有的统计信息都可以通过XMPP的ad-hoc指令/Http/JXM获取,其中一部分也可以通过SNMP获取。作为组件的开发者,你不需要关注如何把统计信息通过上面的协议进行输出,需要做的只是准备出统计数据就行,管理员可以通过上面任意一种方式来获取这些数据。
这一节将教会你如何产生自己的统计数据,如何让产生统计数据的过程不影响系统性能。
你的组件在最初只能提供父类产生的那些统计数据,我们现在为它添加一些额外的统计项:
1
2
3
4
5
6
7
8
9
|
@Override
publicvoidgetStatistics(StatisticsList list) {
super.getStatistics(list);
list.add(getName(),"Spam messages found", totalSpamCounter, Level.INFO);
list.add(getName(),"All messages processed", messagesCounter, Level.FINER);
if(list.checkLevel(Level.FINEST)) {
// 可以把那些非常消耗系统资源的统计数据产生代码写在下面
}
}
|
代码应该很容易理解:D。首先调用“super.getStatistics(…)”方法来获取父类的统计项并更新父类的状态。StatisticsList是一个保存所有统计项的集合,它可以非常方便的对统计项进行更新和查找。实际上你不需要知道实现的所有细节,但是如果你感兴趣,可以查看源码并阅读javadoc文档。
add()方法的第一个参数是组件名称。所有的统计项都会以组件名称来进行分组,当想要看特定组件的统计数据的时候可以很容易得进行查找;第二个参数是统计项的描述;第三个是统计项的值,它可以是数字或字符串。最后一个参数最有意思,它的设计思路来自于日志框架。每一个统计项都有一个重要级别,最重要的级别为“SEVERE”,“FINEST”是最不重要的。这个参数可以用来提高系统性能,也能帮助统计数据进行分类显示。当“StatisticsList”对象被创建的时候,会被用户指定一个特定的级别。当调用add方法向其中添加一个低级别统计项的时候,这个统计项不会被添加到列表当中。这样可以节省网络带宽,提高统计数据的接收速度,也能为最终用户提供一个简单明了的展现。
一个比较容易产生困惑的地方是,当一个值为数字“0”的统计项被添加到统计列表的时候,统计项的级别别会被强制设定为“FINEST”。这基于一个假设:管理员在大多数情况下不会关注值为0的统计项,所以除非在ta有意请求低级别的统计列表的时候,否则ta无法看到0值统计项。
“if”语句也需要一些解释。在大多数情况,添加一个统计项并不会消耗多少系统资源,所以可以直接调用add方法来进行添加。但有些时候,生成统计数据是一个耗时较长并且消耗系统资源的过程(比如需要从数据库当中读取数据并进行计算)。统计信息的收集可能非常频繁,所以每次收集全部的统计项(尤其是某些统计项的级别低于统计列表的级别)是没有意义的。在这种情况,还是建议检查一下统计项的级别是否低于统计列表的级别,如果低于可以直接跳过。
就像你所看到的,统计信息的产生和展现API是非常简单和直接的。只有一个方法需要覆写,下面是样例的完整代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
importjava.util.Arrays;
importjava.util.Map;
importjava.util.logging.Level;
importjava.util.logging.Logger;
importtigase.server.AbstractMessageReceiver;
importtigase.server.Packet;
importtigase.stats.StatisticsList;
importtigase.util.JIDUtils;
importtigase.xmpp.StanzaType;
publicclassTestComponentextendsAbstractMessageReceiver {
privatestaticfinalLogger log =
Logger.getLogger(TestComponent.class.getName());
privatestaticfinalString BAD_WORDS_KEY ="bad-words";
privatestaticfinalString WHITELIST_KEY ="white-list";
privatestaticfinalString PREPEND_TEXT_KEY ="log-prepend";
privatestaticfinalString SECURE_LOGGING_KEY ="secure-logging";
privatestaticfinalString ABUSE_ADDRESS_KEY ="abuse-address";
privatestaticfinalString NOTIFICATION_FREQ_KEY ="notification-freq";
privateString[] badWords = {"word1","word2","word3"};
privateString[] whiteList = {"admin@localhost"};
privateString prependText ="Spam detected: ";
privateString abuseAddress ="abuse@locahost";
privateintnotificationFrequency =10;
privateintdelayCounter =0;
privatebooleansecureLogging =false;
privatelongspamCounter =0;
privatelongtotalSpamCounter =0;
privatelongmessagesCounter =0;
@Override
publicvoidprocessPacket(Packet packet) {
// 这是一个message packet吗?
if("message"== packet.getElemName()) {
updateServiceDiscoveryItem(getName(),"messages",
"Messages processed: ["+ (++messagesCounter) +"]",true);
String from = JIDUtils.getNodeID(packet.getElemFrom());
// 消息的发送者在白名单内吗?
if(Arrays.binarySearch(whiteList, from) <0) {
// 如果ta不在白名单里面,那么检查消息的内容
Stringbody = packet.getElemCData("/message/body");
if(body !=null&& !body.isEmpty()) {
body = body.toLowerCase();
for(String word : badWords) {
if(body.contains(word)) {
log.finest(prependText + packet.toString(secureLogging));
++spamCounter;
updateServiceDiscoveryItem(getName(),"spam","Spam caught: ["+
(++totalSpamCounter) +"]",true);
return;
}
}
}
}
}
// 不是垃圾信息,返回以便做下一步处理
Packet result = packet.swapElemFromTo();
addOutPacket(result);
}
@Override
publicintprocessingThreads() {
returnRuntime.getRuntime().availableProcessors();
}
@Override
publicinthashCodeForPacket(Packet packet) {
if(packet.getElemTo() !=null) {
returnpacket.getElemTo().hashCode();
}
// 程序不应该运行到这里,所有的packet都必须具有一个目的地地址,但是也许垃圾过滤器也许会过滤一些奇怪的地址
if(packet.getElemFrom() !=null) {
returnpacket.getElemFrom().hashCode();
}
// 如果程序真的运行到这一部,就应该好好检查一下到达组件的packet是否正常,然后找到一个更好的计算hashCode方法。
return1;
}
@Override
publicMap<String, Object> getDefaults(Map<String, Object> params) {
Map<String, Object> defs =super.getDefaults(params);
defs.put(BAD_WORDS_KEY, badWords);
defs.put(WHITELIST_KEY, whiteList);
defs.put(PREPEND_TEXT_KEY, prependText);
defs.put(SECURE_LOGGING_KEY, secureLogging);
defs.put(ABUSE_ADDRESS_KEY, abuseAddress);
defs.put(NOTIFICATION_FREQ_KEY, notificationFrequency);
returndefs;
}
@Override
publicvoidsetProperties(Map<String, Object> props) {
super.setProperties(props);
badWords = (String[])props.get(BAD_WORDS_KEY);
whiteList = (String[])props.get(WHITELIST_KEY);
Arrays.sort(whiteList);
prependText = (String)props.get(PREPEND_TEXT_KEY);
secureLogging = (Boolean)props.get(SECURE_LOGGING_KEY);
abuseAddress = (String)props.get(ABUSE_ADDRESS_KEY);
notificationFrequency = (Integer)props.get(NOTIFICATION_FREQ_KEY);
updateServiceDiscoveryItem(getName(),null, getDiscoDescription(),
"automation","spam-filtering",true,
"tigase:x:spam-filter","tigase:x:spam-reporting");
}
@Override
publicsynchronizedvoideveryMinute() {
super.everyMinute();
if((++delayCounter) >= notificationFrequency) {
addOutPacket(Packet.getMessage(abuseAddress, getComponentId(),
StanzaType.chat,"Detected spam messages: "+ spamCounter,
"Spam counter",null, newPacketId("spam-")));
delayCounter =0;
spamCounter =0;
}
}
@Override
publicString getDiscoDescription() {
return"Spam filtering";
}
@Override
publicString getDiscoCategoryType() {
return"spam";
}
@Override
publicvoidgetStatistics(StatisticsList list) {
super.getStatistics(list);
list.add(getName(),"Spam messages found", totalSpamCounter, Level.INFO);
list.add(getName(),"All messages processed", messagesCounter, Level.FINE);
if(list.checkLevel(Level.FINEST)) {
// 可以把那些非常消耗系统资源的统计数据产生代码写在下面
}
}
}
|