blob: 7ff636c18cb484034729d736d3b6044f97fa2840 [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);
123 influxDbReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
124 log.info("Start to report metrics to influxDB.");
Jian Lie1d97c92016-03-22 10:21:44 -0700125 }
126
127 @Override
128 public void stopReport() {
129 influxDbReporter.stop();
130 influxDbHttpSender = null;
131 influxDbReporter = null;
132 log.info("Stop reporting metrics to influxDB.");
133 }
134
135 @Override
136 public void restartReport() {
137 stopReport();
138 startReport();
139 }
140
141 @Override
Jian Li55cbd5c2016-04-06 09:50:20 -0700142 public void notifyMetricsChange() {
143 influxDbReporter.stop();
144 influxDbReporter = buildReporter(influxDbHttpSender);
145 influxDbReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
146 log.info("Metric registry has been changed, apply changes.");
147 }
148
149 @Override
Jian Lie1d97c92016-03-22 10:21:44 -0700150 public void config(String address, int port, String database,
151 String username, String password) {
152 this.address = address;
153 this.port = port;
154 this.database = database;
155 this.username = username;
156 this.password = password;
157 }
158
159 /**
160 * Filters the metrics to only include a set of the given metrics.
161 *
162 * @param metricRegistry original metric registry
163 * @return filtered metric registry
164 */
165 protected MetricRegistry filter(MetricRegistry metricRegistry) {
166 if (!monitorAll) {
167 final MetricRegistry filtered = new MetricRegistry();
168 metricRegistry.getNames().stream().filter(name ->
169 containsName(name, metricNames)).forEach(name ->
170 filtered.register(name, metricRegistry.getMetrics().get(name)));
171 return filtered;
172 } else {
173 return metricRegistry;
174 }
175 }
176
177 /**
178 * Appends node IP prefix to all performance metrics.
179 *
180 * @param metricRegistry original metric registry
181 * @return prefix added metric registry
182 */
183 protected MetricRegistry addHostPrefix(MetricRegistry metricRegistry) {
184 MetricRegistry moddedRegistry = new MetricRegistry();
185 ControllerNode node = clusterService.getLocalNode();
186 String prefix = node.id().id() + ".";
187 metricRegistry.getNames().stream().forEach(name ->
188 moddedRegistry.register(prefix + name, metricRegistry.getMetrics().get(name)));
189
190 return moddedRegistry;
191 }
192
193 /**
194 * Looks up whether the metric name contains the given prefix keywords.
195 * Note that the keywords are separated with comma as delimiter.
196 *
197 * @param full the original metric name that to be compared with
198 * @param prefixes the prefix keywords that are matched against with the metric name
199 * @return boolean value that denotes whether the metric name starts with the given prefix
200 */
201 protected boolean containsName(String full, String prefixes) {
202 String[] prefixArray = StringUtils.split(prefixes, ",");
203 for (String prefix : prefixArray) {
204 if (StringUtils.startsWith(full, StringUtils.trimToEmpty(prefix))) {
205 return true;
206 }
207 }
208 return false;
209 }
210
211 /**
212 * Extracts properties from the component configuration context.
213 *
214 * @param context the component context
215 */
216 private void readComponentConfiguration(ComponentContext context) {
217 Dictionary<?, ?> properties = context.getProperties();
218
219 String metricNameStr = Tools.get(properties, "metricNames");
220 metricNames = metricNameStr != null ? metricNameStr : DEFAULT_METRIC_NAMES;
221 log.info("Configured. Metric name is {}", metricNames);
222
223 Boolean monitorAllEnabled = Tools.isPropertyEnabled(properties, "monitorAll");
224 if (monitorAllEnabled == null) {
225 log.info("Monitor all metrics is not configured, " +
226 "using current value of {}", monitorAll);
227 } else {
228 monitorAll = monitorAllEnabled;
229 log.info("Configured. Monitor all metrics is {}",
230 monitorAll ? "enabled" : "disabled");
231 }
232 }
Jian Li55cbd5c2016-04-06 09:50:20 -0700233
234 /**
235 * Configures parameters for sender.
236 */
237 private void configSender() {
238 try {
239 influxDbHttpSender = new InfluxDbHttpSender(DEFAULT_PROTOCOL, address,
240 port, database, username + SEPARATOR + password, REPORT_TIME_UNIT,
241 DEFAULT_CONN_TIMEOUT, DEFAULT_READ_TIMEOUT);
242 } catch (Exception e) {
243 log.error("Fail to connect to given influxDB server!");
244 }
245 }
246
247 /**
248 * Builds reporter with the given sender.
249 *
250 * @param sender sender
251 * @return reporter
252 */
253 private InfluxDbReporter buildReporter(InfluxDbHttpSender sender) {
254 MetricRegistry mr = metricsService.getMetricRegistry();
255 return InfluxDbReporter.forRegistry(addHostPrefix(filter(mr)))
256 .convertRatesTo(TimeUnit.SECONDS)
257 .convertDurationsTo(TimeUnit.MILLISECONDS)
258 .build(sender);
259 }
Jian Lie1d97c92016-03-22 10:21:44 -0700260}