blob: 742564ab38d801cd55909009808927a84120034d [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
39import static org.slf4j.LoggerFactory.getLogger;
40
41/**
42 * A metric report that reports all metrics value to ganglia monitoring server.
43 */
44@Component(immediate = true)
45public class DefaultGangliaMetricsReporter implements GangliaMetricsReporter {
46 private final Logger log = getLogger(getClass());
47
48 // we will use uni-cast mode to transfer the metrics value by default
49 private static final GMetric.UDPAddressingMode GANGLIA_MODE =
50 GMetric.UDPAddressingMode.UNICAST;
51 private static final int REPORT_PERIOD = 1;
52 private static final TimeUnit REPORT_TIME_UNIT = TimeUnit.MINUTES;
53
54 private static final String DEFAULT_ADDRESS = "localhost";
55 private static final int DEFAULT_PORT = 8649;
56 private static final int DEFAULT_TTL = 1;
57 private static final String DEFAULT_METRIC_NAMES = "default";
58
Ray Milkeyd84f89b2018-08-17 14:54:17 -070059 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070060 protected CoreService coreService;
61
Ray Milkeyd84f89b2018-08-17 14:54:17 -070062 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070063 protected MetricsService metricsService;
64
Ray Milkeyd84f89b2018-08-17 14:54:17 -070065 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li55cbd5c2016-04-06 09:50:20 -070066 protected ComponentConfigService cfgService;
67
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068 //@Property(name = "monitorAll", boolValue = true,
69 // label = "Enable to monitor all of metrics stored in metric registry default is true")
Jian Li55cbd5c2016-04-06 09:50:20 -070070 protected boolean monitorAll = true;
71
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 //@Property(name = "metricNames", value = DEFAULT_METRIC_NAMES,
73 // label = "Names of metric to be monitored; default metric names are 'default'")
Jian Li55cbd5c2016-04-06 09:50:20 -070074 protected String metricNames = DEFAULT_METRIC_NAMES;
75
Ray Milkeyd84f89b2018-08-17 14:54:17 -070076 //@Property(name = "address", value = DEFAULT_ADDRESS,
77 // label = "IP address of ganglia monitoring server; default is localhost")
Jian Li55cbd5c2016-04-06 09:50:20 -070078 protected String address = DEFAULT_ADDRESS;
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 //@Property(name = "port", intValue = DEFAULT_PORT,
81 // label = "Port number of ganglia monitoring server; default is 8649")
Jian Li55cbd5c2016-04-06 09:50:20 -070082 protected int port = DEFAULT_PORT;
83
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084 //@Property(name = "ttl", intValue = DEFAULT_TTL,
85 // label = "TTL value of ganglia monitoring server; default is 1")
Jian Li55cbd5c2016-04-06 09:50:20 -070086 protected int ttl = DEFAULT_TTL;
87
88 private GMetric ganglia;
89 private GangliaReporter gangliaReporter;
90
91 @Activate
92 public void activate() {
93 cfgService.registerProperties(getClass());
Jian Li279130d2016-04-06 16:29:44 -070094 coreService.registerApplication("org.onosproject.gangliametrics");
Jian Li55cbd5c2016-04-06 09:50:20 -070095 metricsService.registerReporter(this);
96
97 startReport();
98 log.info("Started");
99 }
100
101 @Deactivate
102 public void deactivate() {
103 cfgService.unregisterProperties(getClass(), false);
104
105 stopReport();
106 metricsService.unregisterReporter(this);
107
108 log.info("Stopped");
109 }
110
111 @Modified
112 public void modified(ComponentContext context) {
113 readComponentConfiguration(context);
114 stopReport();
115 startReport();
116 }
117
118 @Override
119 public void startReport() {
120 configGMetric();
121 gangliaReporter = buildReporter(ganglia);
Jian Li279130d2016-04-06 16:29:44 -0700122
123 try {
124 gangliaReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
125 } catch (Exception e) {
126 log.error("Errors during reporting to ganglia, msg: {}" + e.getMessage());
127 }
128
Jian Li55cbd5c2016-04-06 09:50:20 -0700129 log.info("Start to report metrics to ganglia server.");
130 }
131
132 @Override
133 public void stopReport() {
134 gangliaReporter.stop();
135 ganglia = null;
136 gangliaReporter = null;
137 log.info("Stop reporting metrics to ganglia server.");
138 }
139
140 @Override
141 public void restartReport() {
142 stopReport();
143 startReport();
144 }
145
146 @Override
147 public void notifyMetricsChange() {
148 gangliaReporter.stop();
149 gangliaReporter = buildReporter(ganglia);
Jian Li279130d2016-04-06 16:29:44 -0700150
151 try {
152 gangliaReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
153 } catch (Exception e) {
154 log.error("Errors during reporting to ganglia, 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 /**
161 * Filters the metrics to only include a set of the given metrics.
162 *
163 * @param metricRegistry original metric registry
164 * @return filtered metric registry
165 */
166 protected MetricRegistry filter(MetricRegistry metricRegistry) {
167 if (!monitorAll) {
168 final MetricRegistry filtered = new MetricRegistry();
169 metricRegistry.getNames().stream().filter(name ->
170 containsName(name, metricNames)).forEach(name ->
171 filtered.register(name, metricRegistry.getMetrics().get(name)));
172 return filtered;
173 } else {
174 return metricRegistry;
175 }
176 }
177
178 /**
179 * Looks up whether the metric name contains the given prefix keywords.
180 * Note that the keywords are separated with comma as delimiter
181 *
182 * @param full the original metric name that to be compared with
183 * @param prefixes the prefix keywords that are matched against with the metric name
184 * @return boolean value that denotes whether the metric name starts with the given prefix
185 */
186 protected boolean containsName(String full, String prefixes) {
187 String[] prefixArray = StringUtils.split(prefixes, ",");
188 for (String prefix : prefixArray) {
189 if (StringUtils.startsWith(full, StringUtils.trimToEmpty(prefix))) {
190 return true;
191 }
192 }
193 return false;
194 }
195
196 /**
197 * Extracts properties from the component configuration context.
198 *
199 * @param context the component context
200 */
201 private void readComponentConfiguration(ComponentContext context) {
202 Dictionary<?, ?> properties = context.getProperties();
203
204 String addressStr = Tools.get(properties, "address");
205 address = addressStr != null ? addressStr : DEFAULT_ADDRESS;
206 log.info("Configured. Ganglia server address is {}", address);
207
208 String metricNameStr = Tools.get(properties, "metricNames");
209 metricNames = metricNameStr != null ? metricNameStr : DEFAULT_METRIC_NAMES;
210 log.info("Configured. Metric name is {}", metricNames);
211
212 Integer portConfigured = Tools.getIntegerProperty(properties, "port");
213 if (portConfigured == null) {
214 port = DEFAULT_PORT;
215 log.info("Ganglia port is not configured, default value is {}", port);
216 } else {
217 port = portConfigured;
218 log.info("Configured. Ganglia port is configured to {}", port);
219 }
220
221 Integer ttlConfigured = Tools.getIntegerProperty(properties, "ttl");
222 if (ttlConfigured == null) {
223 ttl = DEFAULT_TTL;
224 log.info("Ganglia TTL is not configured, default value is {}", ttl);
225 } else {
226 ttl = ttlConfigured;
227 log.info("Configured. Ganglia TTL is configured to {}", ttl);
228 }
229
230 Boolean monitorAllEnabled = Tools.isPropertyEnabled(properties, "monitorAll");
231 if (monitorAllEnabled == null) {
232 log.info("Monitor all metrics is not configured, " +
233 "using current value of {}", monitorAll);
234 } else {
235 monitorAll = monitorAllEnabled;
236 log.info("Configured. Monitor all metrics is {}",
237 monitorAll ? "enabled" : "disabled");
238 }
239 }
240
241 /**
242 * Configures parameters for GMetric.
243 */
244 private void configGMetric() {
245 try {
246 ganglia = new GMetric(address, port, GANGLIA_MODE, ttl);
247 } catch (IOException e) {
248 log.error("Fail to connect to given ganglia server!");
249 }
250 }
251
252 /**
253 * Builds reporter with the given ganglia metric.
254 *
255 * @param gMetric ganglia metric
256 * @return reporter
257 */
258 private GangliaReporter buildReporter(GMetric gMetric) {
259 MetricRegistry mr = metricsService.getMetricRegistry();
260
261 return GangliaReporter.forRegistry(filter(mr))
262 .convertRatesTo(TimeUnit.SECONDS)
263 .convertDurationsTo(TimeUnit.MILLISECONDS)
264 .build(gMetric);
265 }
266}