net.bull.javamelody.internal.publish.Datadog Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javamelody-core Show documentation
Show all versions of javamelody-core Show documentation
Monitoring of JavaEE applications
/*
* Copyright 2008-2019 by Emeric Vernat
*
* This file is part of Java Melody.
*
* 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 net.bull.javamelody.internal.publish;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import net.bull.javamelody.Parameter;
import net.bull.javamelody.internal.common.LOG;
import net.bull.javamelody.internal.model.LabradorRetriever;
/**
* Publish chart data to Datadog.
* @author Emeric Vernat
*/
class Datadog extends MetricsPublisher {
private static final String BEGIN_SERIES = "{ \"series\" : [";
private static final String END_SERIES = "\n]}";
private final URL datadogUrl;
private final String prefix;
private final String hostAndTags;
private final Map httpHeaders = Collections.singletonMap("Content-Type",
"application/json");
private final DecimalFormat decimalFormat = new DecimalFormat("0.00",
DecimalFormatSymbols.getInstance(Locale.US));
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final Writer bufferWriter = new OutputStreamWriter(buffer, StandardCharsets.UTF_8);
private long lastTime;
private String lastTimestamp;
private boolean beginSeries;
Datadog(String datadogApiKey, String datadogApiHost, String prefix, String hostAndTags) {
super();
assert datadogApiKey != null;
assert prefix != null;
assert hostAndTags != null;
try {
this.datadogUrl = new URL(
"https://" + datadogApiHost + "/api/v1/series?api_key=" + datadogApiKey);
} catch (final MalformedURLException e) {
throw new IllegalArgumentException(e);
}
this.prefix = prefix;
this.hostAndTags = hostAndTags;
try {
bufferWriter.append(BEGIN_SERIES);
beginSeries = true;
} catch (final IOException e) {
// can not happen
throw new IllegalStateException(e);
}
}
static Datadog getInstance(String contextPath, String hostName) {
final String datadogApiKey = Parameter.DATADOG_API_KEY.getValue();
if (datadogApiKey != null) {
String datadogApiHost = Parameter.DATADOG_API_HOST.getValue();
if (datadogApiHost == null) {
datadogApiHost = "api.datadoghq.com";
}
assert contextPath != null;
assert hostName != null;
// contextPath est du genre "/testapp"
// hostName est du genre "www.host.com"
final String prefix = "javamelody.";
// see https://help.datadoghq.com/hc/en-us/articles/203764705-What-are-valid-metric-names-
final String hostAndTags = "\"host\":\"" + hostName + "\",\"tags\":[\"application:"
+ contextPath + "\"]";
return new Datadog(datadogApiKey, datadogApiHost, prefix, hostAndTags);
}
return null;
}
@Override
public synchronized void addValue(String metric, double value) throws IOException {
/*
https://docs.datadoghq.com/api/
json example for timestamp now, host and tags are optional.
"{ \"series\" :
[{\"metric\":\"page.views\",
\"points\":[[$currenttime, 1000]],
\"host\":\"myhost.example.com\",
\"tags\":[\"version:1\"]}
]
}"
*/
final long timeInSeconds = System.currentTimeMillis() / 1000;
if (lastTime != timeInSeconds) {
lastTimestamp = String.valueOf(timeInSeconds);
lastTime = timeInSeconds;
}
if (beginSeries) {
beginSeries = false;
} else {
bufferWriter.append(',');
}
bufferWriter.append("\n{\"metric\":\"").append(prefix).append(metric).append("\",");
bufferWriter.append("\"points\":[[").append(lastTimestamp).append(',')
.append(decimalFormat.format(value)).append("]],");
bufferWriter.append(hostAndTags);
bufferWriter.append('}');
}
@Override
public synchronized void send() throws IOException {
try {
bufferWriter.append(END_SERIES);
bufferWriter.flush();
new LabradorRetriever(datadogUrl, httpHeaders).post(buffer);
} catch (final Exception e) {
LOG.warn(e.toString(), e);
} finally {
// finally to be sure to not keep too much data in buffer
// including when the http url can't connect
buffer.reset();
bufferWriter.append(BEGIN_SERIES);
beginSeries = true;
}
}
@Override
public void stop() {
// nothing
}
}