Storm Metric类似于Hadoop的Counter,用于手机应用程序中的特定指标,输出到输出到外部,在Storm中是存储到各个机器logs目录下的metric.log文件。有时我们想保存一些计算的中间变量,当达到一定状态时,统一在一个位置输出,或者统计整合应用的一些指标,Metric是个很好的选择。如果在Bolt类中存储变量,只能统计该Bolt的一些信息,无法取到其他Bolt的状态信息。用户可以直接使用LoggingMetricsConsumer类,将统计指标写入MetricConsumer接口,这些类可以通过函数registerMetricsConsumer注册,也可以在配置文件storm.yaml中注册。我们定义一个MonitorKafkaLogConsumer的自定义类

package com.lyz.hadoop.storm.metric;

import java.util.Collection;
import java.util.Map;

import org.apache.storm.metric.api.IMetricsConsumer;
import org.apache.storm.task.IErrorReporter;
import org.apache.storm.task.TopologyContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MinitorKafkaLogConsumer implements IMetricsConsumer {
private final Logger logger = LoggerFactory.getLogger(MinitorKafkaLogConsumer.class);
@Override
public void prepare(Map stormConf, Object registrationArgument, TopologyContext context,
IErrorReporter errorReporter) {

}
@Override
public void handleDataPoints(TaskInfo taskInfo, Collection<DataPoint> dataPoints) {
for(DataPoint p : dataPoints) {
logger.info((p.name + ":" + p.value));
}
}
@Override
public void cleanup() {

}
}

然后把MonitorKafkaLogConsumer注册到 registerMetricsConsumer中。

Config conf = new Config();
//输出统计指标值到日志文件中
conf.registerMetricsConsumer(MinitorKafkaLogConsumer.class, 5);
StormSubmitter.submitTopology(args[0], conf, builder.createTopology());

最后,在具体业务的Bolt中加入需要统计的值,比如统计用户的访问次数。

package com.lyz.hadoop.storm.metric;

import java.util.Map;

import org.apache.storm.metric.api.CountMetric;
import org.apache.storm.metric.api.MultiCountMetric;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Tuple;

public class MonitorUserActionBolt extends BaseBasicBolt {

private static final long serialVersionUID = -7650845624664389481L;

private transient MultiCountMetric userProfileStatMetric;
//浏览行为
private static final String USER_ACTION_BROWSE = "Bro";

@Override
public void prepare(Map stormConf, TopologyContext context) {
super.prepare(stormConf, context);
this.userProfileStatMetric = new MultiCountMetric();
//每10秒统计一些浏览行为的次数
context.registerMetric("useraction_count", userProfileStatMetric, 10);
}

public void updateUserActionMetric(UserActionTuple userAction) {
if(USER_ACTION_BROWSE.equalIgnoreCase(userAction.getUserType())) {
CountMetric broCount = userProfileStatMetric.scope(USER_ACTION_BROWSE);
broCount.incr();
}
}

@Override
public void execute(Tuple input, BasicOutputCollector collector) {
Object msg = input.getValueByField("trackInfos");
//用户行为的自定义类
UserActionTuple userAction = (UserActionTuple)msg;
updateUserActionMetric(userAction);
}

@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {

}
}

这样,通过Metric信息可以将所关心的业务指标数据提取出来,发送到相应的系统中,用于监控和报警。