blob: 518c1ff3416ec9550ec398dcd93b098a21a580bd [file] [log] [blame]
Jian Li55cbd5c2016-04-06 09:50:20 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jian Li55cbd5c2016-04-06 09:50:20 -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.graphitemetrics;
17
18
19import com.codahale.metrics.MetricRegistry;
20import com.codahale.metrics.graphite.Graphite;
21import com.codahale.metrics.graphite.GraphiteReporter;
22import org.apache.commons.lang.StringUtils;
Jian Li55cbd5c2016-04-06 09:50:20 -070023import org.onlab.metrics.MetricsService;
24import org.onlab.util.Tools;
25import org.onosproject.cfg.ComponentConfigService;
26import org.onosproject.core.CoreService;
27import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070028import org.osgi.service.component.annotations.Activate;
29import org.osgi.service.component.annotations.Component;
30import org.osgi.service.component.annotations.Deactivate;
31import org.osgi.service.component.annotations.Modified;
32import org.osgi.service.component.annotations.Reference;
33import org.osgi.service.component.annotations.ReferenceCardinality;
Jian Li55cbd5c2016-04-06 09:50:20 -070034import org.slf4j.Logger;
35
36import java.net.InetSocketAddress;
37import java.util.Dictionary;
38import java.util.concurrent.TimeUnit;
39
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070040import static org.onosproject.graphitemetrics.OsgiPropertyConstants.ADDRESS;
41import static org.onosproject.graphitemetrics.OsgiPropertyConstants.ADDRESS_DEFAULT;
42import static org.onosproject.graphitemetrics.OsgiPropertyConstants.METRIC_NAMES;
43import static org.onosproject.graphitemetrics.OsgiPropertyConstants.METRIC_NAMES_DEFAULT;
44import static org.onosproject.graphitemetrics.OsgiPropertyConstants.METRIC_NAME_PREFIX;
45import static org.onosproject.graphitemetrics.OsgiPropertyConstants.METRIC_NAME_PREFIX_DEFAULT;
46import static org.onosproject.graphitemetrics.OsgiPropertyConstants.MONITOR_ALL;
47import static org.onosproject.graphitemetrics.OsgiPropertyConstants.MONITOR_ALL_DEFAULT;
48import static org.onosproject.graphitemetrics.OsgiPropertyConstants.PORT;
49import static org.onosproject.graphitemetrics.OsgiPropertyConstants.PORT_DEFAULT;
50import static org.onosproject.graphitemetrics.OsgiPropertyConstants.REPORT_PERIOD;
51import static org.onosproject.graphitemetrics.OsgiPropertyConstants.REPORT_PERIOD_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070052import static org.slf4j.LoggerFactory.getLogger;
53
54/**
55 * A metric report that reports all metrics value to graphite monitoring server.
56 */
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070057@Component(
58 immediate = true,
59 property = {
60 MONITOR_ALL + ":Boolean=" + MONITOR_ALL_DEFAULT,
61 METRIC_NAMES + "=" + METRIC_NAMES_DEFAULT,
62 ADDRESS + "=" + ADDRESS_DEFAULT,
63 PORT + ":Integer=" + PORT_DEFAULT,
64 REPORT_PERIOD + ":Integer=" + REPORT_PERIOD_DEFAULT,
65 METRIC_NAME_PREFIX + "=" + METRIC_NAME_PREFIX_DEFAULT
66 }
67)
Jian Li55cbd5c2016-04-06 09:50:20 -070068public class DefaultGraphiteMetricsReporter implements GraphiteMetricsReporter {
69
70 private final Logger log = getLogger(getClass());
71
72 private static final TimeUnit REPORT_TIME_UNIT = TimeUnit.MINUTES;
Jian Li55cbd5c2016-04-06 09:50:20 -070073
Ray Milkeyd84f89b2018-08-17 14:54:17 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070075 protected CoreService coreService;
76
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070078 protected MetricsService metricsService;
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070081 protected ComponentConfigService cfgService;
82
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070083 /** Enable to monitor all of metrics stored in metric registry default is true. */
84 protected boolean monitorAll = MONITOR_ALL_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070085
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070086 /** Names of metric to be monitored; default metric names are 'default'. */
87 protected String metricNames = METRIC_NAMES_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070088
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070089 /** IP address of graphite monitoring server; default is localhost. */
90 protected String address = ADDRESS_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070091
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070092 /** Port number of graphite monitoring server; default is 2003. */
93 protected int port = PORT_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070094
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070095 /** Reporting period of graphite monitoring server; default is 1. */
96 protected int reportPeriod = REPORT_PERIOD_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070097
Ray Milkey7cc3e7d2018-10-31 09:28:40 -070098 /** Prefix of metric name for graphite back-end server; default is 'onos'. */
99 protected String metricNamePrefix = METRIC_NAME_PREFIX_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700100
101 private Graphite graphite;
102 private GraphiteReporter graphiteReporter;
103
104 @Activate
105 public void activate() {
106 cfgService.registerProperties(getClass());
107 coreService.registerApplication("org.onosproject.graphitemetrics");
108 metricsService.registerReporter(this);
109
110 startReport();
111 log.info("Started");
112 }
113
114 @Deactivate
115 public void deactivate() {
116 cfgService.unregisterProperties(getClass(), false);
117
118 stopReport();
119 metricsService.unregisterReporter(this);
120
121 log.info("Stopped");
122 }
123
124 @Modified
125 public void modified(ComponentContext context) {
126 readComponentConfiguration(context);
127
128 // Restarts reporting
129 stopReport();
130 startReport();
131 }
132
133 public void startReport() {
134 configGraphite();
135 graphiteReporter = buildReporter(graphite);
Jian Li279130d2016-04-06 16:29:44 -0700136
137 try {
sangyun-hanf78f17b2016-04-25 15:22:12 +0900138 graphiteReporter.start(reportPeriod, REPORT_TIME_UNIT);
Jian Li279130d2016-04-06 16:29:44 -0700139 } catch (Exception e) {
140 log.error("Errors during reporting to graphite, msg: {}" + e.getMessage());
141 }
142
Jian Li55cbd5c2016-04-06 09:50:20 -0700143 log.info("Start to report metrics to graphite server.");
144 }
145
146 public void stopReport() {
147 graphiteReporter.stop();
148 graphite = null;
149 graphiteReporter = null;
150 log.info("Stop reporting metrics to graphite server.");
151 }
152
153 @Override
154 public void restartReport() {
155 stopReport();
156 startReport();
157 }
158
159 @Override
160 public void notifyMetricsChange() {
161 graphiteReporter.stop();
162 graphiteReporter = buildReporter(graphite);
Jian Li279130d2016-04-06 16:29:44 -0700163
164 try {
sangyun-hanf78f17b2016-04-25 15:22:12 +0900165 graphiteReporter.start(reportPeriod, REPORT_TIME_UNIT);
Jian Li279130d2016-04-06 16:29:44 -0700166 } catch (Exception e) {
167 log.error("Errors during reporting to graphite, msg: {}" + e.getMessage());
168 }
169
Jian Li55cbd5c2016-04-06 09:50:20 -0700170 log.info("Metric registry has been changed, apply changes.");
171 }
172
173 /**
174 * Filters the metrics to only include a set of the given metrics.
175 *
176 * @param metricRegistry original metric registry
177 * @return filtered metric registry
178 */
179 protected MetricRegistry filter(MetricRegistry metricRegistry) {
180 if (!monitorAll) {
181 final MetricRegistry filtered = new MetricRegistry();
182 metricRegistry.getNames().stream().filter(name ->
183 containsName(name, metricNames)).forEach(name ->
184 filtered.register(name, metricRegistry.getMetrics().get(name)));
185 return filtered;
186 } else {
187 return metricRegistry;
188 }
189 }
190
191 /**
192 * Looks up whether the metric name contains the given prefix keywords.
193 * Note that the keywords are separated with comma as delimiter
194 *
195 * @param full the original metric name that to be compared with
196 * @param prefixes the prefix keywords that are matched against with the metric name
197 * @return boolean value that denotes whether the metric name starts with the given prefix
198 */
199 protected boolean containsName(String full, String prefixes) {
200 String[] prefixArray = StringUtils.split(prefixes, ",");
201 for (String prefix : prefixArray) {
202 if (StringUtils.startsWith(full, StringUtils.trimToEmpty(prefix))) {
203 return true;
204 }
205 }
206 return false;
207 }
208
209 /**
210 * Extracts properties from the component configuration context.
211 *
212 * @param context the component context
213 */
214 private void readComponentConfiguration(ComponentContext context) {
215 Dictionary<?, ?> properties = context.getProperties();
216
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700217 Boolean newMonitorAll = Tools.isPropertyEnabled(properties, MONITOR_ALL);
Jian Li55cbd5c2016-04-06 09:50:20 -0700218 if (newMonitorAll == null) {
219 log.info("Monitor all metrics is not configured, " +
220 "using current value of {}", monitorAll);
221 } else {
222 monitorAll = newMonitorAll;
223 log.info("Configured. Monitor all metrics is {}, ",
224 monitorAll ? "enabled" : "disabled");
225 }
226
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700227 String newMetricNames = Tools.get(properties, METRIC_NAMES);
228 metricNames = newMetricNames != null ? newMetricNames : METRIC_NAMES_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700229 log.info("Configured. Metric name is {}", metricNames);
230
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700231 String newAddress = Tools.get(properties, ADDRESS);
232 address = newAddress != null ? newAddress : ADDRESS_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700233 log.info("Configured. Graphite monitoring server address is {}", address);
234
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700235 Integer newPort = Tools.getIntegerProperty(properties, PORT);
Jian Li55cbd5c2016-04-06 09:50:20 -0700236 if (newPort == null) {
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700237 port = PORT_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700238 log.info("Graphite port is not configured, default value is {}", port);
239 } else {
240 port = newPort;
241 log.info("Configured. Graphite port is configured to {}", port);
242 }
243
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700244 Integer newReportPeriod = Tools.getIntegerProperty(properties, REPORT_PERIOD);
Jian Li55cbd5c2016-04-06 09:50:20 -0700245 if (newReportPeriod == null) {
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700246 reportPeriod = REPORT_PERIOD_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700247 log.info("Report period of graphite server is not configured, " +
248 "default value is {}", reportPeriod);
249 } else {
250 reportPeriod = newReportPeriod;
251 log.info("Configured. Report period of graphite server" +
252 " is configured to {}", reportPeriod);
253 }
254
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700255 String newMetricNamePrefix = Tools.get(properties, METRIC_NAME_PREFIX);
Jian Li55cbd5c2016-04-06 09:50:20 -0700256 metricNamePrefix = newMetricNamePrefix != null ?
Ray Milkey7cc3e7d2018-10-31 09:28:40 -0700257 newMetricNamePrefix : METRIC_NAME_PREFIX_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700258
259 }
260
261 /**
262 * Configures parameters for graphite config.
263 */
264 private void configGraphite() {
265 try {
266 graphite = new Graphite(new InetSocketAddress(address, port));
267 } catch (Exception e) {
268 log.error("Fail to connect to given graphite server! : " + e.getMessage());
269 }
270 }
271
272 /**
273 * Builds reporter with the given graphite config.
274 *
275 * @param graphiteCfg graphite config
276 * @return reporter
277 */
278 private GraphiteReporter buildReporter(Graphite graphiteCfg) {
279 MetricRegistry metricRegistry = metricsService.getMetricRegistry();
280 return GraphiteReporter.forRegistry(filter(metricRegistry))
281 .prefixedWith(metricNamePrefix)
282 .convertRatesTo(TimeUnit.SECONDS)
283 .convertDurationsTo(TimeUnit.MILLISECONDS)
284 .build(graphiteCfg);
285 }
286}