diff --git a/enterprise/metrics/src/main/java/org/neo4j/metrics/output/PrometheusHttpServer.java b/enterprise/metrics/src/main/java/org/neo4j/metrics/output/PrometheusHttpServer.java new file mode 100644 index 0000000000000..723a3a976888c --- /dev/null +++ b/enterprise/metrics/src/main/java/org/neo4j/metrics/output/PrometheusHttpServer.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j Enterprise Edition. The included source + * code can be redistributed and/or modified under the terms of the + * GNU AFFERO GENERAL PUBLIC LICENSE Version 3 + * (http://www.fsf.org/licensing/licenses/agpl-3.0.html) with the + * Commons Clause, as found in the associated LICENSE.txt file. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * Neo4j object code can be licensed independently from the source + * under separate terms from the AGPL. Inquiries can be directed to: + * licensing@neo4j.com + * + * More information is also available at: + * https://neo4j.com/licensing/ + */ +package org.neo4j.metrics.output; + +import io.prometheus.client.exporter.HTTPServer; + +import java.io.IOException; +import java.net.InetSocketAddress; + +class PrometheusHttpServer extends HTTPServer +{ + PrometheusHttpServer( String host, int port ) throws IOException + { + super( host, port, true ); + } + + InetSocketAddress getAddress() + { + return server.getAddress(); + } +} diff --git a/enterprise/metrics/src/main/java/org/neo4j/metrics/output/PrometheusOutput.java b/enterprise/metrics/src/main/java/org/neo4j/metrics/output/PrometheusOutput.java index 62d632eff4608..8eeb21e2fa4e2 100644 --- a/enterprise/metrics/src/main/java/org/neo4j/metrics/output/PrometheusOutput.java +++ b/enterprise/metrics/src/main/java/org/neo4j/metrics/output/PrometheusOutput.java @@ -30,7 +30,6 @@ import com.codahale.metrics.Timer; import io.prometheus.client.CollectorRegistry; import io.prometheus.client.dropwizard.DropwizardExports; -import io.prometheus.client.exporter.HTTPServer; import java.util.Map; import java.util.SortedMap; @@ -45,15 +44,14 @@ */ public class PrometheusOutput implements Lifecycle, EventReporter { + protected PrometheusHttpServer server; private final HostnamePort hostnamePort; private final MetricRegistry registry; private final Log logger; - - private HTTPServer server; - private Map registeredEvents = new ConcurrentHashMap<>(); + private final Map registeredEvents = new ConcurrentHashMap<>(); private final MetricRegistry eventRegistry; - public PrometheusOutput( HostnamePort hostnamePort, MetricRegistry registry, Log logger ) + PrometheusOutput( HostnamePort hostnamePort, MetricRegistry registry, Log logger ) { this.hostnamePort = hostnamePort; this.registry = registry; @@ -76,7 +74,7 @@ public void start() throws Throwable { if ( server == null ) { - server = new HTTPServer( hostnamePort.getHost(), hostnamePort.getPort(), true ); + server = new PrometheusHttpServer( hostnamePort.getHost(), hostnamePort.getPort() ); logger.info( "Started publishing Prometheus metrics at http://" + hostnamePort + "/metrics" ); } } diff --git a/enterprise/metrics/src/test/java/org/neo4j/metrics/output/PrometheusOutputTest.java b/enterprise/metrics/src/test/java/org/neo4j/metrics/output/PrometheusOutputTest.java index 15f318027b7dd..4a44744d461c7 100644 --- a/enterprise/metrics/src/test/java/org/neo4j/metrics/output/PrometheusOutputTest.java +++ b/enterprise/metrics/src/test/java/org/neo4j/metrics/output/PrometheusOutputTest.java @@ -25,9 +25,9 @@ import com.codahale.metrics.Gauge; import com.codahale.metrics.MetricRegistry; import org.junit.Test; -import org.mockito.Mockito; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.URL; import java.net.URLConnection; import java.util.Scanner; @@ -36,34 +36,33 @@ import org.neo4j.helpers.HostnamePort; import org.neo4j.logging.Log; -import org.neo4j.ports.allocation.PortAuthority; import static java.util.Collections.emptySortedMap; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; public class PrometheusOutputTest { @Test public void eventsShouldBeRedirectedToGauges() throws Throwable { - String serverAddress = "localhost:" + PortAuthority.allocatePort(); MetricRegistry registry = new MetricRegistry(); - PrometheusOutput prometheusOutput = - new PrometheusOutput( new HostnamePort( serverAddress ), registry, Mockito.mock( Log.class ) ); + DynamicAddressPrometheusOutput dynamicOutput = new DynamicAddressPrometheusOutput( "localhost", registry, mock( Log.class ) ); LongConsumer callback = l -> { TreeMap gauges = new TreeMap<>(); gauges.put( "my.event", () -> l ); - prometheusOutput.report( gauges, emptySortedMap(), emptySortedMap(), emptySortedMap(), emptySortedMap() ); + dynamicOutput.report( gauges, emptySortedMap(), emptySortedMap(), emptySortedMap(), emptySortedMap() ); }; callback.accept( 10 ); - prometheusOutput.init(); - prometheusOutput.start(); + dynamicOutput.init(); + dynamicOutput.start(); + String serverAddress = dynamicOutput.getServerAddress(); assertTrue( getResponse( serverAddress ).contains( "my_event 10.0" ) ); assertTrue( getResponse( serverAddress ).contains( "my_event 10.0" ) ); @@ -75,42 +74,55 @@ public void eventsShouldBeRedirectedToGauges() throws Throwable @Test public void metricsRegisteredAfterStartShouldBeIncluded() throws Throwable { - String serverAddress = "localhost:" + PortAuthority.allocatePort(); MetricRegistry registry = new MetricRegistry(); - PrometheusOutput prometheusOutput = - new PrometheusOutput( new HostnamePort( serverAddress ), registry, Mockito.mock( Log.class ) ); + DynamicAddressPrometheusOutput dynamicOutput = new DynamicAddressPrometheusOutput( "localhost", registry, mock( Log.class ) ); LongConsumer callback = l -> { TreeMap gauges = new TreeMap<>(); gauges.put( "my.event", () -> l ); - prometheusOutput.report( gauges, emptySortedMap(), emptySortedMap(), emptySortedMap(), emptySortedMap() ); + dynamicOutput.report( gauges, emptySortedMap(), emptySortedMap(), emptySortedMap(), emptySortedMap() ); }; registry.register( "my.metric", (Gauge) () -> 10 ); - prometheusOutput.init(); - prometheusOutput.start(); + dynamicOutput.init(); + dynamicOutput.start(); callback.accept( 20 ); + String serverAddress = dynamicOutput.getServerAddress(); String response = getResponse( serverAddress ); assertTrue( response.contains( "my_metric 10.0" ) ); assertTrue( response.contains( "my_event 20.0" ) ); } - private String getResponse( String serverAddress ) throws IOException + private static String getResponse( String serverAddress ) throws IOException { String url = "http://" + serverAddress + "/metrics"; URLConnection connection = new URL( url ).openConnection(); connection.setDoOutput( true ); connection.connect(); - Scanner s = new Scanner( connection.getInputStream(), "UTF-8" ).useDelimiter( "\\A" ); + try ( Scanner s = new Scanner( connection.getInputStream(), "UTF-8" ).useDelimiter( "\\A" ) ) + { + assertTrue( s.hasNext() ); + String ret = s.next(); + assertFalse( s.hasNext() ); + return ret; + } + } + + private static class DynamicAddressPrometheusOutput extends PrometheusOutput + { + DynamicAddressPrometheusOutput( String host, MetricRegistry registry, Log logger ) + { + super( new HostnamePort( host ), registry, logger ); + } - assertTrue( s.hasNext() ); - String ret = s.next(); - assertFalse( s.hasNext() ); - s.close(); - return ret; + String getServerAddress() + { + InetSocketAddress address = server.getAddress(); + return address.getHostString() + ":" + address.getPort(); + } } }