// Path: src/main/java/io/github/tjheslin1/patterdale/metrics/MetricsUseCase.java
// public class MetricsUseCase {
// 
//     private final Logger logger;
//     private final List<OracleSQLProbe> probes;
//     private final RuntimeParameters runtimeParameters;
//     private final Supplier<ExecutorService> executorServiceSupplier;
// 
//     public MetricsUseCase(Logger logger, List<OracleSQLProbe> probes, RuntimeParameters runtimeParameters, Supplier<ExecutorService> executorServiceSupplier) {
//         this.logger = logger;
//         this.probes = probes;
//         this.runtimeParameters = runtimeParameters;
//         this.executorServiceSupplier = executorServiceSupplier;
//     }
// 
//     public List<ProbeResult> scrapeMetrics() {
//         ExecutorService executor = executorServiceSupplier.get();
// 
//         List<ProbeWithFuture> eventualProbeResults = probes.stream()
//                 .map(probe -> new ProbeWithFuture(probe, executor.submit(new ScrapeProbe(probe))))
//                 .collect(toList());
// 
//         executor.shutdown();
//         try {
//             executor.awaitTermination(runtimeParameters.probeConnectionWaitInSeconds(), SECONDS);
//         } catch (InterruptedException e) {
//             logger.warn("Interrupted while awaiting termination", e);
//             Thread.currentThread().interrupt();
//         }
//         try {
//             return collectProbeResults(eventualProbeResults);
//         } catch (Exception e) {
//             logger.error("Exception occurred while scraping metrics", e);
//             return failedProbeResults().collect(toList());
//         }
//     }
// 
//     private List<ProbeResult> collectProbeResults(List<ProbeWithFuture> eventualProbeResults) {
//         return eventualProbeResults.stream()
//                 .flatMap(this::eventualResult)
//                 .collect(toList());
//     }
// 
//     private Stream<ProbeResult> eventualResult(ProbeWithFuture eventualResult) {
//         try {
//             // the results are already there because of the await termination but we still need a timeout here for some reason
//             return eventualResult.future.get(1, SECONDS).stream();
//         } catch (Exception e) {
//             logger.error("Exception occurred while scraping metrics for " + eventualResult.probe.probeDefinition(), e);
//             return Stream.of(failedProbe(eventualResult.probe.probeDefinition()));
//         }
//     }
// 
//     private Stream<ProbeResult> failedProbeResults() {
//         return probes.stream()
//                 .map(probe -> failedProbe(probe.probeDefinition()));
//     }
// 
//     private static class ProbeWithFuture {
//         public final OracleSQLProbe probe;
//         public final Future<List<ProbeResult>> future;
// 
//         private ProbeWithFuture(OracleSQLProbe probe, Future<List<ProbeResult>> future) {
//             this.probe = probe;
//             this.future = future;
//         }
// 
//     }
// }
// 
// Path: src/main/java/io/github/tjheslin1/patterdale/metrics/probe/ProbeResult.java
// public class ProbeResult extends ValueType {
// 
//     public final double value;
//     public final Probe probe;
//     public final List<String> dynamicLabelValues;
// 
//     public ProbeResult(double value, Probe probe) {
//         this(value, probe, emptyList());
//     }
// 
//     public ProbeResult(double value, Probe probe, List<String> dynamicLabelValues) {
//         this.value = value;
//         this.probe = probe;
//         this.dynamicLabelValues = dynamicLabelValues;
//     }
// 
//     public static ProbeResult failedProbe(Probe probe) {
//         return new ProbeResult(-1, probe);
//     }
// }
// 
// Path: src/main/java/io/github/tjheslin1/patterdale/http/MetricsCache.java
// public static MetricsCache metricsCache(MetricsUseCase metricsUseCase, long cacheDuration) {
//     MetricsCache metricsCache = new MetricsCache(metricsUseCase);
//     metricsCache.run();
// 
//     ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
//     scheduler.scheduleAtFixedRate(metricsCache, cacheDuration, cacheDuration, TimeUnit.SECONDS);
//     return metricsCache;
// }
// 
// Path: src/main/java/io/github/tjheslin1/patterdale/metrics/probe/ProbeResultFormatter.java
// public static List<String> formatProbeResults(List<ProbeResult> probeResults) throws IOException {
//     return probeResults.stream()
//             .map(ProbeResultFormatter::formatProbe)
//             .collect(toList());
// }


import static io.github.tjheslin1.patterdale.http.MetricsCache.metricsCache;
import static io.github.tjheslin1.patterdale.metrics.probe.ProbeResultFormatter.formatProbeResults;
import io.github.tjheslin1.patterdale.metrics.MetricsUseCase;
import io.github.tjheslin1.patterdale.metrics.probe.ProbeResult;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.common.TextFormat;
import org.slf4j.Logger;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.function.Supplier;
/*
 * Copyright 2017 - 2021 Thomas Heslin <tjheslin1@kolabnow.com>.
 *
 * This file is part of Patterdale.
 *
 * Licensed 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 io.github.tjheslin1.patterdale.http;




public class MetricsServlet extends HttpServlet {

    private final CollectorRegistry registry;
    private final Supplier<List<ProbeResult>> metricsCache;
    private final Logger logger;

    public MetricsServlet(CollectorRegistry registry, MetricsUseCase metricsUseCase, Logger logger, long cacheDuration) {
        this.registry = registry;
        this.metricsCache = metricsCache(metricsUseCase, cacheDuration);
        this.logger = logger;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.setStatus(HttpServletResponse.SC_OK);
        resp.setContentType(TextFormat.CONTENT_TYPE_004);

// Path: src/main/java/io/github/tjheslin1/patterdale/metrics/MetricsUseCase.java
// public class MetricsUseCase {
// 
//     private final Logger logger;
//     private final List<OracleSQLProbe> probes;
//     private final RuntimeParameters runtimeParameters;
//     private final Supplier<ExecutorService> executorServiceSupplier;
// 
//     public MetricsUseCase(Logger logger, List<OracleSQLProbe> probes, RuntimeParameters runtimeParameters, Supplier<ExecutorService> executorServiceSupplier) {
//         this.logger = logger;
//         this.probes = probes;
//         this.runtimeParameters = runtimeParameters;
//         this.executorServiceSupplier = executorServiceSupplier;
//     }
// 
//     public List<ProbeResult> scrapeMetrics() {
//         ExecutorService executor = executorServiceSupplier.get();
// 
//         List<ProbeWithFuture> eventualProbeResults = probes.stream()
//                 .map(probe -> new ProbeWithFuture(probe, executor.submit(new ScrapeProbe(probe))))
//                 .collect(toList());
// 
//         executor.shutdown();
//         try {
//             executor.awaitTermination(runtimeParameters.probeConnectionWaitInSeconds(), SECONDS);
//         } catch (InterruptedException e) {
//             logger.warn("Interrupted while awaiting termination", e);
//             Thread.currentThread().interrupt();
//         }
//         try {
//             return collectProbeResults(eventualProbeResults);
//         } catch (Exception e) {
//             logger.error("Exception occurred while scraping metrics", e);
//             return failedProbeResults().collect(toList());
//         }
//     }
// 
//     private List<ProbeResult> collectProbeResults(List<ProbeWithFuture> eventualProbeResults) {
//         return eventualProbeResults.stream()
//                 .flatMap(this::eventualResult)
//                 .collect(toList());
//     }
// 
//     private Stream<ProbeResult> eventualResult(ProbeWithFuture eventualResult) {
//         try {
//             // the results are already there because of the await termination but we still need a timeout here for some reason
//             return eventualResult.future.get(1, SECONDS).stream();
//         } catch (Exception e) {
//             logger.error("Exception occurred while scraping metrics for " + eventualResult.probe.probeDefinition(), e);
//             return Stream.of(failedProbe(eventualResult.probe.probeDefinition()));
//         }
//     }
// 
//     private Stream<ProbeResult> failedProbeResults() {
//         return probes.stream()
//                 .map(probe -> failedProbe(probe.probeDefinition()));
//     }
// 
//     private static class ProbeWithFuture {
//         public final OracleSQLProbe probe;
//         public final Future<List<ProbeResult>> future;
// 
//         private ProbeWithFuture(OracleSQLProbe probe, Future<List<ProbeResult>> future) {
//             this.probe = probe;
//             this.future = future;
//         }
// 
//     }
// }
// 
// Path: src/main/java/io/github/tjheslin1/patterdale/metrics/probe/ProbeResult.java
// public class ProbeResult extends ValueType {
// 
//     public final double value;
//     public final Probe probe;
//     public final List<String> dynamicLabelValues;
// 
//     public ProbeResult(double value, Probe probe) {
//         this(value, probe, emptyList());
//     }
// 
//     public ProbeResult(double value, Probe probe, List<String> dynamicLabelValues) {
//         this.value = value;
//         this.probe = probe;
//         this.dynamicLabelValues = dynamicLabelValues;
//     }
// 
//     public static ProbeResult failedProbe(Probe probe) {
//         return new ProbeResult(-1, probe);
//     }
// }
// 
// Path: src/main/java/io/github/tjheslin1/patterdale/http/MetricsCache.java
// public static MetricsCache metricsCache(MetricsUseCase metricsUseCase, long cacheDuration) {
//     MetricsCache metricsCache = new MetricsCache(metricsUseCase);
//     metricsCache.run();
// 
//     ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
//     scheduler.scheduleAtFixedRate(metricsCache, cacheDuration, cacheDuration, TimeUnit.SECONDS);
//     return metricsCache;
// }
// 
// Path: src/main/java/io/github/tjheslin1/patterdale/metrics/probe/ProbeResultFormatter.java
// public static List<String> formatProbeResults(List<ProbeResult> probeResults) throws IOException {
//     return probeResults.stream()
//             .map(ProbeResultFormatter::formatProbe)
//             .collect(toList());
// }


// Path: src/main/java/io/github/tjheslin1/patterdale/http/MetricsServlet.java
import static io.github.tjheslin1.patterdale.http.MetricsCache.metricsCache;
import static io.github.tjheslin1.patterdale.metrics.probe.ProbeResultFormatter.formatProbeResults;
import io.github.tjheslin1.patterdale.metrics.MetricsUseCase;
import io.github.tjheslin1.patterdale.metrics.probe.ProbeResult;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.common.TextFormat;
import org.slf4j.Logger;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.function.Supplier;

/*
 * Copyright 2017 - 2021 Thomas Heslin <tjheslin1@kolabnow.com>.
 *
 * This file is part of Patterdale.
 *
 * Licensed 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 io.github.tjheslin1.patterdale.http;




public class MetricsServlet extends HttpServlet {

    private final CollectorRegistry registry;
    private final Supplier<List<ProbeResult>> metricsCache;
    private final Logger logger;

    public MetricsServlet(CollectorRegistry registry, MetricsUseCase metricsUseCase, Logger logger, long cacheDuration) {
        this.registry = registry;
        this.metricsCache = metricsCache(metricsUseCase, cacheDuration);
        this.logger = logger;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.setStatus(HttpServletResponse.SC_OK);
        resp.setContentType(TextFormat.CONTENT_TYPE_004);

        List<ProbeResult> probeResults = metricsCache.get();