001package io.prometheus.client.exporter; 002 003import io.prometheus.client.CollectorRegistry; 004import io.prometheus.client.exporter.common.TextFormat; 005 006import java.io.ByteArrayOutputStream; 007import java.io.IOException; 008import java.io.OutputStreamWriter; 009import java.net.InetSocketAddress; 010import java.net.URLDecoder; 011import java.util.Set; 012import java.util.HashSet; 013import java.util.concurrent.Executors; 014 015import com.sun.net.httpserver.HttpHandler; 016import com.sun.net.httpserver.HttpServer; 017import com.sun.net.httpserver.HttpExchange; 018 019/** 020 * Expose Prometheus metrics using a plain Java HttpServer. 021 * <p> 022 * Example Usage: 023 * <pre> 024 * {@code 025 * HTTPServer server = new HTTPServer(1234); 026 * } 027 * </pre> 028 * */ 029public class HTTPServer { 030 static class HTTPMetricHandler implements HttpHandler { 031 private CollectorRegistry registry; 032 033 HTTPMetricHandler(CollectorRegistry registry) { 034 this.registry = registry; 035 } 036 037 038 public void handle(HttpExchange t) throws IOException { 039 String query = t.getRequestURI().getRawQuery(); 040 041 ByteArrayOutputStream response = new ByteArrayOutputStream(1 << 20); 042 OutputStreamWriter osw = new OutputStreamWriter(response); 043 TextFormat.write004(osw, 044 registry.filteredMetricFamilySamples(parseQuery(query))); 045 osw.flush(); 046 osw.close(); 047 response.flush(); 048 response.close(); 049 050 t.getResponseHeaders().set("Content-Type", 051 TextFormat.CONTENT_TYPE_004); 052 t.getResponseHeaders().set("Content-Length", 053 String.valueOf(response.size())); 054 t.sendResponseHeaders(200, response.size()); 055 response.writeTo(t.getResponseBody()); 056 t.close(); 057 } 058 059 } 060 061 protected static Set<String> parseQuery(String query) throws IOException { 062 Set<String> names = new HashSet<String>(); 063 if (query != null) { 064 String[] pairs = query.split("&"); 065 for (String pair : pairs) { 066 int idx = pair.indexOf("="); 067 if (idx != -1 && URLDecoder.decode(pair.substring(0, idx), "UTF-8").equals("name[]")) { 068 names.add(URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); 069 } 070 } 071 } 072 return names; 073 } 074 075 protected HttpServer server; 076 077 078 /** 079 * Start a HTTP server serving Prometheus metrics from the given registry. 080 */ 081 public HTTPServer(InetSocketAddress addr, CollectorRegistry registry) throws IOException { 082 server = HttpServer.create(); 083 server.bind(addr, 3); 084 HttpHandler mHandler = new HTTPMetricHandler(registry); 085 server.createContext("/", mHandler); 086 server.createContext("/metrics", mHandler); 087 server.setExecutor(Executors.newFixedThreadPool(5)); 088 server.start(); 089 } 090 091 /** 092 * Start a HTTP server serving the default Prometheus registry. 093 */ 094 public HTTPServer(int port) throws IOException { 095 this(new InetSocketAddress(port), CollectorRegistry.defaultRegistry); 096 } 097 098 /** 099 * Start a HTTP server serving the default Prometheus registry. 100 */ 101 public HTTPServer(String host, int port) throws IOException { 102 this(new InetSocketAddress(host, port), CollectorRegistry.defaultRegistry); 103 } 104 105 /** 106 * Stop the HTTP server. 107 */ 108 public void stop() { 109 server.stop(0); 110 } 111} 112