001package org.avaje.metric.elastic;
002
003import okhttp3.MediaType;
004import okhttp3.OkHttpClient;
005import okhttp3.Request;
006import okhttp3.RequestBody;
007import okhttp3.Response;
008import org.avaje.metric.report.MetricReporter;
009import org.avaje.metric.report.ReportMetrics;
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013import java.io.StringWriter;
014import java.net.ConnectException;
015import java.time.LocalDate;
016
017/**
018 * Http(s) based Reporter that sends JSON formatted metrics directly to Elastic.
019 */
020public class ElasticHttpReporter implements MetricReporter {
021
022  private static final Logger logger = LoggerFactory.getLogger(ElasticHttpReporter.class);
023
024  private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
025
026  private final OkHttpClient client = new OkHttpClient();
027
028  private final String bulkUrl;
029
030  private final ElasticReporterConfig config;
031
032  public ElasticHttpReporter(ElasticReporterConfig config) {
033    this.config = config;
034    this.bulkUrl = config.getUrl() + "/_bulk";
035
036    // put the template to elastic if it is not already there
037    new TemplateApply(client, config.getUrl(), config.getTemplateName()).run();
038  }
039
040  /**
041   * Send the non-empty metrics that were collected to the remote repository.
042   */
043  @Override
044  public void report(ReportMetrics reportMetrics) {
045
046    String today = today();
047    String json = null;
048    try {
049      StringWriter writer = new StringWriter(1000);
050      BulkJsonWriteVisitor jsonVisitor = new BulkJsonWriteVisitor(writer, reportMetrics, config, today);
051      jsonVisitor.write();
052
053      json = writer.toString();
054
055      if (logger.isTraceEnabled()) {
056        logger.trace("Sending:\n{}", json);
057      }
058
059      RequestBody body = RequestBody.create(JSON, json);
060      Request request = new Request.Builder()
061          .url(bulkUrl)
062          .post(body)
063          .build();
064
065      Response response = client.newCall(request).execute();
066      if (!response.isSuccessful()) {
067        logger.warn("Unsuccessful sending metrics payload to server - {}", response.body().string());
068        storeJsonForResend(json);
069      } else if (logger.isTraceEnabled()) {
070        logger.trace("Bulk Response - {}", response.body().string());
071      }
072
073    } catch (ConnectException e) {
074      logger.info("Connection error sending metrics to server: " + e.getMessage());
075      storeJsonForResend(json);
076
077    } catch (Exception e) {
078      logger.error("Unexpected error sending metrics to server", e);
079      storeJsonForResend(json);
080    }
081  }
082
083  private String today() {
084    return LocalDate.now().toString();
085  }
086
087  protected void storeJsonForResend(String json) {
088    // override this to support store and re-send 
089  }
090
091
092  @Override
093  public void cleanup() {
094    // Do nothing
095  }
096
097}