blob: 7111fc0dbd7b78f580f63a43b80d71fa11dbfe01 [file] [log] [blame]
boyoung21c5f5f42018-09-27 20:29:41 +09001/*
2 * Copyright 2018-present Open Networking Foundation
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 */
16package org.onosproject.openstacktelemetry.impl;
17
Jian Li69600e02018-12-24 13:21:18 +090018import com.google.common.collect.Sets;
19import io.prometheus.client.Counter;
boyoung2a8549d22018-11-23 20:42:37 +090020import io.prometheus.client.Gauge;
Jian Li69600e02018-12-24 13:21:18 +090021import io.prometheus.client.exporter.MetricsServlet;
22import org.eclipse.jetty.server.Server;
23import org.eclipse.jetty.servlet.ServletContextHandler;
24import org.eclipse.jetty.servlet.ServletHolder;
boyoung2a8549d22018-11-23 20:42:37 +090025import org.onlab.packet.TpPort;
boyoung21c5f5f42018-09-27 20:29:41 +090026import org.onosproject.openstacktelemetry.api.FlowInfo;
27import org.onosproject.openstacktelemetry.api.OpenstackTelemetryService;
28import org.onosproject.openstacktelemetry.api.PrometheusTelemetryAdminService;
Jian Li69600e02018-12-24 13:21:18 +090029import org.onosproject.openstacktelemetry.api.TelemetryConfigService;
boyoung21c5f5f42018-09-27 20:29:41 +090030import org.onosproject.openstacktelemetry.api.config.PrometheusTelemetryConfig;
Ray Milkeydf521292018-10-04 15:13:33 -070031import org.osgi.service.component.annotations.Activate;
32import org.osgi.service.component.annotations.Component;
33import org.osgi.service.component.annotations.Deactivate;
34import org.osgi.service.component.annotations.Reference;
35import org.osgi.service.component.annotations.ReferenceCardinality;
boyoung21c5f5f42018-09-27 20:29:41 +090036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
boyoung2a8549d22018-11-23 20:42:37 +090039import java.util.Arrays;
boyoung21c5f5f42018-09-27 20:29:41 +090040import java.util.Set;
41
Jian Li69600e02018-12-24 13:21:18 +090042import static org.onosproject.openstacktelemetry.api.Constants.PROMETHEUS_SCHEME;
43import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.PROMETHEUS;
44import static org.onosproject.openstacktelemetry.config.DefaultPrometheusTelemetryConfig.fromTelemetryConfig;
45
boyoung21c5f5f42018-09-27 20:29:41 +090046/**
47 * Prometheus telemetry manager.
48 */
boyoung2a8549d22018-11-23 20:42:37 +090049@Component(immediate = true, service = PrometheusTelemetryAdminService.class)
boyoung21c5f5f42018-09-27 20:29:41 +090050public class PrometheusTelemetryManager implements PrometheusTelemetryAdminService {
51
52 private final Logger log = LoggerFactory.getLogger(getClass());
53
Jian Li69600e02018-12-24 13:21:18 +090054 private Set<Server> prometheusExporters = Sets.newConcurrentHashSet();
boyoung21c5f5f42018-09-27 20:29:41 +090055
boyoung2a8549d22018-11-23 20:42:37 +090056 private static final String FLOW_TYPE = "flowType";
57 private static final String DEVICE_ID = "deviceId";
58 private static final String INPUT_INTERFACE_ID = "inputInterfaceId";
59 private static final String OUTPUT_INTERFACE_ID = "outputInterfaceId";
60 private static final String VLAN_ID = "vlanId";
61 private static final String VXLAN_ID = "vxlanId";
62 private static final String SRC_IP = "srcIp";
63 private static final String DST_IP = "dstIp";
64 private static final String SRC_PORT = "srcPort";
65 private static final String DST_PORT = "dstPort";
66 private static final String PROTOCOL = "protocol";
boyoung21c5f5f42018-09-27 20:29:41 +090067
boyoung2a8549d22018-11-23 20:42:37 +090068 private static final String[] LABEL_TAGS = {
69 FLOW_TYPE, DEVICE_ID, INPUT_INTERFACE_ID, OUTPUT_INTERFACE_ID,
70 VLAN_ID, VXLAN_ID, SRC_IP, DST_IP, SRC_PORT, DST_PORT, PROTOCOL
71 };
boyoung21c5f5f42018-09-27 20:29:41 +090072
boyoung2a8549d22018-11-23 20:42:37 +090073 private static final String STAT_NAME_VM2VM_BYTE = "vm2vm_byte";
74 private static final String STAT_NAME_VM2VM_BYTE_PREV = "vm2vm_byte_prev";
75 private static final String STAT_NAME_VM2VM_BYTE_CURR = "vm2vm_byte_curr";
76 private static final String STAT_NAME_VM2VM_PKT = "vm2vm_pkt";
77 private static final String STAT_NAME_VM2VM_PKT_PREV = "vm2vm_pkt_prev";
78 private static final String STAT_NAME_VM2VM_PKT_CURR = "vm2vm_pkt_curr";
79 private static final String STAT_NAME_ERROR_PKT = "error_pkt";
80 private static final String STAT_NAME_DROP_PKT = "drop_pkt";
boyoung21c5f5f42018-09-27 20:29:41 +090081
boyoung2a8549d22018-11-23 20:42:37 +090082 private static final String HELP_MSG_VM2VM_BYTE =
83 "SONA flow bytes statistics for VM to VM";
84 private static final String HELP_MSG_VM2VM_BYTE_PREV =
85 HELP_MSG_VM2VM_BYTE + " [Accumulated previous byte]";
86 private static final String HELP_MSG_VM2VM_BYTE_CURR =
87 HELP_MSG_VM2VM_BYTE + " [Accumulated current byte]";
88 private static final String HELP_MSG_VM2VM_PKT =
89 "SONA flow packets statistics for VM to VM";
90 private static final String HELP_MSG_VM2VM_PKT_PREV =
91 HELP_MSG_VM2VM_PKT + " [Accumulated previous pkt]";
92 private static final String HELP_MSG_VM2VM_PKT_CURR =
93 HELP_MSG_VM2VM_PKT + " [Accumulated current pkt]";
94 private static final String HELP_MSG_ERROR = "SONA error statistics";
95 private static final String HELP_MSG_DROP = "SONA drop statistics";
boyoung21c5f5f42018-09-27 20:29:41 +090096
boyoung2a8549d22018-11-23 20:42:37 +090097 private static Gauge byteVM2VM = Gauge.build()
98 .name(STAT_NAME_VM2VM_BYTE)
99 .help(HELP_MSG_VM2VM_BYTE)
100 .labelNames(LABEL_TAGS)
101 .register();
102 private static Gauge byteVM2VMPrev = Gauge.build()
103 .name(STAT_NAME_VM2VM_BYTE_PREV)
104 .help(HELP_MSG_VM2VM_BYTE_PREV)
105 .labelNames(LABEL_TAGS)
106 .register();
107 private static Gauge byteVM2VMCurr = Gauge.build()
108 .name(STAT_NAME_VM2VM_BYTE_CURR)
109 .help(HELP_MSG_VM2VM_BYTE_CURR)
110 .labelNames(LABEL_TAGS)
111 .register();
112 private static Gauge pktVM2VM = Gauge.build()
113 .name(STAT_NAME_VM2VM_PKT)
114 .help(HELP_MSG_VM2VM_PKT)
115 .labelNames(LABEL_TAGS)
116 .register();
117 private static Gauge pktVM2VMPrev = Gauge.build()
118 .name(STAT_NAME_VM2VM_PKT_PREV)
119 .help(HELP_MSG_VM2VM_PKT_PREV)
120 .labelNames(LABEL_TAGS)
121 .register();
122 private static Gauge pktVM2VMCurr = Gauge.build()
123 .name(STAT_NAME_VM2VM_PKT_CURR)
124 .help(HELP_MSG_VM2VM_PKT_CURR)
125 .labelNames(LABEL_TAGS)
126 .register();
127 private static Counter pktError = Counter.build()
128 .name(STAT_NAME_ERROR_PKT)
129 .help(HELP_MSG_ERROR)
130 .labelNames(LABEL_TAGS)
131 .register();
132 private static Counter pktDrop = Counter.build()
133 .name(STAT_NAME_DROP_PKT)
134 .help(HELP_MSG_DROP)
135 .labelNames(LABEL_TAGS)
136 .register();
boyoung21c5f5f42018-09-27 20:29:41 +0900137
Ray Milkeydf521292018-10-04 15:13:33 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
boyoung21c5f5f42018-09-27 20:29:41 +0900139 protected OpenstackTelemetryService openstackTelemetryService;
140
Jian Li69600e02018-12-24 13:21:18 +0900141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
142 protected TelemetryConfigService telemetryConfigService;
143
boyoung21c5f5f42018-09-27 20:29:41 +0900144 @Activate
145 protected void activate() {
146 openstackTelemetryService.addTelemetryService(this);
147 log.info("Started");
148 }
149
150 @Deactivate
151 protected void deactivate() {
152 stop();
153 openstackTelemetryService.removeTelemetryService(this);
154 log.info("Stopped");
155 }
156
157 @Override
Jian Li69600e02018-12-24 13:21:18 +0900158 public void start() {
boyoung21c5f5f42018-09-27 20:29:41 +0900159 log.info("Prometheus exporter starts.");
160
Jian Li69600e02018-12-24 13:21:18 +0900161 telemetryConfigService.getConfigsByType(PROMETHEUS).forEach(c -> {
162 PrometheusTelemetryConfig prometheusConfig = fromTelemetryConfig(c);
boyoung21c5f5f42018-09-27 20:29:41 +0900163
Jian Li69600e02018-12-24 13:21:18 +0900164 if (prometheusConfig != null &&
165 !c.name().equals(PROMETHEUS_SCHEME) && c.enabled()) {
166 try {
167 // TODO Offer a 'Authentication'
168 Server prometheusExporter = new Server(prometheusConfig.port());
169 ServletContextHandler context = new ServletContextHandler();
170 context.setContextPath("/");
171 prometheusExporter.setHandler(context);
172 context.addServlet(new ServletHolder(new MetricsServlet()), "/metrics");
173
174 log.info("Prometheus server start");
175
176 prometheusExporter.start();
177
178 prometheusExporters.add(prometheusExporter);
179
180 } catch (Exception ex) {
181 log.warn("Exception: {}", ex);
182 }
183 }
184 });
boyoung21c5f5f42018-09-27 20:29:41 +0900185 }
186
187 @Override
188 public void stop() {
Jian Li69600e02018-12-24 13:21:18 +0900189 prometheusExporters.forEach(pe -> {
190 try {
191 pe.stop();
192 } catch (Exception e) {
193 log.warn("Failed to stop prometheus server due to {}", e);
194 }
195 });
boyoung21c5f5f42018-09-27 20:29:41 +0900196 log.info("Prometheus exporter has stopped");
197 }
198
199 @Override
Jian Li69600e02018-12-24 13:21:18 +0900200 public void restart() {
boyoung21c5f5f42018-09-27 20:29:41 +0900201 stop();
Jian Li69600e02018-12-24 13:21:18 +0900202 start();
boyoung21c5f5f42018-09-27 20:29:41 +0900203 }
204
205 @Override
206 public void publish(Set<FlowInfo> flowInfos) {
boyoung2a8549d22018-11-23 20:42:37 +0900207 if (flowInfos.isEmpty()) {
208 log.debug("No FlowInfo record to publish");
boyoung21c5f5f42018-09-27 20:29:41 +0900209 return;
210 }
211
212 long flowByte;
213 int flowPkt;
boyoung2a8549d22018-11-23 20:42:37 +0900214 String[] labelValues;
215
boyoung21c5f5f42018-09-27 20:29:41 +0900216 for (FlowInfo flowInfo: flowInfos) {
217 flowByte = flowInfo.statsInfo().currAccBytes() - flowInfo.statsInfo().prevAccBytes();
218 flowPkt = flowInfo.statsInfo().currAccPkts() - flowInfo.statsInfo().prevAccPkts();
boyoung2a8549d22018-11-23 20:42:37 +0900219 labelValues = getLabelValues(flowInfo);
220 byteVM2VM.labels(labelValues).set(flowByte);
221 byteVM2VMPrev.labels(labelValues).set(flowInfo.statsInfo().prevAccBytes());
222 byteVM2VMCurr.labels(labelValues).set(flowInfo.statsInfo().currAccBytes());
223 pktVM2VM.labels(labelValues).set(flowPkt);
224 pktVM2VMPrev.labels(labelValues).set(flowInfo.statsInfo().prevAccPkts());
225 pktVM2VMCurr.labels(labelValues).set(flowInfo.statsInfo().currAccPkts());
226 pktError.labels(labelValues).inc(flowInfo.statsInfo().errorPkts());
227 pktDrop.labels(labelValues).inc(flowInfo.statsInfo().dropPkts());
boyoung21c5f5f42018-09-27 20:29:41 +0900228 }
229 }
230
boyoung2a8549d22018-11-23 20:42:37 +0900231 private String[] getLabelValues(FlowInfo flowInfo) {
232 String[] labelValues = new String[LABEL_TAGS.length];
233
234 labelValues[Arrays.asList(LABEL_TAGS).indexOf(FLOW_TYPE)]
235 = String.valueOf(flowInfo.flowType());
236 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DEVICE_ID)]
237 = flowInfo.deviceId().toString();
238 labelValues[Arrays.asList(LABEL_TAGS).indexOf(INPUT_INTERFACE_ID)]
239 = String.valueOf(flowInfo.inputInterfaceId());
240 labelValues[Arrays.asList(LABEL_TAGS).indexOf(OUTPUT_INTERFACE_ID)]
241 = String.valueOf(flowInfo.outputInterfaceId());
242 labelValues[Arrays.asList(LABEL_TAGS).indexOf(VXLAN_ID)]
243 = String.valueOf(flowInfo.vxlanId());
244 labelValues[Arrays.asList(LABEL_TAGS).indexOf(SRC_IP)]
245 = flowInfo.srcIp().toString();
246 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DST_IP)]
247 = flowInfo.dstIp().toString();
248 labelValues[Arrays.asList(LABEL_TAGS).indexOf(SRC_PORT)]
249 = getTpPort(flowInfo.srcPort());
250 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DST_PORT)]
251 = getTpPort(flowInfo.dstPort());
252 labelValues[Arrays.asList(LABEL_TAGS).indexOf(PROTOCOL)]
253 = String.valueOf(flowInfo.protocol());
254 if (flowInfo.vlanId() != null) {
255 labelValues[Arrays.asList(LABEL_TAGS).indexOf(VLAN_ID)]
256 = flowInfo.vlanId().toString();
257 }
258 return labelValues;
259 }
260
261 private String getTpPort(TpPort tpPort) {
262 if (tpPort == null) {
263 return "";
264 }
265 return tpPort.toString();
266 }
267
boyoung21c5f5f42018-09-27 20:29:41 +0900268 @Override
269 public boolean isRunning() {
Jian Li69600e02018-12-24 13:21:18 +0900270 return !prometheusExporters.isEmpty();
boyoung21c5f5f42018-09-27 20:29:41 +0900271 }
272}