| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sling.metrics.prometheus.impl; |
| |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| |
| import javax.servlet.Servlet; |
| import javax.servlet.ServletException; |
| |
| import org.osgi.service.component.annotations.Component; |
| import org.osgi.service.component.annotations.Reference; |
| import org.osgi.service.component.annotations.ReferenceCardinality; |
| import org.osgi.service.component.annotations.ReferencePolicy; |
| import org.osgi.service.component.annotations.ReferencePolicyOption; |
| import org.osgi.service.http.whiteboard.propertytypes.HttpWhiteboardContextSelect; |
| import org.osgi.service.http.whiteboard.propertytypes.HttpWhiteboardServletPattern; |
| import org.osgi.service.metatype.annotations.Designate; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.codahale.metrics.Counter; |
| import com.codahale.metrics.Gauge; |
| import com.codahale.metrics.Histogram; |
| import com.codahale.metrics.Meter; |
| import com.codahale.metrics.Metric; |
| import com.codahale.metrics.MetricRegistry; |
| import com.codahale.metrics.MetricRegistryListener; |
| import com.codahale.metrics.Timer; |
| |
| import io.prometheus.client.CollectorRegistry; |
| import io.prometheus.client.dropwizard.DropwizardExports; |
| import io.prometheus.client.exporter.MetricsServlet; |
| |
| @HttpWhiteboardServletPattern("/metrics") |
| @HttpWhiteboardContextSelect("(osgi.http.whiteboard.context.name=org.osgi.service.http)") |
| @Component(service = Servlet.class) |
| @Designate(ocd = WrapperMetricsServletConfiguration.class) |
| public class WrapperMetricsServlet extends MetricsServlet { |
| |
| private static final long serialVersionUID = 1L; |
| |
| private final MetricRegistry metrics = new MetricRegistry(); |
| @SuppressWarnings("squid:S2226") |
| private DropwizardExports exports; |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| private final ConcurrentMap<MetricRegistry, CopyMetricRegistryListener> childRegistries = new ConcurrentHashMap<>(); |
| |
| @Override |
| public void init() throws ServletException { |
| super.init(); |
| this.exports = new DropwizardExports(metrics); |
| CollectorRegistry.defaultRegistry.register(this.exports); |
| } |
| |
| @Override |
| public void destroy() { |
| CollectorRegistry.defaultRegistry.unregister(this.exports); |
| super.destroy(); |
| } |
| |
| @Reference(service = MetricRegistry.class, cardinality = ReferenceCardinality.MULTIPLE, |
| policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) |
| void bindMetricRegistry(MetricRegistry metricRegistry, Map<String, Object> properties) { |
| |
| log.info("Binding Metrics Registry..."); |
| |
| String name = registryName(metricRegistry, properties); |
| |
| CopyMetricRegistryListener listener = new CopyMetricRegistryListener(this.metrics, metricRegistry, name); |
| listener.start(); |
| childRegistries.put(metricRegistry, listener); |
| log.info("Bound Metrics Registry {} ", name); |
| } |
| |
| void unbindMetricRegistry(MetricRegistry metricRegistry, Map<String, Object> properties) { |
| String name = registryName(metricRegistry, properties); |
| |
| CopyMetricRegistryListener metricRegistryListener = childRegistries.remove(metricRegistry); |
| if (metricRegistryListener != null) |
| metricRegistryListener.stop(); |
| log.info("Unbound Metrics Registry {} ", name); |
| } |
| |
| private String registryName(MetricRegistry metricRegistry, Map<String, Object> properties) { |
| String name = (String) properties.get("name"); |
| if (name == null) |
| name = metricRegistry.toString(); |
| return name; |
| } |
| |
| static class CopyMetricRegistryListener implements MetricRegistryListener { |
| |
| private MetricRegistry parent; |
| private MetricRegistry child; |
| private String name; |
| |
| public CopyMetricRegistryListener(MetricRegistry parent, MetricRegistry child, String name) { |
| this.parent = parent; |
| this.child = child; |
| this.name = name; |
| } |
| |
| public void start() { |
| child.addListener(this); |
| } |
| |
| public void stop() { |
| child.removeListener(this); |
| child.getMetrics().keySet().stream() |
| .map( this::getMetricName ) |
| .forEach( this::removeMetric ); |
| } |
| |
| @Override |
| public void onGaugeAdded(String name, Gauge<?> gauge) { |
| addMetric(name, gauge); |
| |
| } |
| |
| @Override |
| public void onGaugeRemoved(String name) { |
| removeMetric(name); |
| |
| } |
| |
| @Override |
| public void onCounterAdded(String name, Counter counter) { |
| addMetric(name, counter); |
| } |
| |
| @Override |
| public void onCounterRemoved(String name) { |
| removeMetric(name); |
| } |
| |
| @Override |
| public void onHistogramAdded(String name, Histogram histogram) { |
| addMetric(name, histogram); |
| } |
| |
| @Override |
| public void onHistogramRemoved(String name) { |
| removeMetric(name); |
| } |
| |
| @Override |
| public void onMeterAdded(String name, Meter meter) { |
| addMetric(name, meter); |
| } |
| |
| @Override |
| public void onMeterRemoved(String name) { |
| removeMetric(name); |
| } |
| |
| @Override |
| public void onTimerAdded(String name, Timer timer) { |
| addMetric(name, timer); |
| } |
| |
| @Override |
| public void onTimerRemoved(String name) { |
| removeMetric(name); |
| } |
| |
| private void addMetric(String metricName, Metric m) { |
| parent.register(getMetricName(metricName), m); |
| } |
| |
| private void removeMetric(String metricName) { |
| parent.remove(getMetricName(metricName)); |
| } |
| |
| private String getMetricName(String metricName) { |
| return name + "_" + metricName; |
| } |
| } |
| } |