blob: 7695c95880b7f7b785ad679a8632851ff26f00cf [file] [log] [blame]
Jian Li7261c7b2016-03-05 00:04:55 -08001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
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 */
Jian Lic0fe42d2016-03-28 15:19:16 -070016package org.onosproject.gangliametrics;
Jian Li7261c7b2016-03-05 00:04:55 -080017
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.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.osgi.service.component.ComponentContext;
35import org.slf4j.Logger;
36
37import java.io.IOException;
38import java.util.Dictionary;
39import java.util.concurrent.TimeUnit;
40
41import static org.slf4j.LoggerFactory.getLogger;
42
43/**
44 * A metric report that reports all metrics value to ganglia monitoring server.
45 */
46@Component(immediate = true)
47public class GangliaMetricsReporter implements MetricsReporter {
48 private final Logger log = getLogger(getClass());
49
50 // we will use uni-cast mode to transfer the metrics value by default
51 private static final GMetric.UDPAddressingMode GANGLIA_MODE =
52 GMetric.UDPAddressingMode.UNICAST;
53 private static final int REPORT_PERIOD = 1;
54 private static final TimeUnit REPORT_TIME_UNIT = TimeUnit.MINUTES;
55
56 private static final String DEFAULT_ADDRESS = "localhost";
57 private static final int DEFAULT_PORT = 8649;
58 private static final int DEFAULT_TTL = 1;
59 private static final String DEFAULT_METRIC_NAMES = "default";
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 @Property(name = "monitorAll", boolValue = true,
71 label = "Enable to monitor all of metrics stored in metric registry default is true")
72 protected boolean monitorAll = true;
73
74 @Property(name = "metricNames", value = DEFAULT_METRIC_NAMES,
75 label = "Names of metric to be monitored; default metric names are 'default'")
76 protected String metricNames = DEFAULT_METRIC_NAMES;
77
78 @Property(name = "address", value = DEFAULT_ADDRESS,
79 label = "IP address of ganglia monitoring server; default is localhost")
80 protected String address = DEFAULT_ADDRESS;
81
82 @Property(name = "port", intValue = DEFAULT_PORT,
83 label = "Port number of ganglia monitoring server; default is 8649")
84 protected int port = DEFAULT_PORT;
85
86 @Property(name = "ttl", intValue = DEFAULT_TTL,
87 label = "TTL value of ganglia monitoring server; default is 1")
88 protected int ttl = DEFAULT_TTL;
89
90 private ApplicationId appId;
91 private GMetric ganglia;
92 private GangliaReporter gangliaReporter;
93
94 @Activate
95 public void activate() {
96 cfgService.registerProperties(getClass());
97 appId = coreService.registerApplication("org.onosproject.metrics.reporter");
98
99 startReport();
100 log.info("Started");
101 }
102
103 @Deactivate
104 public void deactivate() {
105 cfgService.unregisterProperties(getClass(), false);
106
107 stopReport();
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 try {
121 ganglia = new GMetric(address, port, GANGLIA_MODE, ttl);
122
123 MetricRegistry mr = metricsService.getMetricRegistry();
124
125 gangliaReporter = GangliaReporter.forRegistry(filter(mr))
126 .convertRatesTo(TimeUnit.SECONDS)
127 .convertDurationsTo(TimeUnit.MILLISECONDS)
128 .build(ganglia);
129 gangliaReporter.start(REPORT_PERIOD, REPORT_TIME_UNIT);
130 } catch (IOException e) {
131 log.error("Fail to connect to given ganglia server!");
132 }
133 }
134
135 @Override
136 public void stopReport() {
137 gangliaReporter.stop();
138 ganglia = null;
139 gangliaReporter = null;
140 }
141
142 /**
143 * Filters the metrics to only include a set of the given metrics.
144 *
145 * @param metricRegistry original metric registry
146 * @return filtered metric registry
147 */
148 protected MetricRegistry filter(MetricRegistry metricRegistry) {
149 if (!monitorAll) {
150 final MetricRegistry filtered = new MetricRegistry();
151 metricRegistry.getNames().stream().filter(name ->
152 containsName(name, metricNames)).forEach(name ->
153 filtered.register(name, metricRegistry.getMetrics().get(name)));
154 return filtered;
155 } else {
156 return metricRegistry;
157 }
158 }
159
160 /**
161 * Looks up whether the metric name contains the given prefix keywords.
162 * Note that the keywords are separated with comma as delimiter
163 *
164 * @param full the original metric name that to be compared with
165 * @param prefixes the prefix keywords that are matched against with the metric name
166 * @return boolean value that denotes whether the metric name starts with the given prefix
167 */
168 protected boolean containsName(String full, String prefixes) {
169 String[] prefixArray = StringUtils.split(prefixes, ",");
170 for (String prefix : prefixArray) {
171 if (StringUtils.startsWith(full, StringUtils.trimToEmpty(prefix))) {
172 return true;
173 }
174 }
175 return false;
176 }
177
178 /**
179 * Extracts properties from the component configuration context.
180 *
181 * @param context the component context
182 */
183 private void readComponentConfiguration(ComponentContext context) {
184 Dictionary<?, ?> properties = context.getProperties();
185
186 String addressStr = Tools.get(properties, "address");
187 address = addressStr != null ? addressStr : DEFAULT_ADDRESS;
188 log.info("Configured. Ganglia server address is {}", address);
189
190 String metricNameStr = Tools.get(properties, "metricNames");
191 metricNames = metricNameStr != null ? metricNameStr : DEFAULT_METRIC_NAMES;
192 log.info("Configured. Metric name is {}", metricNames);
193
194 Integer portConfigured = Tools.getIntegerProperty(properties, "port");
195 if (portConfigured == null) {
196 port = DEFAULT_PORT;
197 log.info("Ganglia port is not configured, default value is {}", port);
198 } else {
199 port = portConfigured;
200 log.info("Configured. Ganglia port is configured to {}", port);
201 }
202
203 Integer ttlConfigured = Tools.getIntegerProperty(properties, "ttl");
204 if (ttlConfigured == null) {
205 ttl = DEFAULT_TTL;
206 log.info("Ganglia TTL is not configured, default value is {}", ttl);
207 } else {
208 ttl = ttlConfigured;
209 log.info("Configured. Ganglia TTL is configured to {}", ttl);
210 }
211
212 Boolean monitorAllEnabled = Tools.isPropertyEnabled(properties, "monitorAll");
213 if (monitorAllEnabled == null) {
214 log.info("Monitor all metrics is not configured, " +
215 "using current value of {}", monitorAll);
216 } else {
217 monitorAll = monitorAllEnabled;
218 log.info("Configured. Monitor all metrics is {}",
219 monitorAll ? "enabled" : "disabled");
220 }
221 }
222}