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