blob: f74133eeb8cc01e278978aa5a03ab3b3dee81b70 [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.gangliametrics;
17
18import com.codahale.metrics.MetricRegistry;
19import com.codahale.metrics.ganglia.GangliaReporter;
20import info.ganglia.gmetric4j.gmetric.GMetric;
21import org.apache.commons.lang.StringUtils;
Jian Li55cbd5c2016-04-06 09:50:20 -070022import org.onlab.metrics.MetricsService;
23import org.onlab.util.Tools;
24import org.onosproject.cfg.ComponentConfigService;
25import org.onosproject.core.CoreService;
26import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070027import org.osgi.service.component.annotations.Activate;
28import org.osgi.service.component.annotations.Component;
29import org.osgi.service.component.annotations.Deactivate;
30import org.osgi.service.component.annotations.Modified;
31import org.osgi.service.component.annotations.Reference;
32import org.osgi.service.component.annotations.ReferenceCardinality;
Jian Li55cbd5c2016-04-06 09:50:20 -070033import org.slf4j.Logger;
34
35import java.io.IOException;
36import java.util.Dictionary;
37import java.util.concurrent.TimeUnit;
38
Ray Milkey2110e4c2018-10-30 15:49:10 -070039import static org.onosproject.gangliametrics.OsgiPropertyConstants.ADDRESS;
40import static org.onosproject.gangliametrics.OsgiPropertyConstants.ADDRESS_DEFAULT;
41import static org.onosproject.gangliametrics.OsgiPropertyConstants.METRIC_NAMES;
42import static org.onosproject.gangliametrics.OsgiPropertyConstants.METRIC_NAMES_DEFAULT;
43import static org.onosproject.gangliametrics.OsgiPropertyConstants.MONITOR_ALL;
44import static org.onosproject.gangliametrics.OsgiPropertyConstants.MONITOR_ALL_DEFAULT;
45import static org.onosproject.gangliametrics.OsgiPropertyConstants.PORT;
46import static org.onosproject.gangliametrics.OsgiPropertyConstants.PORT_DEFAULT;
47import static org.onosproject.gangliametrics.OsgiPropertyConstants.TTL;
48import static org.onosproject.gangliametrics.OsgiPropertyConstants.TTL_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070049import static org.slf4j.LoggerFactory.getLogger;
50
51/**
52 * A metric report that reports all metrics value to ganglia monitoring server.
53 */
Ray Milkey2110e4c2018-10-30 15:49:10 -070054@Component(
55 immediate = true,
56 property = {
57 MONITOR_ALL + ":Boolean=" + MONITOR_ALL_DEFAULT,
58 METRIC_NAMES + "=" + METRIC_NAMES_DEFAULT,
59 ADDRESS + "=" + ADDRESS_DEFAULT,
60 PORT + ":Integer=" + PORT_DEFAULT,
61 TTL + ":Integer=" + TTL_DEFAULT
62 }
63)
Jian Li55cbd5c2016-04-06 09:50:20 -070064public class DefaultGangliaMetricsReporter implements GangliaMetricsReporter {
65 private final Logger log = getLogger(getClass());
66
67 // we will use uni-cast mode to transfer the metrics value by default
68 private static final GMetric.UDPAddressingMode GANGLIA_MODE =
69 GMetric.UDPAddressingMode.UNICAST;
70 private static final int REPORT_PERIOD = 1;
71 private static final TimeUnit REPORT_TIME_UNIT = TimeUnit.MINUTES;
72
Ray Milkeyd84f89b2018-08-17 14:54:17 -070073 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070074 protected CoreService coreService;
75
Ray Milkeyd84f89b2018-08-17 14:54:17 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070077 protected MetricsService metricsService;
78
Ray Milkeyd84f89b2018-08-17 14:54:17 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070080 protected ComponentConfigService cfgService;
81
Ray Milkey2110e4c2018-10-30 15:49:10 -070082 /** Enable to monitor all of metrics stored in metric registry default is true. */
83 protected boolean monitorAll = MONITOR_ALL_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070084
Ray Milkey2110e4c2018-10-30 15:49:10 -070085 /** Names of metric to be monitored; default metric names are 'default'. */
86 protected String metricNames = METRIC_NAMES_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070087
Ray Milkey2110e4c2018-10-30 15:49:10 -070088 /** IP address of ganglia monitoring server; default is localhost. */
89 protected String address = ADDRESS_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070090
Ray Milkey2110e4c2018-10-30 15:49:10 -070091 /** Port number of ganglia monitoring server; default is 8649. */
92 protected int port = PORT_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070093
Ray Milkey2110e4c2018-10-30 15:49:10 -070094 /** TTL value of ganglia monitoring server; default is 1. */
95 protected int ttl = TTL_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -070096
97 private GMetric ganglia;
98 private GangliaReporter gangliaReporter;
99
100 @Activate
101 public void activate() {
102 cfgService.registerProperties(getClass());
Jian Li279130d2016-04-06 16:29:44 -0700103 coreService.registerApplication("org.onosproject.gangliametrics");
Jian Li55cbd5c2016-04-06 09:50:20 -0700104 metricsService.registerReporter(this);
105
106 startReport();
107 log.info("Started");
108 }
109
110 @Deactivate
111 public void deactivate() {
112 cfgService.unregisterProperties(getClass(), false);
113
114 stopReport();
115 metricsService.unregisterReporter(this);
116
117 log.info("Stopped");
118 }
119
120 @Modified
121 public void modified(ComponentContext context) {
122 readComponentConfiguration(context);
123 stopReport();
124 startReport();
125 }
126
127 @Override
128 public void startReport() {
129 configGMetric();
130 gangliaReporter = buildReporter(ganglia);
Jian Li279130d2016-04-06 16:29:44 -0700131
132 try {
133 gangliaReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
134 } catch (Exception e) {
135 log.error("Errors during reporting to ganglia, msg: {}" + e.getMessage());
136 }
137
Jian Li55cbd5c2016-04-06 09:50:20 -0700138 log.info("Start to report metrics to ganglia server.");
139 }
140
141 @Override
142 public void stopReport() {
143 gangliaReporter.stop();
144 ganglia = null;
145 gangliaReporter = null;
146 log.info("Stop reporting metrics to ganglia server.");
147 }
148
149 @Override
150 public void restartReport() {
151 stopReport();
152 startReport();
153 }
154
155 @Override
156 public void notifyMetricsChange() {
157 gangliaReporter.stop();
158 gangliaReporter = buildReporter(ganglia);
Jian Li279130d2016-04-06 16:29:44 -0700159
160 try {
161 gangliaReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
162 } catch (Exception e) {
163 log.error("Errors during reporting to ganglia, msg: {}" + e.getMessage());
164 }
165
Jian Li55cbd5c2016-04-06 09:50:20 -0700166 log.info("Metric registry has been changed, apply changes.");
167 }
168
169 /**
170 * Filters the metrics to only include a set of the given metrics.
171 *
172 * @param metricRegistry original metric registry
173 * @return filtered metric registry
174 */
175 protected MetricRegistry filter(MetricRegistry metricRegistry) {
176 if (!monitorAll) {
177 final MetricRegistry filtered = new MetricRegistry();
178 metricRegistry.getNames().stream().filter(name ->
179 containsName(name, metricNames)).forEach(name ->
180 filtered.register(name, metricRegistry.getMetrics().get(name)));
181 return filtered;
182 } else {
183 return metricRegistry;
184 }
185 }
186
187 /**
188 * Looks up whether the metric name contains the given prefix keywords.
189 * Note that the keywords are separated with comma as delimiter
190 *
191 * @param full the original metric name that to be compared with
192 * @param prefixes the prefix keywords that are matched against with the metric name
193 * @return boolean value that denotes whether the metric name starts with the given prefix
194 */
195 protected boolean containsName(String full, String prefixes) {
196 String[] prefixArray = StringUtils.split(prefixes, ",");
197 for (String prefix : prefixArray) {
198 if (StringUtils.startsWith(full, StringUtils.trimToEmpty(prefix))) {
199 return true;
200 }
201 }
202 return false;
203 }
204
205 /**
206 * Extracts properties from the component configuration context.
207 *
208 * @param context the component context
209 */
210 private void readComponentConfiguration(ComponentContext context) {
211 Dictionary<?, ?> properties = context.getProperties();
212
Ray Milkey2110e4c2018-10-30 15:49:10 -0700213 String addressStr = Tools.get(properties, ADDRESS);
214 address = addressStr != null ? addressStr : ADDRESS_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700215 log.info("Configured. Ganglia server address is {}", address);
216
Ray Milkey2110e4c2018-10-30 15:49:10 -0700217 String metricNameStr = Tools.get(properties, METRIC_NAMES);
218 metricNames = metricNameStr != null ? metricNameStr : METRIC_NAMES_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700219 log.info("Configured. Metric name is {}", metricNames);
220
Ray Milkey2110e4c2018-10-30 15:49:10 -0700221 Integer portConfigured = Tools.getIntegerProperty(properties, PORT);
Jian Li55cbd5c2016-04-06 09:50:20 -0700222 if (portConfigured == null) {
Ray Milkey2110e4c2018-10-30 15:49:10 -0700223 port = PORT_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700224 log.info("Ganglia port is not configured, default value is {}", port);
225 } else {
226 port = portConfigured;
227 log.info("Configured. Ganglia port is configured to {}", port);
228 }
229
Ray Milkey2110e4c2018-10-30 15:49:10 -0700230 Integer ttlConfigured = Tools.getIntegerProperty(properties, TTL);
Jian Li55cbd5c2016-04-06 09:50:20 -0700231 if (ttlConfigured == null) {
Ray Milkey2110e4c2018-10-30 15:49:10 -0700232 ttl = TTL_DEFAULT;
Jian Li55cbd5c2016-04-06 09:50:20 -0700233 log.info("Ganglia TTL is not configured, default value is {}", ttl);
234 } else {
235 ttl = ttlConfigured;
236 log.info("Configured. Ganglia TTL is configured to {}", ttl);
237 }
238
Ray Milkey2110e4c2018-10-30 15:49:10 -0700239 Boolean monitorAllEnabled = Tools.isPropertyEnabled(properties, MONITOR_ALL);
Jian Li55cbd5c2016-04-06 09:50:20 -0700240 if (monitorAllEnabled == null) {
241 log.info("Monitor all metrics is not configured, " +
242 "using current value of {}", monitorAll);
243 } else {
244 monitorAll = monitorAllEnabled;
245 log.info("Configured. Monitor all metrics is {}",
246 monitorAll ? "enabled" : "disabled");
247 }
248 }
249
250 /**
251 * Configures parameters for GMetric.
252 */
253 private void configGMetric() {
254 try {
255 ganglia = new GMetric(address, port, GANGLIA_MODE, ttl);
256 } catch (IOException e) {
257 log.error("Fail to connect to given ganglia server!");
258 }
259 }
260
261 /**
262 * Builds reporter with the given ganglia metric.
263 *
264 * @param gMetric ganglia metric
265 * @return reporter
266 */
267 private GangliaReporter buildReporter(GMetric gMetric) {
268 MetricRegistry mr = metricsService.getMetricRegistry();
269
270 return GangliaReporter.forRegistry(filter(mr))
271 .convertRatesTo(TimeUnit.SECONDS)
272 .convertDurationsTo(TimeUnit.MILLISECONDS)
273 .build(gMetric);
274 }
275}