[KEYCLOAK-13639] - Improvements to metrics and health status
This commit is contained in:
parent
21c7af1c53
commit
42b9141326
7 changed files with 108 additions and 46 deletions
|
@ -37,6 +37,10 @@ import io.quarkus.deployment.IsDevelopment;
|
|||
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
|
||||
import io.quarkus.deployment.builditem.IndexDependencyBuildItem;
|
||||
import io.quarkus.hibernate.orm.deployment.HibernateOrmConfig;
|
||||
import io.quarkus.smallrye.health.runtime.SmallRyeHealthHandler;
|
||||
import io.quarkus.vertx.http.deployment.RouteBuildItem;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -66,7 +70,9 @@ import io.quarkus.deployment.annotations.Record;
|
|||
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
||||
import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem;
|
||||
import io.quarkus.vertx.http.deployment.FilterBuildItem;
|
||||
import org.keycloak.services.NotFoundHandler;
|
||||
import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.services.health.KeycloakMetricsHandler;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.transaction.JBossJtaTransactionManagerLookup;
|
||||
import org.keycloak.util.Environment;
|
||||
|
@ -75,6 +81,8 @@ class KeycloakProcessor {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(KeycloakProcessor.class);
|
||||
|
||||
private static final String DEFAULT_HEALTH_ENDPOINT = "/health";
|
||||
|
||||
@BuildStep
|
||||
FeatureBuildItem getFeature() {
|
||||
return new FeatureBuildItem("keycloak");
|
||||
|
@ -195,13 +203,41 @@ class KeycloakProcessor {
|
|||
indexDependencyBuildItemBuildProducer.produce(new IndexDependencyBuildItem("org.keycloak", "keycloak-services"));
|
||||
}
|
||||
|
||||
@Record(ExecutionTime.RUNTIME_INIT)
|
||||
@BuildStep
|
||||
void initializeFilter(BuildProducer<FilterBuildItem> routes, KeycloakRecorder recorder) {
|
||||
Optional<Boolean> metricsEnabled = Configuration.getOptionalBooleanValue(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat("metrics.enabled"));
|
||||
void initializeFilter(BuildProducer<FilterBuildItem> filters) {
|
||||
filters.produce(new FilterBuildItem(new QuarkusRequestFilter(),FilterBuildItem.AUTHORIZATION - 10));
|
||||
}
|
||||
|
||||
routes.produce(new FilterBuildItem(recorder.createFilter(metricsEnabled.orElse(false)),
|
||||
FilterBuildItem.AUTHORIZATION - 10));
|
||||
/**
|
||||
* <p>Initialize metrics and health endpoints.
|
||||
*
|
||||
* <p>The only reason for manually registering these endpoints is that by default they run as blocking hence
|
||||
* running in a different thread than the worker thread started by {@link QuarkusRequestFilter}.
|
||||
* See https://github.com/quarkusio/quarkus/issues/12990.
|
||||
*
|
||||
* <p>By doing this, custom health checks such as {@link org.keycloak.services.health.KeycloakReadyHealthCheck} is
|
||||
* executed within an active {@link org.keycloak.models.KeycloakSession}, making possible to use it when calculating the
|
||||
* status.
|
||||
*
|
||||
* @param routes
|
||||
*/
|
||||
@BuildStep
|
||||
void initializeMetrics(BuildProducer<RouteBuildItem> routes) {
|
||||
Handler<RoutingContext> healthHandler;
|
||||
Handler<RoutingContext> metricsHandler;
|
||||
|
||||
if (isMetricsEnabled()) {
|
||||
healthHandler = new SmallRyeHealthHandler();
|
||||
metricsHandler = new KeycloakMetricsHandler();
|
||||
} else {
|
||||
healthHandler = new NotFoundHandler();
|
||||
metricsHandler = new NotFoundHandler();
|
||||
}
|
||||
|
||||
routes.produce(new RouteBuildItem(DEFAULT_HEALTH_ENDPOINT, healthHandler));
|
||||
routes.produce(new RouteBuildItem(DEFAULT_HEALTH_ENDPOINT.concat("/live"), healthHandler));
|
||||
routes.produce(new RouteBuildItem(DEFAULT_HEALTH_ENDPOINT.concat("/ready"), healthHandler));
|
||||
routes.produce(new RouteBuildItem(KeycloakMetricsHandler.DEFAULT_METRICS_ENDPOINT, metricsHandler));
|
||||
}
|
||||
|
||||
@BuildStep(onlyIf = IsDevelopment.class)
|
||||
|
@ -310,4 +346,8 @@ class KeycloakProcessor {
|
|||
throw new RuntimeException("No valid ConfigProvider found");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMetricsEnabled() {
|
||||
return Configuration.getOptionalBooleanValue(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat("metrics.enabled")).orElse(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,15 +40,8 @@ public class QuarkusRequestFilter extends AbstractRequestFilter implements Handl
|
|||
// we don't really care about the result because any exception thrown should be handled by the parent class
|
||||
};
|
||||
|
||||
private Predicate<RoutingContext> enabledEndpoints;
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext context) {
|
||||
if (!enabledEndpoints.test(context)) {
|
||||
context.fail(404);
|
||||
return;
|
||||
}
|
||||
|
||||
// our code should always be run as blocking until we don't provide a better support for running non-blocking code
|
||||
// in the event loop
|
||||
context.vertx().executeBlocking(promise -> {
|
||||
|
@ -102,8 +95,4 @@ public class QuarkusRequestFilter extends AbstractRequestFilter implements Handl
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void setEnabledEndpoints(Predicate<RoutingContext> disabledEndpoints) {
|
||||
this.enabledEndpoints = disabledEndpoints;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@ import java.util.function.Predicate;
|
|||
import java.util.stream.StreamSupport;
|
||||
|
||||
import io.smallrye.config.ConfigValue;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.QuarkusKeycloakSessionFactory;
|
||||
import org.keycloak.cli.ShowConfigCommand;
|
||||
|
@ -45,7 +43,6 @@ import org.keycloak.provider.Spi;
|
|||
import io.quarkus.runtime.annotations.Recorder;
|
||||
import liquibase.logging.LogFactory;
|
||||
import liquibase.servicelocator.ServiceLocator;
|
||||
import org.keycloak.provider.quarkus.QuarkusRequestFilter;
|
||||
import org.keycloak.util.Environment;
|
||||
|
||||
@Recorder
|
||||
|
@ -213,23 +210,4 @@ public class KeycloakRecorder {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Handler<RoutingContext> createFilter(boolean metricsEnabled) {
|
||||
QuarkusRequestFilter handler = new QuarkusRequestFilter();
|
||||
|
||||
handler.setEnabledEndpoints(new Predicate<RoutingContext>() {
|
||||
@Override
|
||||
public boolean test(RoutingContext context) {
|
||||
|
||||
if (context.request().uri().startsWith("/metrics") ||
|
||||
context.request().uri().startsWith("/health")) {
|
||||
return metricsEnabled;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.services;
|
||||
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
|
||||
public class NotFoundHandler implements Handler<RoutingContext> {
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext event) {
|
||||
event.fail(404);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.services.health;
|
||||
|
||||
import io.quarkus.smallrye.metrics.runtime.SmallRyeMetricsHandler;
|
||||
|
||||
public class KeycloakMetricsHandler extends SmallRyeMetricsHandler {
|
||||
|
||||
public static final String DEFAULT_METRICS_ENDPOINT = "/metrics";
|
||||
|
||||
public KeycloakMetricsHandler() {
|
||||
setMetricsPath(DEFAULT_METRICS_ENDPOINT);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,9 @@ quarkus.http.root-path=/
|
|||
quarkus.application.name=Keycloak
|
||||
quarkus.banner.enabled=false
|
||||
|
||||
# Disable the default data source health check by Agroal extension, since we provide our own (default is true)
|
||||
quarkus.datasource.health.enabled=false
|
||||
# Disable health checks from extensions, since we provide our own (default is true)
|
||||
quarkus.health.extensions.enabled=false
|
||||
|
||||
# Default transaction timeout
|
||||
quarkus.transaction-manager.default-transaction-timeout=300
|
||||
|
||||
|
|
|
@ -88,9 +88,6 @@ public class JtaTransactionWrapper implements KeycloakTransaction {
|
|||
@Override
|
||||
public void commit() {
|
||||
try {
|
||||
if (Status.STATUS_NO_TRANSACTION == tm.getStatus()) {
|
||||
return;
|
||||
}
|
||||
logger.debug("JtaTransactionWrapper commit");
|
||||
tm.commit();
|
||||
} catch (Exception e) {
|
||||
|
@ -103,9 +100,6 @@ public class JtaTransactionWrapper implements KeycloakTransaction {
|
|||
@Override
|
||||
public void rollback() {
|
||||
try {
|
||||
if (Status.STATUS_NO_TRANSACTION == tm.getStatus()) {
|
||||
return;
|
||||
}
|
||||
logger.debug("JtaTransactionWrapper rollback");
|
||||
tm.rollback();
|
||||
} catch (Exception e) {
|
||||
|
|
Loading…
Reference in a new issue