package resa.metrics; import backtype.storm.metric.api.IMetricsConsumer; import backtype.storm.task.IErrorReporter; import backtype.storm.task.TopologyContext; import backtype.storm.utils.Utils; import java.util.*; import java.util.stream.Collectors; /** * Class used to filter useless metrics that collected by storm build-in metric system. * * @author Troy Ding */ public abstract class FilteredMetricsCollector implements IMetricsConsumer { public static final String APPROVED_METRIC_NAMES = "resa.metric.approved.names"; private final Map<String, String> approvedMetricNames = new HashMap<>(); @Override public void prepare(Map stormConf, Object arg, TopologyContext context, IErrorReporter errorReporter) { List<String> metricNames = (List<String>) stormConf.get(APPROVED_METRIC_NAMES); if (metricNames != null) { metricNames.stream().forEach((line) -> { line = line.trim(); if (line.isEmpty()) { return; } String[] tmp = line.split("\\s+"); if (tmp.length == 1) { addApprovedMetirc(tmp[0]); } else { addApprovedMetirc(tmp[0], tmp[1]); } }); } } public void addApprovedMetirc(String metricName, String alias) { approvedMetricNames.put(metricName, alias); } public void addApprovedMetirc(String metricName) { addApprovedMetirc(metricName, metricName); } public void removeApprovedMetirc(String metricName) { approvedMetricNames.remove(metricName); } @Override public void handleDataPoints(TaskInfo taskInfo, Collection<DataPoint> dataPoints) { //check task fist if (keepTask(taskInfo)) { return; } // select points that need to keep based on the implementation of keepPoint function List<DataPoint> selectedPoints = dataPoints.stream().map(dataPoint -> processPoint(taskInfo, dataPoint)) .filter(Objects::nonNull).collect(Collectors.toList()); if (!selectedPoints.isEmpty()) { handleSelectedDataPoints(taskInfo, selectedPoints); } } /** * Check whether this task metrics should be keep, default implementations filter * metrics that generated by system components. * * @param taskInfo * @return true if this metrics should be keep; otherwise false */ protected boolean keepTask(TaskInfo taskInfo) { //ignore system component return Utils.isSystemId(taskInfo.srcComponentId); } private DataPoint processPoint(TaskInfo taskInfo, DataPoint dataPoint) { String alias = approvedMetricNames.get(dataPoint.name); return alias != null && keepPoint(taskInfo, dataPoint) ? new DataPoint(alias, dataPoint.value) : null; } /** * Check whether this data point should be keep, default implementations filters empty collections * * @param dataPoint * @return false if this data point should be removed */ protected boolean keepPoint(TaskInfo taskInfo, DataPoint dataPoint) { Object value = dataPoint.value; if (value == null) { return false; } else if (value instanceof Map) { return !((Map) value).isEmpty(); } else if (value instanceof Collection) { return !((Collection) value).isEmpty(); } return true; } protected abstract void handleSelectedDataPoints(TaskInfo taskInfo, Collection<DataPoint> dataPoints); @Override public void cleanup() { } }