Skip to content

Commit

Permalink
Support for HTTPServer's SampleNameFilter
Browse files Browse the repository at this point in the history
Signed-off-by: Davi Arnaut <[email protected]>
  • Loading branch information
darnaut committed Feb 16, 2024
1 parent f96796d commit 74d5228
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2024 The Prometheus jmx_exporter Authors
*
* 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.prometheus.jmx.test.http.sampleNameFilter;

import static io.prometheus.jmx.test.support.MetricsAssertions.assertThatMetricIn;
import static io.prometheus.jmx.test.support.RequestResponseAssertions.assertThatResponseForRequest;

import io.prometheus.jmx.test.BaseTest;
import io.prometheus.jmx.test.Metric;
import io.prometheus.jmx.test.MetricsParser;
import io.prometheus.jmx.test.Mode;
import io.prometheus.jmx.test.support.ContentConsumer;
import io.prometheus.jmx.test.support.HealthyRequest;
import io.prometheus.jmx.test.support.HealthyResponse;
import io.prometheus.jmx.test.support.MetricsRequest;
import io.prometheus.jmx.test.support.MetricsResponse;
import io.prometheus.jmx.test.support.OpenMetricsRequest;
import io.prometheus.jmx.test.support.OpenMetricsResponse;
import io.prometheus.jmx.test.support.PrometheusMetricsRequest;
import io.prometheus.jmx.test.support.PrometheusMetricsResponse;
import java.util.Collection;
import org.antublue.test.engine.api.TestEngine;

public class SampleNameFilterConfigurationTest extends BaseTest implements ContentConsumer {

@TestEngine.Test
public void testHealthy() throws InterruptedException {
assertThatResponseForRequest(new HealthyRequest(testState.httpClient()))
.isSuperset(HealthyResponse.RESULT_200);
}

@TestEngine.Test
public void testMetrics() {
assertThatResponseForRequest(new MetricsRequest(testState.httpClient()))
.isSuperset(MetricsResponse.RESULT_200)
.dispatch(this);
}

@TestEngine.Test
public void testMetricsOpenMetricsFormat() {
assertThatResponseForRequest(new OpenMetricsRequest(testState.httpClient()))
.isSuperset(OpenMetricsResponse.RESULT_200)
.dispatch(this);
}

@TestEngine.Test
public void testMetricsPrometheusFormat() {
assertThatResponseForRequest(new PrometheusMetricsRequest(testState.httpClient()))
.isSuperset(PrometheusMetricsResponse.RESULT_200)
.dispatch(this);
}

@Override
public void accept(String content) {
Collection<Metric> metrics = MetricsParser.parse(content);

String buildInfoName =
testArgument.mode() == Mode.JavaAgent
? "jmx_prometheus_javaagent"
: "jmx_prometheus_httpserver";

assertThatMetricIn(metrics)
.withName("jmx_exporter_build_info")
.withLabel("name", buildInfoName)
.exists();

assertThatMetricIn(metrics)
.withName("java_lang_Memory_NonHeapMemoryUsage_committed")
.exists();

assertThatMetricIn(metrics)
.withName("io_prometheus_jmx_tabularData_Server_1_Disk_Usage_Table_size")
.withLabel("source", "/dev/sda1")
.withValue(7.516192768E9)
.exists();

assertThatMetricIn(metrics)
.withName("io_prometheus_jmx_tabularData_Server_2_Disk_Usage_Table_pcent")
.withLabel("source", "/dev/sda2")
.withValue(0.8)
.exists();

assertThatMetricIn(metrics).withName("jvm_threads_state").doesNotExist();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

java \
-Xmx128M \
-javaagent:jmx_prometheus_javaagent.jar=8888:exporter.yaml \
-jar jmx_example_application.jar
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
httpServer:
sampleNameFilter:
name-must-not-be-equal-to:
- jvm_threads_state
rules:
- pattern: ".*"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

java \
-Xmx128M \
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.registry.ssl=false \
-Dcom.sun.management.jmxremote.rmi.port=9999 \
-Dcom.sun.management.jmxremote.ssl.need.client.auth=false \
-Dcom.sun.management.jmxremote.ssl=false \
-jar jmx_example_application.jar
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

java \
-Xmx128M \
-jar jmx_prometheus_httpserver.jar 8888 exporter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
httpServer:
sampleNameFilter:
name-must-not-be-equal-to:
- jvm_threads_state
hostPort: application:9999
rules:
- pattern: ".*"
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2023 The Prometheus jmx_exporter Authors
*
* 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.prometheus.jmx.common.configuration;

import io.prometheus.jmx.common.util.Precondition;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;

public class ConvertToStringList implements Function<Object, List<String>> {

private final Supplier<? extends RuntimeException> supplier;

/**
* Constructor
*
* @param supplier supplier
*/
public ConvertToStringList(Supplier<? extends RuntimeException> supplier) {
Precondition.notNull(supplier);
this.supplier = supplier;
}

/**
* Method to apply a function
*
* @param value value
* @return the return value
*/
@Override
public List<String> apply(Object value) {
if (value == null) {
throw new IllegalArgumentException();
}

try {
return (List<String>) value;
} catch (Throwable t) {
throw supplier.get();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
import com.sun.net.httpserver.Authenticator;
import com.sun.net.httpserver.HttpsConfigurator;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.SampleNameFilter;
import io.prometheus.client.exporter.HTTPServer;
import io.prometheus.jmx.common.configuration.ConvertToInteger;
import io.prometheus.jmx.common.configuration.ConvertToMapAccessor;
import io.prometheus.jmx.common.configuration.ConvertToString;
import io.prometheus.jmx.common.configuration.ConvertToStringList;
import io.prometheus.jmx.common.configuration.ValidateIntegerInRange;
import io.prometheus.jmx.common.configuration.ValidateStringIsNotBlank;
import io.prometheus.jmx.common.http.authenticator.MessageDigestAuthenticator;
Expand All @@ -38,7 +40,9 @@
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
Expand Down Expand Up @@ -119,6 +123,7 @@ public HTTPServer createHTTPServer(
configureThreads(httpServerBuilder);
configureAuthentication(httpServerBuilder);
configureSSL(httpServerBuilder);
configureSampleNameFilter(httpServerBuilder);

return httpServerBuilder.build();
}
Expand Down Expand Up @@ -591,6 +596,84 @@ public void configureSSL(HTTPServer.Builder httpServerBuilder) {
}
}

/**
* Method to configure sampleNameFilter
*
* @param httpServerBuilder httpServerBuilder
*/
public void configureSampleNameFilter(HTTPServer.Builder httpServerBuilder) {
Optional<List<String>> allowedNames = Optional.empty();
Optional<List<String>> excludedNames = Optional.empty();
Optional<List<String>> allowedPrefixes = Optional.empty();
Optional<List<String>> excludedPrefixes = Optional.empty();

if (rootYamlMapAccessor.containsPath("/httpServer/sampleNameFilter")) {
YamlMapAccessor httpServerSampleNameFilterMapAccessor =
rootYamlMapAccessor
.get("/httpServer/sampleNameFilter")
.map(
new ConvertToMapAccessor(
ConfigurationException.supplier(
"Invalid configuration for"
+ " /httpServer/sampleNameFilter")))
.orElseThrow(
ConfigurationException.supplier(
"/httpServer/sampleNameFilter configuration values are"
+ " required"));
allowedNames =
httpServerSampleNameFilterMapAccessor
.get("/name-must-be-equal-to")
.map(
new ConvertToStringList(
ConfigurationException.supplier(
"Invalid configuration for"
+ " /httpServer/sampleNameFilter/name-must-be-equal-to"
+ " must be a list of string")));

excludedNames =
httpServerSampleNameFilterMapAccessor
.get("/name-must-not-be-equal-to")
.map(
new ConvertToStringList(
ConfigurationException.supplier(
"Invalid configuration for"
+ " /httpServer/sampleNameFilter/name-must-not-be-equal-to"
+ " must be a list of string")));

allowedPrefixes =
httpServerSampleNameFilterMapAccessor
.get("/name-must-start-with")
.map(
new ConvertToStringList(
ConfigurationException.supplier(
"Invalid configuration for"
+ " /httpServer/sampleNameFilter/name-must-start-with"
+ " must be a list of string")));

excludedPrefixes =
httpServerSampleNameFilterMapAccessor
.get("/name-must-not-start-with")
.map(
new ConvertToStringList(
ConfigurationException.supplier(
"Invalid configuration for"
+ " /httpServer/sampleNameFilter/name-must-not-start-with"
+ " must be a list of string")));

SampleNameFilter.Builder sampleNameFilterBuilder = new SampleNameFilter.Builder();

allowedNames.ifPresent(names -> sampleNameFilterBuilder.nameMustBeEqualTo(names));
excludedNames.ifPresent(names -> sampleNameFilterBuilder.nameMustNotBeEqualTo(names));

allowedPrefixes.ifPresent(
prefixes -> sampleNameFilterBuilder.nameMustStartWith(prefixes));
excludedPrefixes.ifPresent(
prefixes -> sampleNameFilterBuilder.nameMustNotStartWith(prefixes));

httpServerBuilder.withSampleNameFilter(sampleNameFilterBuilder.build());
}
}

/**
* Class to implement a named thread factory
*
Expand Down

0 comments on commit 74d5228

Please sign in to comment.