diff --git a/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonClientBuilder.java b/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonClientBuilder.java index 6a5f843dce9..d4cc853c924 100644 --- a/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonClientBuilder.java +++ b/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonClientBuilder.java @@ -126,6 +126,12 @@ public T mapperManager(MapperManager manager) { return identity(); } + @Override + public T dbMapperManager(DbMapperManager manager) { + this.dbMapperManager = manager; + return identity(); + } + @Override public T addMapperProvider(DbMapperProvider provider) { this.dbMapperBuilder.addMapperProvider(provider); diff --git a/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonService.java b/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonService.java index 20afa7f1893..a10fd5c18f8 100644 --- a/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonService.java +++ b/dbclient/common/src/main/java/io/helidon/dbclient/common/CommonService.java @@ -42,7 +42,7 @@ public abstract class CommonService implements DbClientService { * * @param builder builder to configure predicate to use */ - protected CommonService(CommonServiceBuilder builder) { + protected CommonService(CommonServiceBuilder builder) { this.predicate = builder.predicate(); } @@ -68,8 +68,9 @@ public final DbClientServiceContext statement(DbClientServiceContext context) { * A base class for builders of {@link CommonService}. * * @param type of the builder extending this class + * @param Type of the built {@link CommonService} instance */ - public abstract static class CommonServiceBuilder> implements Builder { + public abstract static class CommonServiceBuilder, T extends CommonService> implements Builder { private static final Predicate YES = it -> true; private static final Predicate NO = it -> false; diff --git a/dbclient/dbclient/src/main/java/io/helidon/dbclient/spi/DbClientBuilder.java b/dbclient/dbclient/src/main/java/io/helidon/dbclient/spi/DbClientBuilder.java index 98298200be6..d54e13fcdd7 100644 --- a/dbclient/dbclient/src/main/java/io/helidon/dbclient/spi/DbClientBuilder.java +++ b/dbclient/dbclient/src/main/java/io/helidon/dbclient/spi/DbClientBuilder.java @@ -22,6 +22,7 @@ import io.helidon.dbclient.DbClient; import io.helidon.dbclient.DbClientService; import io.helidon.dbclient.DbMapper; +import io.helidon.dbclient.DbMapperManager; import io.helidon.dbclient.DbStatements; /** @@ -108,6 +109,14 @@ public interface DbClientBuilder> extends Builder + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + + + + + diff --git a/dbclient/metrics/pom.xml b/dbclient/metrics/pom.xml new file mode 100644 index 00000000000..c93aafcd62e --- /dev/null +++ b/dbclient/metrics/pom.xml @@ -0,0 +1,72 @@ + + + + + 4.0.0 + + io.helidon.dbclient + helidon-dbclient-project + 4.0.0-SNAPSHOT + ../pom.xml + + + helidon-dbclient-metrics + Helidon DB Client Metrics + Helidon Database Client Metrics + + + + io.helidon.dbclient + helidon-dbclient-common + ${project.version} + + + io.helidon.metrics + helidon-metrics-api + + + io.helidon.common.features + helidon-common-features-api + + + io.helidon.metrics + helidon-metrics + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + + + + + + diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetricBuilder.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetricBuilder.java new file mode 100644 index 00000000000..abdbd4606a3 --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetricBuilder.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import io.helidon.dbclient.common.CommonService; + +/** + * DB Client metric builder. + * + * @param type of the builder extending this class + * @param Type of the built {@link CommonService} instance + */ +public abstract class DbClientMetricBuilder, T extends CommonService> + extends MetricBuilderBase { +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetrics.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetrics.java new file mode 100644 index 00000000000..8ea999e9639 --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetrics.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import io.helidon.dbclient.common.CommonService; + +/** + * Utility class to obtain various types of metrics to register + * with {@link io.helidon.dbclient.DbClient.Builder#addService(io.helidon.dbclient.DbClientService)}. + * Metrics can be limited to a set of statement types or statement names, and also configured to + * meter success, failure or both. + * + * @see DbClientMetricBuilder#statementTypes(io.helidon.dbclient.DbStatementType...) + * @see DbClientMetricBuilder#statementNames(String...) + * @see DbClientMetricBuilder#statementPredicate(java.util.function.Predicate) + * @see DbClientMetricBuilder#success(boolean) + * @see DbClientMetricBuilder#errors(boolean) + */ +public class DbClientMetrics { + private DbClientMetrics() { + } + + /** + * Create a counter builder, to be registered + * with {@link io.helidon.dbclient.DbClient.Builder#addService(java.util.function.Supplier)}. + * + * @return a new counter builder + * @see org.eclipse.microprofile.metrics.Counter + */ + public static DbClientMetricBuilder, ? extends CommonService> counter() { + return MetricCounter.builder(); + } + + /** + * Create a meter builder, to be registered + * with {@link io.helidon.dbclient.DbClient.Builder#addService(java.util.function.Supplier)}. + * + * @return a new meter builder + * @see org.eclipse.microprofile.metrics.Meter + */ + public static DbClientMetricBuilder, ? extends CommonService> meter() { + return MetricMeter.builder(); + } + + /** + * Create a timer builder, to be registered + * with {@link io.helidon.dbclient.DbClient.Builder#addService(java.util.function.Supplier)}. + * + * @return a new timer builder + * @see org.eclipse.microprofile.metrics.Timer + */ + public static DbClientMetricBuilder, ? extends CommonService> timer() { + return MetricTimer.builder(); + } + +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetricsProvider.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetricsProvider.java new file mode 100644 index 00000000000..d7ba6b19645 --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/DbClientMetricsProvider.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClientException; +import io.helidon.dbclient.DbClientService; +import io.helidon.dbclient.spi.DbClientServiceProvider; + +/** + * Java service loader service for DB metrics. + */ +public class DbClientMetricsProvider implements DbClientServiceProvider { + private static final System.Logger LOGGER = System.getLogger(DbClientMetricsProvider.class.getName()); + + @Override + public String configKey() { + return "metrics"; + } + + @Override + public Collection create(Config config) { + List metricConfigs = config.asNodeList().orElseGet(List::of); + List result = new LinkedList<>(); + + for (Config metricConfig : metricConfigs) { + result.add(fromConfig(metricConfig)); + } + + if (result.isEmpty()) { + LOGGER.log(System.Logger.Level.INFO, "DB Client metrics are enabled, yet none are configured in config."); + } + + return result; + } + + private DbClientService fromConfig(Config config) { + String type = config.get("type").asString().orElse("COUNTER"); + switch (type) { + case "COUNTER": + return DbClientMetrics.counter().config(config).build(); + case "METER": + return DbClientMetrics.meter().config(config).build(); + case "TIMER": + return DbClientMetrics.timer().config(config).build(); + default: + throw new DbClientException("Metrics type " + type + " is not supported through service loader"); + } + } +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricBuilderBase.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricBuilderBase.java new file mode 100644 index 00000000000..14dc19f9a1e --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricBuilderBase.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import java.util.function.BiFunction; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbStatementType; +import io.helidon.dbclient.common.CommonService; + +import org.eclipse.microprofile.metrics.Metadata; + +/** + * A metric builder used as a base for Helidon DB metrics. + * + * @param type of the builder extending this class + * @param Type of the built {@link CommonService} instance + */ +abstract class MetricBuilderBase, T extends CommonService> + extends CommonService.CommonServiceBuilder { + + private Metadata meta; + private BiFunction nameFormat; + private boolean measureErrors = true; + private boolean measureSuccess = true; + private String description; + + /** + * Configure a metric name. + * + * @param metricName name of the metric + * @return updated builder instance + */ + public B name(String metricName) { + nameFormat = (s, s2) -> metricName; + return me(); + } + + /** + * Configure metric metadata. + * + * @param meta metric metadata + * @return updated builder instance + */ + public B metadata(Metadata meta) { + this.meta = meta; + return me(); + } + + /** + * Configure a name format. + *

The format can use up to two parameters - first is the {@link io.helidon.dbclient.DbStatementType} + * as a string, second is the statement name. + * + * @param format format string expecting zero to two parameters that can be processed by + * {@link String#format(String, Object...)} + * @return updated builder instance + */ + public B nameFormat(String format) { + return nameFormat((name, queryType) -> String.format(format, queryType.toString(), name)); + } + + /** + * Configure a name format function. + *

The first parameter is the statement name. + * + * @param function function to use to create metric name + * @return updated builder instance + */ + public B nameFormat(BiFunction function) { + this.nameFormat = function; + return me(); + } + + /** + * Whether to measure failed statements. + * + * @param measureErrors set to {@code false} if errors should be ignored + * @return updated builder instance + */ + public B errors(boolean measureErrors) { + this.measureErrors = measureErrors; + return me(); + } + + /** + * Whether to measure successful statements. + * + * @param measureSuccess set to {@code false} if successes should be ignored + * @return updated builder instance + */ + public B success(boolean measureSuccess) { + this.measureSuccess = measureSuccess; + return me(); + } + + /** + * Description of the metric used in metric metadata. + * + * @param description description + * @return updated builder instance + */ + public B description(String description) { + this.description = description; + return me(); + } + + /** + * Configure a metric from configuration. + * The following configuration key are used: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
DB Metric configuration options
keydefaultdescription
errors{@code true}Whether this metric triggers for error states
success{@code true}Whether this metric triggers for successful executions
name-format{@code db.metric-type.statement-name}A string format used to construct a metric name. The format gets two parameters: the statement name and the + * statement type
description Description of this metric, used in metric {@link org.eclipse.microprofile.metrics.Metadata}
+ * + * @param config configuration to configure this metric + * @return updated builder instance + */ + public B config(Config config) { + super.config(config); + config.get("errors").asBoolean().ifPresent(this::errors); + config.get("success").asBoolean().ifPresent(this::success); + config.get("name-format").asString().ifPresent(this::nameFormat); + config.get("description").asString().ifPresent(this::description); + return me(); + } + + String description() { + return description; + } + + @SuppressWarnings("unchecked") + B me() { + return (B) this; + } + + Metadata meta() { + return meta; + } + + BiFunction nameFormat() { + return nameFormat; + } + + boolean errors() { + return measureErrors; + } + + boolean success() { + return measureSuccess; + } +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricCounter.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricCounter.java new file mode 100644 index 00000000000..7b34d371bd2 --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricCounter.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import java.util.concurrent.CompletionStage; + +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.MetricType; + +/** + * Counter metric for Helidon DB. This class implements the {@link io.helidon.dbclient.DbClientService} and + * can be configured either through a {@link io.helidon.dbclient.DbClient.Builder} or through configuration. + */ +final class MetricCounter extends MetricService { + + private MetricCounter(Builder builder) { + super(builder); + } + + /** + * Create a new fluent API builder to create a new counter metric. + * @return a new builder instance + */ + static Builder builder() { + return new Builder(); + } + + @Override + protected void executeMetric(Counter metric, CompletionStage aFuture) { + aFuture.thenRun(() -> { + if (measureSuccess()) { + metric.inc(); + } + }).exceptionally(throwable -> { + if (measureErrors()) { + metric.inc(); + } + return null; + }); + } + + @Override + protected MetricType metricType() { + return MetricType.COUNTER; + } + + @Override + protected Counter metric(MetricRegistry registry, Metadata meta) { + return registry.counter(meta); + } + + @Override + protected String defaultNamePrefix() { + return "db.counter."; + } + + /** + * Fluent API builder for {@link MetricCounter}. + */ + static class Builder extends DbClientMetricBuilder { + + @Override + public MetricCounter build() { + return new MetricCounter(this); + } + + } + +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricMeter.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricMeter.java new file mode 100644 index 00000000000..90ecb946c65 --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricMeter.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import java.util.concurrent.CompletionStage; + +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.Meter; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.MetricType; + +/** + * Meter for Helidon DB. This class implements the {@link io.helidon.dbclient.DbClientService} and + * can be configured either through a {@link io.helidon.dbclient.DbClient.Builder} or through configuration. + */ +final class MetricMeter extends MetricService { + + private MetricMeter(Builder builder) { + super(builder); + } + + /** + * Create a new fluent API builder to create a new meter metric. + * @return a new builder instance + */ + static Builder builder() { + return new Builder(); + } + + @Override + protected void executeMetric(Meter metric, CompletionStage aFuture) { + aFuture + .thenAccept(nothing -> { + if (measureSuccess()) { + metric.mark(); + } + }) + .exceptionally(throwable -> { + if (measureErrors()) { + metric.mark(); + } + return null; + }); + } + + @Override + protected MetricType metricType() { + return MetricType.METERED; + } + + @Override + protected Meter metric(MetricRegistry registry, Metadata meta) { + return registry.meter(meta); + } + + @Override + protected String defaultNamePrefix() { + return "db.meter."; + } + + /** + * Fluent API builder for {@link MetricMeter}. + */ + static class Builder extends DbClientMetricBuilder { + + @Override + public MetricMeter build() { + return new MetricMeter(this); + } + + } + +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricService.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricService.java new file mode 100644 index 00000000000..a089960f278 --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricService.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; + +import io.helidon.common.LazyValue; +import io.helidon.dbclient.DbClientServiceContext; +import io.helidon.dbclient.DbStatementType; +import io.helidon.dbclient.common.CommonService; +import io.helidon.metrics.api.RegistryFactory; + +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.MetadataBuilder; +import org.eclipse.microprofile.metrics.Metric; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.MetricType; + +/** + * Common ancestor for Helidon DB metrics. + */ +abstract class MetricService extends CommonService { + private final Metadata meta; + private final String description; + private final BiFunction nameFunction; + private final LazyValue registry = LazyValue.create( + () -> RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION)); + private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); + private final boolean measureErrors; + private final boolean measureSuccess; + + protected MetricService(MetricBuilderBase builder) { + super(builder); + + BiFunction nameFunction = builder.nameFormat(); + this.meta = builder.meta(); + + if (null == nameFunction) { + nameFunction = (name, statement) -> defaultNamePrefix() + name; + } + this.nameFunction = nameFunction; + this.measureErrors = builder.errors(); + this.measureSuccess = builder.success(); + String tmpDescription; + if (builder.description() == null) { + tmpDescription = ((null == meta) ? null : meta.getDescription()); + } else { + tmpDescription = builder.description(); + } + this.description = tmpDescription; + } + + protected abstract String defaultNamePrefix(); + + @Override + protected DbClientServiceContext apply(DbClientServiceContext context) { + DbStatementType dbStatementType = context.statementType(); + String statementName = context.statementName(); + + T metric = cache.computeIfAbsent(statementName, s -> { + String name = nameFunction.apply(statementName, dbStatementType); + MetadataBuilder builder = (meta == null) + ? Metadata.builder().withName(name).withType(metricType()) + : Metadata.builder(meta); + if (description != null) { + builder = builder.withDescription(description); + } + return metric(registry.get(), builder.build()); + }); + + executeMetric(metric, context.statementFuture()); + + return context; + } + + protected boolean measureErrors() { + return measureErrors; + } + + protected boolean measureSuccess() { + return measureSuccess; + } + + protected abstract void executeMetric(T metric, CompletionStage aFuture); + protected abstract MetricType metricType(); + protected abstract T metric(MetricRegistry registry, Metadata meta); +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricTimer.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricTimer.java new file mode 100644 index 00000000000..74eb875d96b --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/MetricTimer.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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.helidon.dbclient.metrics; + +import java.time.Duration; +import java.util.concurrent.CompletionStage; + +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.MetricType; +import org.eclipse.microprofile.metrics.Timer; + +/** + * Timer metric for Helidon DB. This class implements the {@link io.helidon.dbclient.DbClientService} and + * can be configured either through a {@link io.helidon.dbclient.DbClient.Builder} or through configuration. + */ +final class MetricTimer extends MetricService { + + private MetricTimer(Builder builder) { + super(builder); + } + + /** + * Create a new fluent API builder to create a new timer metric. + * @return a new builder instance + */ + static Builder builder() { + return new Builder(); + } + + @Override + protected void executeMetric(Timer metric, CompletionStage aFuture) { + long started = System.nanoTime(); + + aFuture + .thenAccept(nothing -> { + if (measureSuccess()) { + update(metric, started); + } + }) + .exceptionally(throwable -> { + if (measureErrors()) { + update(metric, started); + } + return null; + }); + } + + private void update(Timer metric, long started) { + long delta = System.nanoTime() - started; + metric.update(Duration.ofNanos(delta)); + } + + @Override + protected String defaultNamePrefix() { + return "db.timer."; + } + + @Override + protected MetricType metricType() { + return MetricType.TIMER; + } + + @Override + protected Timer metric(MetricRegistry registry, Metadata meta) { + return registry.timer(meta); + } + + /** + * Fluent API builder for {@link MetricTimer}. + */ + static class Builder extends DbClientMetricBuilder { + + @Override + public MetricTimer build() { + return new MetricTimer(this); + } + + } +} diff --git a/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/package-info.java b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/package-info.java new file mode 100644 index 00000000000..8b8a0ddf848 --- /dev/null +++ b/dbclient/metrics/src/main/java/io/helidon/dbclient/metrics/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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. + */ +/** + * Metrics support for Helidon DB Client. + */ +package io.helidon.dbclient.metrics; diff --git a/dbclient/metrics/src/main/java/module-info.java b/dbclient/metrics/src/main/java/module-info.java new file mode 100644 index 00000000000..d5e0f694fb4 --- /dev/null +++ b/dbclient/metrics/src/main/java/module-info.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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. + */ + +import io.helidon.common.features.api.Feature; +import io.helidon.common.features.api.HelidonFlavor; +import io.helidon.dbclient.metrics.DbClientMetricsProvider; +import io.helidon.dbclient.spi.DbClientServiceProvider; + +/** + * Helidon DB Client Metrics. + */ +@Feature(value = "Metrics", + description = "Database client metrics support", + in = HelidonFlavor.SE, + path = {"DbClient", "Metrics"} +) +module io.helidon.dbclient.metrics { + + requires static io.helidon.common.features.api; + requires io.helidon.dbclient; + requires io.helidon.dbclient.common; + requires io.helidon.metrics.api; + + exports io.helidon.dbclient.metrics; + + provides DbClientServiceProvider with DbClientMetricsProvider; + +} \ No newline at end of file diff --git a/dbclient/pom.xml b/dbclient/pom.xml index a14077fee82..5892740a51c 100644 --- a/dbclient/pom.xml +++ b/dbclient/pom.xml @@ -35,6 +35,7 @@ common jdbc tracing + metrics health diff --git a/dbclient/tracing/src/main/java/io/helidon/dbclient/tracing/DbClientTracing.java b/dbclient/tracing/src/main/java/io/helidon/dbclient/tracing/DbClientTracing.java index 74b31e7d595..1fb90b098bf 100644 --- a/dbclient/tracing/src/main/java/io/helidon/dbclient/tracing/DbClientTracing.java +++ b/dbclient/tracing/src/main/java/io/helidon/dbclient/tracing/DbClientTracing.java @@ -121,7 +121,7 @@ protected DbClientServiceContext apply(DbClientServiceContext serviceContext) { /** * Fluent API builder for {@link DbClientTracing}. */ - public static class Builder extends CommonServiceBuilder { + public static class Builder extends CommonServiceBuilder { private Builder() { }