Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.prometheus.metrics.config;

import java.time.Duration;
import java.util.Map;
import javax.annotation.Nullable;

Expand All @@ -9,21 +10,29 @@ public class ExporterPushgatewayProperties {
private static final String JOB = "job";
private static final String SCHEME = "scheme";
private static final String ESCAPING_SCHEME = "escapingScheme";
private static final String READ_TIMEOUT = "readTimeoutSeconds";
private static final String CONNECT_TIMEOUT = "connectTimeoutSeconds";
private static final String PREFIX = "io.prometheus.exporter.pushgateway";
@Nullable private final String scheme;
@Nullable private final String address;
@Nullable private final String job;
@Nullable private final EscapingScheme escapingScheme;
@Nullable private final Duration connectTimeout;
@Nullable private final Duration readTimeout;

private ExporterPushgatewayProperties(
@Nullable String address,
@Nullable String job,
@Nullable String scheme,
@Nullable EscapingScheme escapingScheme) {
@Nullable EscapingScheme escapingScheme,
@Nullable Duration connectTimeout,
@Nullable Duration readTimeout) {
this.address = address;
this.job = job;
this.scheme = scheme;
this.escapingScheme = escapingScheme;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
}

/** Address of the Pushgateway in the form {@code host:port}. Default is {@code localhost:9091} */
Expand Down Expand Up @@ -56,6 +65,18 @@ public EscapingScheme getEscapingScheme() {
return escapingScheme;
}

/** Connection timeout for connections to the Pushgateway. */
@Nullable
public Duration getConnectTimeout() {
return connectTimeout;
}

/** Read timeout for connections to the Pushgateway. */
@Nullable
public Duration getReadTimeout() {
return readTimeout;
}

/**
* Note that this will remove entries from {@code properties}. This is because we want to know if
* there are unused properties remaining after all properties have been loaded.
Expand All @@ -66,6 +87,8 @@ static ExporterPushgatewayProperties load(Map<Object, Object> properties)
String job = Util.loadString(PREFIX + "." + JOB, properties);
String scheme = Util.loadString(PREFIX + "." + SCHEME, properties);
String escapingScheme = Util.loadString(PREFIX + "." + ESCAPING_SCHEME, properties);
Duration connectTimeout = Util.loadOptionalDuration(PREFIX + "." + CONNECT_TIMEOUT, properties);
Duration readTimeout = Util.loadOptionalDuration(PREFIX + "." + READ_TIMEOUT, properties);

if (scheme != null) {
if (!scheme.equals("http") && !scheme.equals("https")) {
Expand All @@ -77,7 +100,7 @@ static ExporterPushgatewayProperties load(Map<Object, Object> properties)
}

return new ExporterPushgatewayProperties(
address, job, scheme, parseEscapingScheme(escapingScheme));
address, job, scheme, parseEscapingScheme(escapingScheme), connectTimeout, readTimeout);
}

private static @Nullable EscapingScheme parseEscapingScheme(@Nullable String scheme) {
Expand Down Expand Up @@ -111,6 +134,8 @@ public static class Builder {
@Nullable private String job;
@Nullable private String scheme;
@Nullable private EscapingScheme escapingScheme;
@Nullable private Duration connectTimeout;
@Nullable private Duration readTimeout;

private Builder() {}

Expand All @@ -134,8 +159,19 @@ public Builder escapingScheme(EscapingScheme escapingScheme) {
return this;
}

public Builder connectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}

public Builder readTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
return this;
}

public ExporterPushgatewayProperties build() {
return new ExporterPushgatewayProperties(address, job, scheme, escapingScheme);
return new ExporterPushgatewayProperties(
address, job, scheme, escapingScheme, connectTimeout, readTimeout);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.prometheus.metrics.config;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
Expand Down Expand Up @@ -160,14 +161,30 @@ static Long loadLong(String name, Map<Object, Object> properties)
return null;
}

@Nullable
static Duration loadOptionalDuration(String name, Map<Object, Object> properties)
throws PrometheusPropertiesException {

Long value = loadLong(name, properties);

assertValue(value, t -> t >= 0, "Expecting value >= 0.", null, name);

if (value == null || value == 0) {
return null;
}
return Duration.ofSeconds(value);
}

static <T extends Number> void assertValue(
@Nullable T number, Predicate<T> predicate, String message, String prefix, String name)
@Nullable T number,
Predicate<T> predicate,
String message,
@Nullable String prefix,
String name)
throws PrometheusPropertiesException {
if (number != null && !predicate.test(number)) {
String fullMessage =
prefix == null
? name + ": " + message
: String.format("%s.%s: %s Found: %s", prefix, name, message, number);
String fullKey = prefix == null ? name : prefix + "." + name;
String fullMessage = String.format("%s: %s Found: %s", fullKey, message, number);
throw new PrometheusPropertiesException(fullMessage);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -41,11 +42,15 @@ void builder() {
.job("job")
.scheme("http")
.escapingScheme(EscapingScheme.DOTS_ESCAPING)
.connectTimeout(Duration.ofSeconds(1))
.readTimeout(Duration.ofSeconds(2))
.build();

assertThat(properties.getAddress()).isEqualTo("http://localhost");
assertThat(properties.getJob()).isEqualTo("job");
assertThat(properties.getScheme()).isEqualTo("http");
assertThat(properties.getEscapingScheme()).isEqualTo(EscapingScheme.DOTS_ESCAPING);
assertThat(properties.getConnectTimeout()).isEqualTo(Duration.ofSeconds(1));
assertThat(properties.getReadTimeout()).isEqualTo(Duration.ofSeconds(2));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.prometheus.metrics.config;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;

class UtilTest {
@Test
void loadOptionalDuration_positive() {
Map<Object, Object> properties = new HashMap<>(Map.of("foo", "5"));

assertThat(Util.loadOptionalDuration("foo", properties)).isEqualTo(Duration.ofSeconds(5));
}

@Test
void loadOptionalDuration_zero() {
Map<Object, Object> properties = new HashMap<>(Map.of("foo", "0"));

assertThat(Util.loadOptionalDuration("foo", properties)).isNull();
}

@Test
void loadOptionalDuration_missing() {
Map<Object, Object> properties = new HashMap<>();

assertThat(Util.loadOptionalDuration("foo", properties)).isNull();
}

@Test
void loadOptionalDuration_negative_throws() {
Map<Object, Object> properties = new HashMap<>(Map.of("foo", "-1"));

assertThatExceptionOfType(PrometheusPropertiesException.class)
.isThrownBy(() -> Util.loadOptionalDuration("foo", properties))
.withMessage("foo: Expecting value >= 0. Found: -1");
}

@Test
void loadOptionalDuration_invalidNumber_throws() {
Map<Object, Object> properties = new HashMap<>(Map.of("foo", "abc"));

assertThatExceptionOfType(PrometheusPropertiesException.class)
.isThrownBy(() -> Util.loadOptionalDuration("foo", properties))
.withMessage("foo=abc: Expecting long value");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -79,16 +80,15 @@
* href="https://github.com/prometheus/pushgateway">https://github.com/prometheus/pushgateway</a>.
*/
public class PushGateway {

private static final int MILLISECONDS_PER_SECOND = 1000;

private final URL url;
private final ExpositionFormatWriter writer;
private final boolean prometheusTimestampsInMs;
private final Map<String, String> requestHeaders;
private final PrometheusRegistry registry;
private final HttpConnectionFactory connectionFactory;
private final EscapingScheme escapingScheme;
private final Duration connectionTimeout;
private final Duration readTimeout;

private PushGateway(
PrometheusRegistry registry,
Expand All @@ -97,13 +97,17 @@ private PushGateway(
HttpConnectionFactory connectionFactory,
Map<String, String> requestHeaders,
boolean prometheusTimestampsInMs,
EscapingScheme escapingScheme) {
EscapingScheme escapingScheme,
Duration connectionTimeout,
Duration readTimeout) {
this.registry = registry;
this.url = url;
this.requestHeaders = Collections.unmodifiableMap(new HashMap<>(requestHeaders));
this.connectionFactory = connectionFactory;
this.prometheusTimestampsInMs = prometheusTimestampsInMs;
this.escapingScheme = escapingScheme;
this.connectionTimeout = connectionTimeout;
this.readTimeout = readTimeout;
writer = getWriter(format);
if (!writer.isAvailable()) {
throw new RuntimeException(writer.getClass() + " is not available");
Expand Down Expand Up @@ -206,8 +210,8 @@ private void doRequest(@Nullable PrometheusRegistry registry, String method) thr
}
connection.setRequestMethod(method);

connection.setConnectTimeout(10 * MILLISECONDS_PER_SECOND);
connection.setReadTimeout(10 * MILLISECONDS_PER_SECOND);
connection.setConnectTimeout((int) this.connectionTimeout.toMillis());
connection.setReadTimeout((int) this.readTimeout.toMillis());
connection.connect();

try {
Expand Down Expand Up @@ -277,6 +281,8 @@ public static class Builder {
@Nullable private String address;
@Nullable private Scheme scheme;
@Nullable private String job;
@Nullable private Duration connectionTimeout;
@Nullable private Duration readTimeout;
private boolean prometheusTimestampsInMs;
private final Map<String, String> requestHeaders = new HashMap<>();
private PrometheusRegistry registry = PrometheusRegistry.defaultRegistry;
Expand Down Expand Up @@ -395,6 +401,49 @@ public Builder prometheusTimestampsInMs(boolean prometheusTimestampsInMs) {
return this;
}

/**
* Specify the connection timeout for HTTP connections to the PushGateway. Default is 10
* seconds.
*
* @param connectionTimeout timeout value
* @return this {@link Builder} instance
*/
public Builder connectionTimeout(Duration connectionTimeout) {
this.connectionTimeout = connectionTimeout;
return this;
}

private Duration getConnectionTimeout(@Nullable ExporterPushgatewayProperties properties) {
if (properties != null && properties.getConnectTimeout() != null) {
return properties.getConnectTimeout();
} else if (this.connectionTimeout != null) {
return this.connectionTimeout;
} else {
return Duration.ofSeconds(10);
}
}

/**
* Specify the read timeout for HTTP connections to the PushGateway. Default is 10 seconds.
*
* @param readTimeout timeout value
* @return this {@link Builder} instance
*/
public Builder readTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
return this;
}

private Duration getReadTimeout(@Nullable ExporterPushgatewayProperties properties) {
if (properties != null && properties.getReadTimeout() != null) {
return properties.getReadTimeout();
} else if (this.readTimeout != null) {
return this.readTimeout;
} else {
return Duration.ofSeconds(10);
}
}

private boolean getPrometheusTimestampsInMs() {
// accept either to opt in to timestamps in milliseconds
return config.getExporterProperties().getPrometheusTimestampsInMs()
Expand Down Expand Up @@ -496,7 +545,9 @@ public PushGateway build() {
connectionFactory,
requestHeaders,
getPrometheusTimestampsInMs(),
getEscapingScheme(properties));
getEscapingScheme(properties),
getConnectionTimeout(properties),
getReadTimeout(properties));
} catch (MalformedURLException e) {
throw new PrometheusPropertiesException(
address + ": Invalid address. Expecting <host>:<port>");
Expand Down