001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.metrics; 020 021import com.sun.net.httpserver.HttpServer; 022import org.jdom2.Element; 023import org.jpos.core.ConfigurationException; 024import org.jpos.core.annotation.Config; 025import org.jpos.q2.QBeanSupport; 026 027import java.io.IOException; 028import java.io.OutputStream; 029import java.net.InetSocketAddress; 030 031public class PrometheusService extends QBeanSupport { 032 @Config("port") 033 private int port; 034 @Config("path") 035 private String path; 036 @Config("status-path") 037 private String statusPath; 038 private HttpServer server; 039 040 @Override 041 protected void initService() throws ConfigurationException { 042 try { 043 final var registry = getServer().getPrometheusMeterRegistry(); 044 server = HttpServer.create(new InetSocketAddress(port), 0); 045 server.createContext(path, httpExchange -> { 046 String response = registry.scrape(); 047 httpExchange.getResponseHeaders().add("Content-Type", "text/plain; version=0.0.4"); 048 httpExchange.sendResponseHeaders(200, response.getBytes().length); 049 try (OutputStream os = httpExchange.getResponseBody()) { 050 os.write(response.getBytes()); 051 } 052 }); 053 if (statusPath != null) { 054 server.createContext(statusPath, httpExchange -> { 055 String response = getServer().running() ? "running\n" : "stopping\n"; 056 httpExchange.getResponseHeaders().add("Content-Type", "text/plain"); 057 httpExchange.sendResponseHeaders(200, response.getBytes().length); 058 try (OutputStream os = httpExchange.getResponseBody()) { 059 os.write(response.getBytes()); 060 } 061 }); 062 } 063 Thread.ofVirtual().start(server::start); 064 } catch (IOException e) { 065 getLog().warn(e); 066 throw new RuntimeException(e); 067 } 068 } 069 070 @Override 071 protected void stopService() { 072 server.stop(2); 073 } 074 075 public static Element createDescriptor (int port, String path, String statusPath) { 076 return new Element("prometheus") 077 .addContent(createProperty ("port", Integer.toString(port))) 078 .addContent (createProperty ("path", path)) 079 .addContent (createProperty ("status-path", statusPath)); 080 081 } 082 private static Element createProperty (String name, String value) { 083 return new Element ("property") 084 .setAttribute("name", name) 085 .setAttribute("value", value); 086 } 087}