瀏覽代碼

Refactored to chain of responsibility pattern

Raymond Edah 7 年之前
父節點
當前提交
e85b30c409

+ 3 - 0
src/main/java/nu/ltd/fp/se/Constant.java

@@ -2,4 +2,7 @@ package nu.ltd.fp.se;
 
 public class Constant {
   public static final String SERVICE_PORT = "service.port";
+  public static final String ROOT_PATH = "/";
+  public static final String METRICS_PATH = "/metrics";
+  public static final Integer LISTEN_PORT = 18089;
 }

+ 67 - 0
src/main/java/nu/ltd/fp/se/MetricsHandler.java

@@ -0,0 +1,67 @@
+package nu.ltd.fp.se;
+
+import io.prometheus.client.CollectorRegistry;
+import io.prometheus.client.exporter.common.TextFormat;
+import io.vertx.core.Handler;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.ext.web.RoutingContext;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * See https://github.com/prometheus/client_java/blob/master/simpleclient_vertx/src/main/java/io/prometheus/client/vertx/MetricsHandler.java
+ */
+
+public class MetricsHandler implements Handler<RoutingContext> {
+  private static class BufferWriter extends Writer {
+
+    private final Buffer buffer = Buffer.buffer();
+
+    @Override
+    public void write(char[] characterBuffer, int off, int len) throws IOException {
+      buffer.appendString(new String(characterBuffer, off, len));
+    }
+
+    @Override
+    public void flush() throws IOException { }
+
+    @Override
+    public void close() throws IOException {  }
+
+    Buffer getBuffer() {
+      return buffer;
+    }
+  }
+
+  private CollectorRegistry registry;
+
+  public MetricsHandler() {
+    this(CollectorRegistry.defaultRegistry);
+  }
+
+  public MetricsHandler(CollectorRegistry registry) {
+    this.registry = registry;
+  }
+
+  @Override
+  public void handle(RoutingContext routingContext) {
+    try {
+      final BufferWriter writer = new BufferWriter();
+      TextFormat.write004(writer, registry.filteredMetricFamilySamples(parse(routingContext.request())));
+      routingContext.response()
+        .setStatusCode(200)
+        .putHeader("Content-Type", TextFormat.CONTENT_TYPE_004)
+        .end(writer.getBuffer());
+    } catch (IOException e) {
+      routingContext.fail(e);
+    }
+  }
+
+  private Set<String> parse(HttpServerRequest request) {
+    return new HashSet(request.params().getAll("name[]"));
+  }
+}

+ 13 - 2
src/main/java/nu/ltd/fp/se/SmartOSExporter.java

@@ -4,12 +4,15 @@ import io.vertx.core.AbstractVerticle;
 import io.vertx.core.Future;
 import io.vertx.core.http.HttpServerResponse;
 import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
 import io.vertx.ext.web.handler.BodyHandler;
 
 public class SmartOSExporter extends AbstractVerticle {
 
   private SmartOSExporter smartOSExporter;
   private String mainPage;
+  private SystemMetrics systemMetrics;
+  private MetricsHandler metricsHandler;
 
   @Override
   public void start(Future<Void> future) {
@@ -18,12 +21,13 @@ public class SmartOSExporter extends AbstractVerticle {
     router.route().handler(BodyHandler.create());
 
     // Route / url
-    router.route("/").handler(routingContext ->  {
+    router.route(Constant.ROOT_PATH).handler(routingContext ->  {
       HttpServerResponse response = routingContext.response();
       response.putHeader("content-type", "text/html").end(mainPage);
     });
 
     // Route /metrics url
+    router.get(Constant.METRICS_PATH).handler(smartOSExporter::handleMetricsRequest);
 
     // Set up HTTP server
     createHttpServer(future, router);
@@ -32,6 +36,8 @@ public class SmartOSExporter extends AbstractVerticle {
   private void initializeVars() {
     smartOSExporter = this;
     mainPage = "<h1>SmartOS Node exporter</h1>\n<p><a href=\"/metrics\">Metrics</a></p>";
+    systemMetrics = new SystemMetrics();
+    metricsHandler = new MetricsHandler();
   }
 
   private void createHttpServer(Future<Void> future, Router router) {
@@ -39,7 +45,7 @@ public class SmartOSExporter extends AbstractVerticle {
       .createHttpServer()
       .requestHandler(router::accept)
       .listen(
-        config().getInteger(Constant.SERVICE_PORT, 8080),
+        config().getInteger(Constant.SERVICE_PORT, Constant.LISTEN_PORT),
         result -> {
           if (result.succeeded()) {
             future.complete();
@@ -50,4 +56,9 @@ public class SmartOSExporter extends AbstractVerticle {
       );
   }
 
+  private void handleMetricsRequest(RoutingContext routingContext) {
+    systemMetrics.pollCollectorChain();
+    metricsHandler.handle(routingContext);
+  }
+
 }

+ 26 - 0
src/main/java/nu/ltd/fp/se/SystemMetrics.java

@@ -0,0 +1,26 @@
+package nu.ltd.fp.se;
+
+import io.prometheus.client.Counter;
+import io.prometheus.client.Gauge;
+import io.prometheus.client.Histogram;
+import io.prometheus.client.Summary;
+import nu.ltd.fp.se.collector.MetricCollector;
+import nu.ltd.fp.se.collector.SmartOSCollector;
+import nu.ltd.fp.se.collector.UnameCollector;
+
+public class SystemMetrics {
+
+  private MetricCollector metricCollector;
+
+  public SystemMetrics() {
+    MetricCollector smartOSCollector = new SmartOSCollector();
+    MetricCollector unameCollector = new UnameCollector(smartOSCollector);
+
+    // this.metricCollector should be set to the last one
+    this.metricCollector = unameCollector;
+  }
+
+  public void pollCollectorChain() {
+    metricCollector.collectMetric();
+  }
+}

+ 13 - 0
src/main/java/nu/ltd/fp/se/collector/AbstractMetricCollector.java

@@ -0,0 +1,13 @@
+package nu.ltd.fp.se.collector;
+
+public class AbstractMetricCollector {
+  private MetricCollector nextCollector;
+
+  public void setNextCollector(MetricCollector nextCollector) {
+    this.nextCollector = nextCollector;
+  }
+
+  public MetricCollector getNextCollector() {
+    return this.nextCollector;
+  }
+}

+ 6 - 0
src/main/java/nu/ltd/fp/se/collector/MetricCollector.java

@@ -0,0 +1,6 @@
+package nu.ltd.fp.se.collector;
+
+public interface MetricCollector {
+  public void collectMetric();
+  public void setNextCollector(MetricCollector successor);
+}

+ 27 - 0
src/main/java/nu/ltd/fp/se/collector/SmartOSCollector.java

@@ -0,0 +1,27 @@
+package nu.ltd.fp.se.collector;
+
+import io.prometheus.client.Gauge;
+
+public class SmartOSCollector extends AbstractMetricCollector implements MetricCollector {
+  static final Gauge unameGauge = Gauge.build()
+    .name("smartos_info")
+    .help("Collector name")
+    .labelNames("collector_name")
+    .register();
+
+  public SmartOSCollector() {
+    unameGauge.labels("SmartOS Collector").set(1);
+  }
+
+  public SmartOSCollector(MetricCollector nextCollector) {
+    this();
+    this.setNextCollector(nextCollector);
+  }
+
+  public void collectMetric() {
+    // Nothing to be done, call next collector
+    if (this.getNextCollector() != null) {
+      this.getNextCollector().collectMetric();
+    }
+  }
+}

+ 29 - 0
src/main/java/nu/ltd/fp/se/collector/UnameCollector.java

@@ -0,0 +1,29 @@
+package nu.ltd.fp.se.collector;
+
+import io.prometheus.client.Gauge;
+
+public class UnameCollector extends AbstractMetricCollector implements MetricCollector {
+  static final Gauge unameGauge = Gauge.build()
+    .name("node_uname_info")
+    .help("Labeled system information as provided by the uname system call")
+    .labelNames("domainname", "machine", "nodename", "sysname", "version")
+    .register();
+
+  public UnameCollector() {
+    unameGauge.labels("fp.ltd.nu", "somehostname", "x64", "l4", "l5").set(1);
+  }
+
+  public UnameCollector(MetricCollector nextCollector) {
+    this();
+    this.setNextCollector(nextCollector);
+  }
+
+  // node_uname_info{domainname="(none)",machine="x86_64",nodename="lnx-host-01",release="4.4.0-87-generic",sysname="Linux",version="#110-Ubuntu SMP Tue Jul 18 12:55:35 UTC 2017"} 1
+  // node_uname_info{nodename="get",} 1.0
+  public void collectMetric() {
+    // Nothing to be done, call next collector
+    if (this.getNextCollector() != null) {
+      this.getNextCollector().collectMetric();
+    }
+  }
+}