Skip to content

Commit

Permalink
Add prometheus.case-insensitive-name-matching option
Browse files Browse the repository at this point in the history
  • Loading branch information
lshmouse committed Aug 22, 2022
1 parent b6278b6 commit 49e6b75
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/src/main/sphinx/connector/prometheus.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Property name Description
``prometheus.auth.password`` Password for basic authentication
``prometheus.bearer.token.file`` File holding bearer token if needed for access to Prometheus
``prometheus.read-timeout`` How much time a query to Prometheus has before timing out
``prometheus.case-insensitive-name-matching`` Match Prometheus metric names case insensitively. Defaults to ``false``
============================================= ============================================================================================

Not exhausting your Trino available heap
Expand Down
5 changes: 5 additions & 0 deletions plugin/trino-prometheus/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import okhttp3.Request;
import okhttp3.Response;

import javax.annotation.Nullable;
import javax.inject.Inject;

import java.io.File;
Expand All @@ -41,6 +42,7 @@
import java.util.Set;
import java.util.function.Supplier;

import static com.google.common.base.Verify.verify;
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
import static io.trino.plugin.prometheus.PrometheusErrorCode.PROMETHEUS_TABLES_METRICS_RETRIEVE_ERROR;
import static io.trino.plugin.prometheus.PrometheusErrorCode.PROMETHEUS_UNKNOWN_ERROR;
Expand All @@ -50,6 +52,7 @@
import static io.trino.spi.type.VarcharType.VARCHAR;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.Files.readString;
import static java.util.Locale.ENGLISH;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

Expand All @@ -61,6 +64,7 @@ public class PrometheusClient
private final OkHttpClient httpClient;
private final Supplier<Map<String, Object>> tableSupplier;
private final Type varcharMapType;
private final boolean caseInsensitiveNameMatching;

@Inject
public PrometheusClient(PrometheusConnectorConfig config, JsonCodec<Map<String, Object>> metricCodec, TypeManager typeManager)
Expand All @@ -80,6 +84,7 @@ public PrometheusClient(PrometheusConnectorConfig config, JsonCodec<Map<String,
config.getCacheDuration().toMillis(),
MILLISECONDS);
varcharMapType = typeManager.getType(mapType(VARCHAR.getTypeSignature(), VARCHAR.getTypeSignature()));
this.caseInsensitiveNameMatching = config.isCaseInsensitiveNameMatching();
}

private static URI getPrometheusMetricsURI(URI prometheusUri)
Expand All @@ -106,6 +111,7 @@ public Set<String> getTableNames(String schema)
throw new TrinoException(PROMETHEUS_TABLES_METRICS_RETRIEVE_ERROR, "Prometheus did no return metrics list (table names): " + status);
}

@Nullable
public PrometheusTable getTable(String schema, String tableName)
{
requireNonNull(schema, "schema is null");
Expand All @@ -114,21 +120,43 @@ public PrometheusTable getTable(String schema, String tableName)
return null;
}

List<String> tableNames = (List<String>) tableSupplier.get().get("data");
if (tableNames == null) {
return null;
}
if (!tableNames.contains(tableName)) {
String remoteTableName = toRemoteTableName(tableName);
if (remoteTableName == null) {
return null;
}
return new PrometheusTable(
tableName,
remoteTableName,
ImmutableList.of(
new PrometheusColumn("labels", varcharMapType),
new PrometheusColumn("timestamp", TIMESTAMP_COLUMN_TYPE),
new PrometheusColumn("value", DoubleType.DOUBLE)));
}

@Nullable
private String toRemoteTableName(String tableName)
{
verify(tableName.equals(tableName.toLowerCase(ENGLISH)), "tableName not in lower-case: %s", tableName);
List<String> tableNames = (List<String>) tableSupplier.get().get("data");
if (tableNames == null) {
return null;
}

if (!caseInsensitiveNameMatching) {
if (tableNames.contains(tableName)) {
return tableName;
}
}
else {
for (String remoteTableName : tableNames) {
if (tableName.equals(remoteTableName.toLowerCase(ENGLISH))) {
return remoteTableName;
}
}
}

return null;
}

private Map<String, Object> fetchMetrics(JsonCodec<Map<String, Object>> metricsCodec, URI metadataUri)
{
return metricsCodec.fromJson(fetchUri(metadataUri));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class PrometheusConnectorConfig
private File bearerTokenFile;
private String user;
private String password;
private boolean caseInsensitiveNameMatching;

@NotNull
public URI getPrometheusURI()
Expand Down Expand Up @@ -151,6 +152,19 @@ public PrometheusConnectorConfig setReadTimeout(Duration readTimeout)
return this;
}

public boolean isCaseInsensitiveNameMatching()
{
return caseInsensitiveNameMatching;
}

@Config("prometheus.case-insensitive-name-matching")
@ConfigDescription("Where to match the prometheus metric name case insensitively ")
public PrometheusConnectorConfig setCaseInsensitiveNameMatching(boolean caseInsensitiveNameMatching)
{
this.caseInsensitiveNameMatching = caseInsensitiveNameMatching;
return this;
}

@PostConstruct
public void checkConfig()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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.trino.plugin.prometheus;

import io.trino.spi.connector.SchemaTableName;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.List;
import java.util.Optional;
import java.util.Set;

import static io.trino.plugin.prometheus.MetadataUtil.METRIC_CODEC;
import static io.trino.type.InternalTypeManager.TESTING_TYPE_MANAGER;
import static java.util.Locale.ENGLISH;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;

public class TestPrometheusCaseInsensitiveNameMatching
{
private PrometheusHttpServer prometheusHttpServer;
private static final String DEFAULT_SCHEMA = "default";
private static final String UPPER_CASE_METRIC = "UpperCase-Metric";

@BeforeClass
public void setUp()
{
prometheusHttpServer = new PrometheusHttpServer();
}

@AfterClass(alwaysRun = true)
public void tearDown()
{
if (prometheusHttpServer != null) {
prometheusHttpServer.stop();
}
}

@Test
public void testCaseInsensitiveNameMatchingFalse()
{
PrometheusConnectorConfig config = new PrometheusConnectorConfig();
config.setPrometheusURI(prometheusHttpServer.resolve("/prometheus-data/uppercase-metrics.json"));

PrometheusClient client = new PrometheusClient(config, METRIC_CODEC, TESTING_TYPE_MANAGER);

Set<String> tableNames = client.getTableNames(DEFAULT_SCHEMA);
assertThat(tableNames).hasSize(1);
assertTrue(tableNames.contains(UPPER_CASE_METRIC));

PrometheusMetadata metadata = new PrometheusMetadata(client);
List<SchemaTableName> tables = metadata.listTables(null, Optional.of(DEFAULT_SCHEMA));
assertThat(tableNames).hasSize(1);
assertEquals(UPPER_CASE_METRIC.toLowerCase(ENGLISH), tables.get(0).getTableName());

assertNull(client.getTable(DEFAULT_SCHEMA, tables.get(0).getTableName()));
}

@Test
public void testCaseInsensitiveNameMatchingTrue()
{
PrometheusConnectorConfig config = new PrometheusConnectorConfig();
config.setPrometheusURI(prometheusHttpServer.resolve("/prometheus-data/uppercase-metrics.json"));
config.setCaseInsensitiveNameMatching(true);

PrometheusClient client = new PrometheusClient(config, METRIC_CODEC, TESTING_TYPE_MANAGER);

Set<String> tableNames = client.getTableNames(DEFAULT_SCHEMA);
assertThat(tableNames).hasSize(1);
assertTrue(tableNames.contains(UPPER_CASE_METRIC));

PrometheusMetadata metadata = new PrometheusMetadata(client);
List<SchemaTableName> tables = metadata.listTables(null, Optional.of(DEFAULT_SCHEMA));
assertThat(tableNames).hasSize(1);
SchemaTableName table = tables.get(0);
assertEquals(UPPER_CASE_METRIC.toLowerCase(ENGLISH), table.getTableName());

assertNotNull(client.getTable(DEFAULT_SCHEMA, tables.get(0).getTableName()));
assertEquals(UPPER_CASE_METRIC, client.getTable(DEFAULT_SCHEMA, tables.get(0).getTableName()).getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public void testDefaults()
.setBearerTokenFile(null)
.setUser(null)
.setPassword(null)
.setReadTimeout(new Duration(10, SECONDS)));
.setReadTimeout(new Duration(10, SECONDS))
.setCaseInsensitiveNameMatching(false));
}

@Test
Expand All @@ -59,6 +60,7 @@ public void testExplicitPropertyMappings()
.put("prometheus.auth.user", "admin")
.put("prometheus.auth.password", "password")
.put("prometheus.read-timeout", "30s")
.put("prometheus.case-insensitive-name-matching", "true")
.buildOrThrow();

URI uri = URI.create("file://test.json");
Expand All @@ -71,6 +73,7 @@ public void testExplicitPropertyMappings()
expected.setUser("admin");
expected.setPassword("password");
expected.setReadTimeout(new Duration(30, SECONDS));
expected.setCaseInsensitiveNameMatching(true);

assertFullMapping(properties, expected);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"status": "success",
"data": [
"UpperCase-Metric"
]
}

0 comments on commit 49e6b75

Please sign in to comment.