Enable Infinispan metrics automatically if overall metrics are enabled

Closes #27724

Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Alexander Schwartz 2024-03-08 16:09:07 +01:00 committed by Alexander Schwartz
parent a32808e8eb
commit 1788cf2b09
13 changed files with 57 additions and 134 deletions

View file

@ -1,3 +1,8 @@
= Metrics for embedded caches enabled by default
Metrics for the embedded caches are now enabled by default.
To enable histograms for latencies, set the option `cache-metrics-histograms-enabled` to `true`.
= Nonce claim is only added to the ID token = Nonce claim is only added to the ID token
The nonce claim is now only added to the ID token strictly following the OpenID Connect Core 1.0 specification. As indicated in the specification, the claim is compulsory inside the https://openid.net/specs/openid-connect-core-1_0.html#IDToken[ID token] when the same parameter was sent in the authorization request. The specification also recommends to not add the `nonce` after a https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse[refresh request]. Previously, the claim was set to all the tokens (Access, Refresh and ID) in all the responses (refresh included). The nonce claim is now only added to the ID token strictly following the OpenID Connect Core 1.0 specification. As indicated in the specification, the claim is compulsory inside the https://openid.net/specs/openid-connect-core-1_0.html#IDToken[ID token] when the same parameter was sent in the authorization request. The specification also recommends to not add the `nonce` after a https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse[refresh request]. Previously, the claim was set to all the tokens (Access, Refresh and ID) in all the responses (refresh included).

View file

@ -258,26 +258,13 @@ For more information about securing cache communication, see the https://infinis
== Exposing metrics from caches == Exposing metrics from caches
By default, metrics from caches are not automatically exposed when the metrics are enabled. Metrics from caches are automatically exposed when the metrics are enabled.
To enable histograms for the cache metrics, set `cache-metrics-histograms-enabled` to `true`.
While these metrics provide more insights into the latency distribution, collecting them might have a performance impact, so you should be cautious to activate them in an already saturated system.
<@kc.start parameters="--metrics-enabled true --cache-metrics-histograms-enabled true"/>
For more details about how to enable metrics, see <@links.server id="configuration-metrics"/>. For more details about how to enable metrics, see <@links.server id="configuration-metrics"/>.
To enable global metrics for all caches within the `cache-container`, you need to change your cache configuration file (e.g.: `conf/cache-ispn.xml`) to enable `statistics` at the `cache-container` level as follows:
.enabling metrics for all caches
[source]
----
<cache-container name="keycloak" statistics="true">
...
</cache-container>
----
Similarly, you can enable metrics individually for each cache by enabling `statistics` as follows:
.enabling metrics for a specific cache
----
<local-cache name="realms" statistics="true">
...
</local-cache>
----
</@tmpl.guide> </@tmpl.guide>

View file

@ -19,6 +19,9 @@ public class CachingOptions {
public static final String CACHE_REMOTE_USERNAME_PROPERTY = CACHE_REMOTE_PREFIX + "-username"; public static final String CACHE_REMOTE_USERNAME_PROPERTY = CACHE_REMOTE_PREFIX + "-username";
public static final String CACHE_REMOTE_PASSWORD_PROPERTY = CACHE_REMOTE_PREFIX + "-password"; public static final String CACHE_REMOTE_PASSWORD_PROPERTY = CACHE_REMOTE_PREFIX + "-password";
private static final String CACHE_METRICS_PREFIX = "cache-metrics";
public static final String CACHE_METRICS_HISTOGRAMS_ENABLED_PROPERTY = CACHE_METRICS_PREFIX + "-histograms-enabled";
public enum Mechanism { public enum Mechanism {
ispn, ispn,
local local
@ -117,4 +120,9 @@ public class CachingOptions {
CACHE_CONFIG_FILE_PROPERTY, CACHE_REMOTE_HOST_PROPERTY, CACHE_REMOTE_USERNAME_PROPERTY)) CACHE_CONFIG_FILE_PROPERTY, CACHE_REMOTE_HOST_PROPERTY, CACHE_REMOTE_USERNAME_PROPERTY))
.build(); .build();
public static final Option<Boolean> CACHE_METRICS_HISTOGRAMS_ENABLED = new OptionBuilder<>(CACHE_METRICS_HISTOGRAMS_ENABLED_PROPERTY, Boolean.class)
.category(OptionCategory.CACHE)
.description("Enable histograms for metrics for the embedded caches.")
.build();
} }

View file

@ -61,6 +61,11 @@ final class CachingPropertyMappers {
.paramLabel("password") .paramLabel("password")
.isMasked(true) .isMasked(true)
.build(), .build(),
fromOption(CachingOptions.CACHE_METRICS_HISTOGRAMS_ENABLED)
.isEnabled(MetricsPropertyMappers::metricsEnabled, MetricsPropertyMappers.METRICS_ENABLED_MSG)
.build(),
}; };
} }

View file

@ -2,11 +2,14 @@ package org.keycloak.quarkus.runtime.configuration.mappers;
import org.keycloak.config.MetricsOptions; import org.keycloak.config.MetricsOptions;
import static org.keycloak.quarkus.runtime.configuration.Configuration.isTrue;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption; import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
final class MetricsPropertyMappers { final class MetricsPropertyMappers {
public static final String METRICS_ENABLED_MSG = "metrics are enabled";
private MetricsPropertyMappers(){} private MetricsPropertyMappers(){}
public static PropertyMapper<?>[] getMetricsPropertyMappers() { public static PropertyMapper<?>[] getMetricsPropertyMappers() {
@ -18,4 +21,7 @@ final class MetricsPropertyMappers {
}; };
} }
public static boolean metricsEnabled() {
return isTrue(MetricsOptions.METRICS_ENABLED);
}
} }

View file

@ -50,6 +50,7 @@ import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_KEYSTORE_FI
import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_KEYSTORE_PASSWORD_PROPERTY; import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_KEYSTORE_PASSWORD_PROPERTY;
import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_TRUSTSTORE_FILE_PROPERTY; import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_TRUSTSTORE_FILE_PROPERTY;
import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_TRUSTSTORE_PASSWORD_PROPERTY; import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_TRUSTSTORE_PASSWORD_PROPERTY;
import static org.keycloak.config.CachingOptions.CACHE_METRICS_HISTOGRAMS_ENABLED_PROPERTY;
import static org.keycloak.config.CachingOptions.CACHE_REMOTE_HOST_PROPERTY; import static org.keycloak.config.CachingOptions.CACHE_REMOTE_HOST_PROPERTY;
import static org.keycloak.config.CachingOptions.CACHE_REMOTE_PASSWORD_PROPERTY; import static org.keycloak.config.CachingOptions.CACHE_REMOTE_PASSWORD_PROPERTY;
import static org.keycloak.config.CachingOptions.CACHE_REMOTE_PORT_PROPERTY; import static org.keycloak.config.CachingOptions.CACHE_REMOTE_PORT_PROPERTY;
@ -110,6 +111,12 @@ public class CacheManagerFactory {
if (metricsEnabled) { if (metricsEnabled) {
builder.getGlobalConfigurationBuilder().addModule(MicrometerMeterRegisterConfigurationBuilder.class); builder.getGlobalConfigurationBuilder().addModule(MicrometerMeterRegisterConfigurationBuilder.class);
builder.getGlobalConfigurationBuilder().module(MicrometerMeterRegisterConfigurationBuilder.class).meterRegistry(Metrics.globalRegistry); builder.getGlobalConfigurationBuilder().module(MicrometerMeterRegisterConfigurationBuilder.class).meterRegistry(Metrics.globalRegistry);
builder.getGlobalConfigurationBuilder().cacheContainer().statistics(true);
builder.getGlobalConfigurationBuilder().metrics().namesAsTags(true);
if (booleanProperty(CACHE_METRICS_HISTOGRAMS_ENABLED_PROPERTY)) {
builder.getGlobalConfigurationBuilder().metrics().histograms(true);
}
builder.getNamedConfigurationBuilders().forEach((s, configurationBuilder) -> configurationBuilder.statistics().enabled(true));
} }
// For Infinispan 10, we go with the JBoss marshalling. // For Infinispan 10, we go with the JBoss marshalling.

View file

@ -23,7 +23,6 @@
<cache-container name="keycloak"> <cache-container name="keycloak">
<transport lock-timeout="60000"/> <transport lock-timeout="60000"/>
<metrics names-as-tags="true" />
<local-cache name="realms" simple-cache="true"> <local-cache name="realms" simple-cache="true">
<encoding> <encoding>
<key media-type="application/x-java-object"/> <key media-type="application/x-java-object"/>

View file

@ -22,7 +22,6 @@
xmlns="urn:infinispan:config:14.0"> xmlns="urn:infinispan:config:14.0">
<cache-container name="keycloak"> <cache-container name="keycloak">
<metrics names-as-tags="true" />
<local-cache name="default"> <local-cache name="default">
<transaction transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup"/> <transaction transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup"/>
</local-cache> </local-cache>

View file

@ -21,15 +21,11 @@ import static io.restassured.RestAssured.when;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.keycloak.it.junit5.extension.BeforeStartDistribution;
import org.keycloak.it.junit5.extension.DistributionTest; import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
import org.keycloak.it.utils.KeycloakDistribution; import org.keycloak.it.utils.KeycloakDistribution;
import io.quarkus.test.junit.main.Launch; import io.quarkus.test.junit.main.Launch;
@ -52,26 +48,21 @@ public class MetricsDistTest {
when().get("/metrics").then() when().get("/metrics").then()
.statusCode(200) .statusCode(200)
.body(containsString("jvm_gc_")) .body(containsString("jvm_gc_"))
.body(not(containsString("vendor_cache_manager_keycloak_cache_realms_"))); .body(containsString("vendor_statistics_hit_ratio"))
} .body(not(containsString("vendor_statistics_miss_times_seconds_bucket")));
@Test
@Launch({ "start-dev", "--metrics-enabled=true", "--cache-config-file=cache-local.xml" })
@BeforeStartDistribution(EnableCachingStatistics.class)
@RawDistOnly(reason = "No support mounting files to containers. Testing raw dist is enough.")
void testExposeCachingMetrics() {
when().get("/metrics").then()
.statusCode(200)
.body(containsString("vendor_cache_manager_keycloak_cache_"));
}
@Test
@Launch({ "start-dev", "--metrics-enabled=true" })
void testMetricsEndpointDoesNotEnableHealth() {
when().get("/health").then() when().get("/health").then()
.statusCode(404); .statusCode(404);
} }
@Test
@Launch({ "start-dev", "--metrics-enabled=true", "--cache-metrics-histograms-enabled=true" })
void testMetricsEndpointWithCacheMetricsHistograms() {
when().get("/metrics").then()
.statusCode(200)
.body(containsString("vendor_statistics_miss_times_seconds_bucket"));
}
@Test @Test
void testUsingRelativePath(KeycloakDistribution distribution) { void testUsingRelativePath(KeycloakDistribution distribution) {
for (String relativePath : List.of("/auth", "/auth/", "auth")) { for (String relativePath : List.of("/auth", "/auth/", "auth")) {
@ -113,10 +104,4 @@ public class MetricsDistTest {
} }
} }
public static class EnableCachingStatistics implements Consumer<KeycloakDistribution> {
@Override
public void accept(KeycloakDistribution dist) {
dist.copyOrReplaceFileFromClasspath("/cache-local.xml", Paths.get("conf", "cache-local.xml"));
}
}
} }

View file

@ -1,87 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2019 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.
-->
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:11.0 http://www.infinispan.org/schemas/infinispan-config-11.0.xsd"
xmlns="urn:infinispan:config:11.0">
<cache-container name="keycloak" statistics="true">
<local-cache name="default">
<transaction transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup"/>
</local-cache>
<local-cache name="realms">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<local-cache name="users">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<local-cache name="sessions">
<expiration lifespan="-1"/>
</local-cache>
<local-cache name="authenticationSessions">
<expiration lifespan="-1"/>
</local-cache>
<local-cache name="offlineSessions">
<expiration lifespan="-1"/>
</local-cache>
<local-cache name="clientSessions">
<expiration lifespan="-1"/>
</local-cache>
<local-cache name="offlineClientSessions">
<expiration lifespan="-1"/>
</local-cache>
<local-cache name="loginFailures">
<expiration lifespan="-1"/>
</local-cache>
<local-cache name="authorization">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<local-cache name="work">
<expiration lifespan="-1"/>
</local-cache>
<local-cache name="keys">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<expiration max-idle="3600000"/>
<memory max-count="1000"/>
</local-cache>
<local-cache name="actionTokens">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<expiration max-idle="-1" lifespan="-1" interval="300000"/>
<memory max-count="-1"/>
</local-cache>
</cache-container>
</infinispan>

View file

@ -39,6 +39,9 @@ Cache:
'cache-mtls-truststore.p12' under conf/ directory. 'cache-mtls-truststore.p12' under conf/ directory.
--cache-embedded-mtls-trust-store-password <password> --cache-embedded-mtls-trust-store-password <password>
The password to access the Truststore. The password to access the Truststore.
--cache-metrics-histograms-enabled <true|false>
Enable histograms for metrics for the embedded caches. Default: false.
Available only when metrics are enabled.
--cache-remote-host <hostname> --cache-remote-host <hostname>
The hostname of the remote server for the remote store configuration. It The hostname of the remote server for the remote store configuration. It
replaces the 'host' attribute of 'remote-server' tag of the configuration replaces the 'host' attribute of 'remote-server' tag of the configuration

View file

@ -40,6 +40,9 @@ Cache:
'cache-mtls-truststore.p12' under conf/ directory. 'cache-mtls-truststore.p12' under conf/ directory.
--cache-embedded-mtls-trust-store-password <password> --cache-embedded-mtls-trust-store-password <password>
The password to access the Truststore. The password to access the Truststore.
--cache-metrics-histograms-enabled <true|false>
Enable histograms for metrics for the embedded caches. Default: false.
Available only when metrics are enabled.
--cache-remote-host <hostname> --cache-remote-host <hostname>
The hostname of the remote server for the remote store configuration. It The hostname of the remote server for the remote store configuration. It
replaces the 'host' attribute of 'remote-server' tag of the configuration replaces the 'host' attribute of 'remote-server' tag of the configuration

View file

@ -32,6 +32,9 @@ Cache:
'cache-mtls-truststore.p12' under conf/ directory. 'cache-mtls-truststore.p12' under conf/ directory.
--cache-embedded-mtls-trust-store-password <password> --cache-embedded-mtls-trust-store-password <password>
The password to access the Truststore. The password to access the Truststore.
--cache-metrics-histograms-enabled <true|false>
Enable histograms for metrics for the embedded caches. Default: false.
Available only when metrics are enabled.
--cache-remote-host <hostname> --cache-remote-host <hostname>
The hostname of the remote server for the remote store configuration. It The hostname of the remote server for the remote store configuration. It
replaces the 'host' attribute of 'remote-server' tag of the configuration replaces the 'host' attribute of 'remote-server' tag of the configuration