blob: a0dca3b6037eb0829fa3fe986a73258097c075f3 [file] [log] [blame]
Jian Lie1d97c92016-03-22 10:21:44 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Jian Lie1d97c92016-03-22 10:21:44 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.influxdbmetrics;
17
18import com.codahale.metrics.MetricRegistry;
19import com.izettle.metrics.influxdb.InfluxDbHttpSender;
20import com.izettle.metrics.influxdb.InfluxDbReporter;
21import org.apache.commons.lang.StringUtils;
22import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Modified;
26import org.apache.felix.scr.annotations.Property;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.apache.felix.scr.annotations.Service;
30import org.onlab.metrics.MetricsService;
31import org.onlab.util.Tools;
32import org.onosproject.cfg.ComponentConfigService;
33import org.onosproject.cluster.ClusterService;
34import org.onosproject.cluster.ControllerNode;
35import org.onosproject.core.CoreService;
36import org.osgi.service.component.ComponentContext;
37import org.slf4j.Logger;
38
39import java.util.Dictionary;
40import java.util.concurrent.TimeUnit;
41
42import static org.slf4j.LoggerFactory.getLogger;
43
44/**
45 * A Metric reporter that reports all metrics value to influxDB server.
46 */
47@Component(immediate = true)
48@Service
49public class DefaultInfluxDbMetricsReporter implements InfluxDbMetricsReporter {
50 private final Logger log = getLogger(getClass());
51
52 private static final int REPORT_PERIOD = 1;
53 private static final TimeUnit REPORT_TIME_UNIT = TimeUnit.MINUTES;
54
55 private static final String DEFAULT_PROTOCOL = "http";
56 private static final String DEFAULT_METRIC_NAMES = "default";
57 private static final String SEPARATOR = ":";
58 private static final int DEFAULT_CONN_TIMEOUT = 1000;
59 private static final int DEFAULT_READ_TIMEOUT = 1000;
60
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 protected CoreService coreService;
63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected MetricsService metricsService;
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected ComponentConfigService cfgService;
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected ClusterService clusterService;
72
73 @Property(name = "monitorAll", boolValue = true,
74 label = "Enable to monitor all of metrics stored in metric registry " +
75 "default is true")
76 protected boolean monitorAll = true;
77
78 @Property(name = "metricNames", value = DEFAULT_METRIC_NAMES,
79 label = "Names of metric to be monitored in third party monitoring " +
80 "server; default metric names are 'default'")
81 protected String metricNames = DEFAULT_METRIC_NAMES;
82
83 protected String address;
84 protected int port;
85 protected String database;
86 protected String username;
87 protected String password;
88
89 private InfluxDbReporter influxDbReporter;
90 private InfluxDbHttpSender influxDbHttpSender;
91
92 @Activate
93 public void activate() {
94 cfgService.registerProperties(getClass());
95 coreService.registerApplication("org.onosproject.influxdbmetrics");
Jian Li55cbd5c2016-04-06 09:50:20 -070096 metricsService.registerReporter(this);
97
98 startReport();
Jian Lie1d97c92016-03-22 10:21:44 -070099
100 log.info("Started");
101 }
102
103 @Deactivate
104 public void deactivate() {
105 cfgService.unregisterProperties(getClass(), false);
106
Jian Li55cbd5c2016-04-06 09:50:20 -0700107 stopReport();
108 metricsService.unregisterReporter(this);
109
Jian Lie1d97c92016-03-22 10:21:44 -0700110 log.info("Stopped");
111 }
112
113 @Modified
114 public void modified(ComponentContext context) {
115 readComponentConfiguration(context);
116 restartReport();
117 }
118
119 @Override
120 public void startReport() {
Jian Li55cbd5c2016-04-06 09:50:20 -0700121 configSender();
122 influxDbReporter = buildReporter(influxDbHttpSender);
Jian Li279130d2016-04-06 16:29:44 -0700123
124 try {
125 influxDbReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
126 } catch (Exception e) {
127 log.error("Errors during reporting to InfluxDB, msg: {}" + e.getMessage());
128 }
Jian Li55cbd5c2016-04-06 09:50:20 -0700129 log.info("Start to report metrics to influxDB.");
Jian Lie1d97c92016-03-22 10:21:44 -0700130 }
131
132 @Override
133 public void stopReport() {
134 influxDbReporter.stop();
135 influxDbHttpSender = null;
136 influxDbReporter = null;
137 log.info("Stop reporting metrics to influxDB.");
138 }
139
140 @Override
141 public void restartReport() {
142 stopReport();
143 startReport();
144 }
145
146 @Override
Jian Li55cbd5c2016-04-06 09:50:20 -0700147 public void notifyMetricsChange() {
148 influxDbReporter.stop();
149 influxDbReporter = buildReporter(influxDbHttpSender);
Jian Li279130d2016-04-06 16:29:44 -0700150
151 try {
152 influxDbReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
153 } catch (Exception e) {
154 log.error("Errors during reporting to InfluxDB, msg: {}" + e.getMessage());
155 }
156
Jian Li55cbd5c2016-04-06 09:50:20 -0700157 log.info("Metric registry has been changed, apply changes.");
158 }
159
160 @Override
Jian Lie1d97c92016-03-22 10:21:44 -0700161 public void config(String address, int port, String database,
162 String username, String password) {
163 this.address = address;
164 this.port = port;
165 this.database = database;
166 this.username = username;
167 this.password = password;
168 }
169
170 /**
171 * Filters the metrics to only include a set of the given metrics.
172 *
173 * @param metricRegistry original metric registry
174 * @return filtered metric registry
175 */
176 protected MetricRegistry filter(MetricRegistry metricRegistry) {
177 if (!monitorAll) {
178 final MetricRegistry filtered = new MetricRegistry();
179 metricRegistry.getNames().stream().filter(name ->
180 containsName(name, metricNames)).forEach(name ->
181 filtered.register(name, metricRegistry.getMetrics().get(name)));
182 return filtered;
183 } else {
184 return metricRegistry;
185 }
186 }
187
188 /**
189 * Appends node IP prefix to all performance metrics.
190 *
191 * @param metricRegistry original metric registry
192 * @return prefix added metric registry
193 */
194 protected MetricRegistry addHostPrefix(MetricRegistry metricRegistry) {
195 MetricRegistry moddedRegistry = new MetricRegistry();
196 ControllerNode node = clusterService.getLocalNode();
197 String prefix = node.id().id() + ".";
198 metricRegistry.getNames().stream().forEach(name ->
199 moddedRegistry.register(prefix + name, metricRegistry.getMetrics().get(name)));
200
201 return moddedRegistry;
202 }
203
204 /**
205 * Looks up whether the metric name contains the given prefix keywords.
206 * Note that the keywords are separated with comma as delimiter.
207 *
208 * @param full the original metric name that to be compared with
209 * @param prefixes the prefix keywords that are matched against with the metric name
210 * @return boolean value that denotes whether the metric name starts with the given prefix
211 */
212 protected boolean containsName(String full, String prefixes) {
213 String[] prefixArray = StringUtils.split(prefixes, ",");
214 for (String prefix : prefixArray) {
215 if (StringUtils.startsWith(full, StringUtils.trimToEmpty(prefix))) {
216 return true;
217 }
218 }
219 return false;
220 }
221
222 /**
223 * Extracts properties from the component configuration context.
224 *
225 * @param context the component context
226 */
227 private void readComponentConfiguration(ComponentContext context) {
228 Dictionary<?, ?> properties = context.getProperties();
229
230 String metricNameStr = Tools.get(properties, "metricNames");
231 metricNames = metricNameStr != null ? metricNameStr : DEFAULT_METRIC_NAMES;
232 log.info("Configured. Metric name is {}", metricNames);
233
234 Boolean monitorAllEnabled = Tools.isPropertyEnabled(properties, "monitorAll");
235 if (monitorAllEnabled == null) {
236 log.info("Monitor all metrics is not configured, " +
237 "using current value of {}", monitorAll);
238 } else {
239 monitorAll = monitorAllEnabled;
240 log.info("Configured. Monitor all metrics is {}",
241 monitorAll ? "enabled" : "disabled");
242 }
243 }
Jian Li55cbd5c2016-04-06 09:50:20 -0700244
245 /**
246 * Configures parameters for sender.
247 */
248 private void configSender() {
249 try {
250 influxDbHttpSender = new InfluxDbHttpSender(DEFAULT_PROTOCOL, address,
251 port, database, username + SEPARATOR + password, REPORT_TIME_UNIT,
252 DEFAULT_CONN_TIMEOUT, DEFAULT_READ_TIMEOUT);
253 } catch (Exception e) {
254 log.error("Fail to connect to given influxDB server!");
255 }
256 }
257
258 /**
259 * Builds reporter with the given sender.
260 *
261 * @param sender sender
262 * @return reporter
263 */
264 private InfluxDbReporter buildReporter(InfluxDbHttpSender sender) {
265 MetricRegistry mr = metricsService.getMetricRegistry();
266 return InfluxDbReporter.forRegistry(addHostPrefix(filter(mr)))
267 .convertRatesTo(TimeUnit.SECONDS)
268 .convertDurationsTo(TimeUnit.MILLISECONDS)
269 .build(sender);
270 }
Jian Lie1d97c92016-03-22 10:21:44 -0700271}