mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
Adds log context information for MDC for realm, users, etc.
Closes #39812 Signed-off-by: Björn Eickvonder <b.eicki@gmx.net> Signed-off-by: Alexander Schwartz <aschwart@redhat.com> Signed-off-by: Bjoern Eickvonder <bjoern.eickvonder@inform-software.com> Co-authored-by: Pedro Ruivo <pruivo@users.noreply.github.com> Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
parent
180745b65f
commit
d62d5030fe
@ -135,6 +135,8 @@ public class Profile {
|
||||
ROLLING_UPDATES_V1("Rolling Updates", Type.DEFAULT, 1),
|
||||
ROLLING_UPDATES_V2("Rolling Updates for patch releases", Type.PREVIEW, 2),
|
||||
|
||||
LOG_MDC("Mapped Diagnostic Context (MDC) information in logs", Type.PREVIEW),
|
||||
|
||||
/**
|
||||
* @see <a href="https://github.com/keycloak/keycloak/issues/37967">Deprecate for removal the Instagram social broker</a>.
|
||||
*/
|
||||
|
||||
@ -5,4 +5,11 @@ Read on to learn more about each new feature, and https://www.keycloak.org/docs/
|
||||
|
||||
= Option to force management interface to use HTTP.
|
||||
|
||||
There's a new option `http-management-scheme` that may be set to `http` to force the management interface to use HTTP rather than inheriting the HTTPS settings of the main interface.
|
||||
There's a new option `http-management-scheme` that may be set to `http` to force the management interface to use HTTP rather than inheriting the HTTPS settings of the main interface.
|
||||
|
||||
= Additional context information for log messages (preview)
|
||||
|
||||
You can now add context information to each log message like the realm or the client that initiated the request.
|
||||
This helps you to track down a warning or error message in the log to a specific caller or environment
|
||||
|
||||
For more details on this opt-in feature, see the https://www.keycloak.org/server/logging[Logging guide].
|
||||
|
||||
@ -68,6 +68,32 @@ This example sets the following log levels:
|
||||
* The hibernate log level in general is set to debug.
|
||||
* To keep SQL abstract syntax trees from creating verbose log output, the specific subcategory `org.hibernate.hql.internal.ast` is set to info. As a result, the SQL abstract syntax trees are omitted instead of appearing at the `debug` level.
|
||||
|
||||
=== Adding context for log messages
|
||||
|
||||
:tech_feature_name: Log messages with Mapped Diagnostic Context (MDC)
|
||||
:tech_feature_id: log-mdc
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
{tech_feature_name} is
|
||||
*Preview*
|
||||
and is not fully supported. This feature is disabled by default.
|
||||
====
|
||||
|
||||
You can enable additional context information for each log line like the current realm and client that is executing the request.
|
||||
|
||||
Use the option `log-mdc-enable` to enable it.
|
||||
|
||||
.Example configuration
|
||||
<@kc.start parameters="--features=log-mdc --log-mdc-enable=true"/>
|
||||
|
||||
.Example output
|
||||
----
|
||||
2025-06-20 14:13:01,772 {kc.clientId=security-admin-console, kc.realm=master} INFO ...
|
||||
----
|
||||
|
||||
Specify which keys to be added by setting the configuration option `log-mdc-keys`.
|
||||
|
||||
==== Configuring levels as individual options
|
||||
When configuring category-specific log levels, you can also set the log levels as individual `log-level-<category>` options instead of using the `log-level` option for that.
|
||||
This is useful when you want to set the log levels for selected categories without overwriting the previously set `log-level` option.
|
||||
|
||||
@ -20,10 +20,9 @@ public class LoggingOptions {
|
||||
public static final String DEFAULT_LOG_PATH = "data" + File.separator + "log" + File.separator + DEFAULT_LOG_FILENAME;
|
||||
|
||||
// Log format + tracing
|
||||
private static final Function<String, String> DEFAULT_LOG_FORMAT_FUNC = (additionalFields) ->
|
||||
public static final Function<String, String> DEFAULT_LOG_FORMAT_FUNC = (additionalFields) ->
|
||||
"%d{yyyy-MM-dd HH:mm:ss,SSS} " + additionalFields + "%-5p [%c] (%t) %s%e%n";
|
||||
public static final String DEFAULT_LOG_FORMAT = DEFAULT_LOG_FORMAT_FUNC.apply("");
|
||||
public static final String DEFAULT_LOG_TRACING_FORMAT = DEFAULT_LOG_FORMAT_FUNC.apply("traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} ");
|
||||
|
||||
public enum Handler {
|
||||
console,
|
||||
@ -125,6 +124,12 @@ public class LoggingOptions {
|
||||
.defaultValue(true)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> LOG_CONSOLE_INCLUDE_MDC = new OptionBuilder<>("log-console-include-mdc", Boolean.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.description(format("Include mdc information in the console log. If the '%s' option is specified, this option has no effect.", LOG_CONSOLE_FORMAT.getKey()))
|
||||
.defaultValue(true)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> LOG_CONSOLE_COLOR = new OptionBuilder<>("log-console-color", Boolean.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.description("Enable or disable colors when logging to console.")
|
||||
@ -188,6 +193,12 @@ public class LoggingOptions {
|
||||
.defaultValue(true)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> LOG_FILE_INCLUDE_MDC = new OptionBuilder<>("log-file-include-mdc", Boolean.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.description(format("Include MDC information in the file log. If the '%s' option is specified, this option has no effect.", LOG_FILE_FORMAT.getKey()))
|
||||
.defaultValue(true)
|
||||
.build();
|
||||
|
||||
public static final Option<Output> LOG_FILE_OUTPUT = new OptionBuilder<>("log-file-output", Output.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.defaultValue(DEFAULT_CONSOLE_OUTPUT)
|
||||
@ -273,6 +284,12 @@ public class LoggingOptions {
|
||||
.defaultValue(true)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> LOG_SYSLOG_INCLUDE_MDC = new OptionBuilder<>("log-syslog-include-mdc", Boolean.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.description(format("Include MDC information in the Syslog. If the '%s' option is specified, this option has no effect.", LOG_SYSLOG_FORMAT.getKey()))
|
||||
.defaultValue(true)
|
||||
.build();
|
||||
|
||||
public static final Option<Output> LOG_SYSLOG_OUTPUT = new OptionBuilder<>("log-syslog-output", Output.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.defaultValue(DEFAULT_SYSLOG_OUTPUT)
|
||||
@ -301,4 +318,19 @@ public class LoggingOptions {
|
||||
.defaultValue(512)
|
||||
.description("The queue length to use before flushing writing when logging to Syslog.")
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> LOG_MDC_ENABLED = new OptionBuilder<>("log-mdc-enabled", Boolean.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.defaultValue(false)
|
||||
.buildTime(true)
|
||||
.description("Indicates whether to add information about the realm and other information to the mapped diagnostic context. All elements will be prefixed with 'kc.'")
|
||||
.build();
|
||||
|
||||
public static final Option<List<String>> LOG_MDC_KEYS = OptionBuilder.listOptionBuilder("log-mdc-keys", String.class)
|
||||
.category(OptionCategory.LOGGING)
|
||||
.expectedValues(List.of("realm", "clientId", "userId", "ipAddress", "org"))
|
||||
.defaultValue(List.of("realm", "org", "clientId"))
|
||||
.description("Defines which information should be added to the mapped diagnostic context as a comma-separated list.")
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@ -81,6 +81,7 @@ import org.keycloak.common.util.StreamUtil;
|
||||
import org.keycloak.config.DatabaseOptions;
|
||||
import org.keycloak.config.HealthOptions;
|
||||
import org.keycloak.config.HttpOptions;
|
||||
import org.keycloak.config.LoggingOptions;
|
||||
import org.keycloak.config.ManagementOptions;
|
||||
import org.keycloak.config.MetricsOptions;
|
||||
import org.keycloak.config.SecurityOptions;
|
||||
@ -111,6 +112,7 @@ import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
import org.keycloak.quarkus.runtime.integration.resteasy.KeycloakHandlerChainCustomizer;
|
||||
import org.keycloak.quarkus.runtime.integration.resteasy.KeycloakTracingCustomizer;
|
||||
import org.keycloak.quarkus.runtime.logging.ClearMappedDiagnosticContextFilter;
|
||||
import org.keycloak.quarkus.runtime.services.health.KeycloakReadyHealthCheck;
|
||||
import org.keycloak.quarkus.runtime.storage.database.jpa.NamedJpaConnectionProviderFactory;
|
||||
import org.keycloak.quarkus.runtime.themes.FlatClasspathThemeResourceProviderFactory;
|
||||
@ -647,6 +649,16 @@ class KeycloakProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void disableMdcContextFilter(BuildProducer<BuildTimeConditionBuildItem> removeBeans, CombinedIndexBuildItem index) {
|
||||
if (!Configuration.isTrue(LoggingOptions.LOG_MDC_ENABLED)) {
|
||||
// disables the filter
|
||||
ClassInfo disabledBean = index.getIndex()
|
||||
.getClassByName(DotName.createSimple(ClearMappedDiagnosticContextFilter.class.getName()));
|
||||
removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean.asClass(), false));
|
||||
}
|
||||
}
|
||||
|
||||
// We can't use quarkus.datasource.health.enabled=false as that would remove the DataSourceHealthCheck from CDI and
|
||||
// it can't be instantiated via constructor as it now includes some field injection points. So we just make it a regular
|
||||
// bean without the @Readiness annotation so it won't be used as a health check on it's own.
|
||||
|
||||
@ -24,6 +24,7 @@ import java.util.stream.Stream;
|
||||
|
||||
import io.quarkus.runtime.configuration.MemorySizeConverter;
|
||||
import org.jboss.logmanager.LogContext;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.config.LoggingOptions;
|
||||
import org.keycloak.config.Option;
|
||||
import org.keycloak.quarkus.runtime.Messages;
|
||||
@ -69,7 +70,7 @@ public final class LoggingPropertyMappers {
|
||||
.isEnabled(LoggingPropertyMappers::isConsoleEnabled, CONSOLE_ENABLED_MSG)
|
||||
.to("quarkus.log.console.format")
|
||||
.paramLabel("format")
|
||||
.transformer((value, ctx) -> addTracingInfo(value, LoggingOptions.LOG_CONSOLE_INCLUDE_TRACE))
|
||||
.transformer((value, ctx) -> addTracingAndMdcInfo(value, LoggingOptions.LOG_CONSOLE_INCLUDE_TRACE, LoggingOptions.LOG_CONSOLE_INCLUDE_MDC))
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_CONSOLE_JSON_FORMAT)
|
||||
.isEnabled(LoggingPropertyMappers::isConsoleJsonEnabled, "%s and output is set to 'json'".formatted(CONSOLE_ENABLED_MSG))
|
||||
@ -80,6 +81,10 @@ public final class LoggingPropertyMappers {
|
||||
.isEnabled(() -> LoggingPropertyMappers.isConsoleEnabled() && TracingPropertyMappers.isTracingEnabled(),
|
||||
"Console log handler and Tracing is activated")
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_CONSOLE_INCLUDE_MDC)
|
||||
.isEnabled(() -> LoggingPropertyMappers.isConsoleEnabled() && isMdcActive(),
|
||||
"Console log handler and MDC logging are activated")
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_CONSOLE_COLOR)
|
||||
.isEnabled(LoggingPropertyMappers::isConsoleEnabled, CONSOLE_ENABLED_MSG)
|
||||
.to("quarkus.log.console.color")
|
||||
@ -120,7 +125,7 @@ public final class LoggingPropertyMappers {
|
||||
.isEnabled(LoggingPropertyMappers::isFileEnabled, FILE_ENABLED_MSG)
|
||||
.to("quarkus.log.file.format")
|
||||
.paramLabel("format")
|
||||
.transformer((value, ctx) -> addTracingInfo(value, LoggingOptions.LOG_FILE_INCLUDE_TRACE))
|
||||
.transformer((value, ctx) -> addTracingAndMdcInfo(value, LoggingOptions.LOG_FILE_INCLUDE_TRACE, LoggingOptions.LOG_FILE_INCLUDE_MDC))
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_FILE_JSON_FORMAT)
|
||||
.isEnabled(LoggingPropertyMappers::isFileJsonEnabled, FILE_ENABLED_MSG + " and output is set to 'json'")
|
||||
@ -131,6 +136,10 @@ public final class LoggingPropertyMappers {
|
||||
.isEnabled(() -> LoggingPropertyMappers.isFileEnabled() && TracingPropertyMappers.isTracingEnabled(),
|
||||
"File log handler and Tracing is activated")
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_FILE_INCLUDE_MDC)
|
||||
.isEnabled(() -> LoggingPropertyMappers.isFileEnabled() && isMdcActive(),
|
||||
"File log handler and MDC logging are activated")
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_FILE_OUTPUT)
|
||||
.isEnabled(LoggingPropertyMappers::isFileEnabled, FILE_ENABLED_MSG)
|
||||
.to("quarkus.log.file.json.enabled")
|
||||
@ -204,7 +213,7 @@ public final class LoggingPropertyMappers {
|
||||
.isEnabled(LoggingPropertyMappers::isSyslogEnabled, SYSLOG_ENABLED_MSG)
|
||||
.to("quarkus.log.syslog.format")
|
||||
.paramLabel("format")
|
||||
.transformer((value, ctx) -> addTracingInfo(value, LoggingOptions.LOG_SYSLOG_INCLUDE_TRACE))
|
||||
.transformer((value, ctx) -> addTracingAndMdcInfo(value, LoggingOptions.LOG_SYSLOG_INCLUDE_TRACE, LoggingOptions.LOG_SYSLOG_INCLUDE_MDC))
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_SYSLOG_JSON_FORMAT)
|
||||
.isEnabled(LoggingPropertyMappers::isSyslogJsonEnabled, SYSLOG_ENABLED_MSG + " and output is set to 'json'")
|
||||
@ -215,6 +224,10 @@ public final class LoggingPropertyMappers {
|
||||
.isEnabled(() -> LoggingPropertyMappers.isSyslogEnabled() && TracingPropertyMappers.isTracingEnabled(),
|
||||
"Syslog handler and Tracing is activated")
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_SYSLOG_INCLUDE_MDC)
|
||||
.isEnabled(() -> LoggingPropertyMappers.isSyslogEnabled() && isMdcActive(),
|
||||
"Syslog handler and MDC logging are activated")
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_SYSLOG_OUTPUT)
|
||||
.isEnabled(LoggingPropertyMappers::isSyslogEnabled, SYSLOG_ENABLED_MSG)
|
||||
.to("quarkus.log.syslog.json.enabled")
|
||||
@ -238,6 +251,17 @@ public final class LoggingPropertyMappers {
|
||||
.to("quarkus.log.syslog.async.queue-length")
|
||||
.paramLabel("queue-length")
|
||||
.build(),
|
||||
// MDC
|
||||
fromOption(LoggingOptions.LOG_MDC_ENABLED)
|
||||
.to("kc.spi-mapped-diagnostic-context--default--enabled")
|
||||
.isEnabled(LoggingPropertyMappers::isMdcAvailable, "log-mdc preview feature is enabled")
|
||||
.build(),
|
||||
fromOption(LoggingOptions.LOG_MDC_KEYS)
|
||||
.isEnabled(LoggingPropertyMappers::isMdcActive, "MDC logging is enabled")
|
||||
.to("kc.spi-mapped-diagnostic-context--default--mdc-keys")
|
||||
.paramLabel("keys")
|
||||
.build(),
|
||||
|
||||
};
|
||||
|
||||
return defaultMappers;
|
||||
@ -275,6 +299,14 @@ public final class LoggingPropertyMappers {
|
||||
return isHandlerAsyncEnabled(LoggingOptions.Handler.syslog);
|
||||
}
|
||||
|
||||
private static boolean isMdcAvailable() {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.LOG_MDC);
|
||||
}
|
||||
|
||||
public static boolean isMdcActive() {
|
||||
return Configuration.isTrue(LoggingOptions.LOG_MDC_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean isSyslogJsonEnabled() {
|
||||
return isSyslogEnabled() && isTrue("quarkus.log.syslog.json.enabled");
|
||||
}
|
||||
@ -380,16 +412,20 @@ public final class LoggingPropertyMappers {
|
||||
/**
|
||||
* Add tracing info to the log if the format is not explicitly set, and tracing and {@code includeTraceOption} options are enabled
|
||||
*/
|
||||
private static String addTracingInfo(String value, Option<Boolean> includeTraceOption) {
|
||||
var isTracingEnabled = TracingPropertyMappers.isTracingEnabled();
|
||||
var includeTrace = isTrue(includeTraceOption);
|
||||
var isChangedLogFormat = !DEFAULT_LOG_FORMAT.equals(value);
|
||||
|
||||
if (!isTracingEnabled || !includeTrace || isChangedLogFormat) {
|
||||
private static String addTracingAndMdcInfo(String value, Option<Boolean> includeTraceOption, Option<Boolean> includeMdcOption) {
|
||||
if (!DEFAULT_LOG_FORMAT.equals(value)) {
|
||||
return value;
|
||||
}
|
||||
var isTracingEnabled = TracingPropertyMappers.isTracingEnabled();
|
||||
var includeTrace = isTrue(includeTraceOption);
|
||||
var includeMdc = isTrue(includeMdcOption);
|
||||
|
||||
return LoggingOptions.DEFAULT_LOG_TRACING_FORMAT;
|
||||
if (isMdcActive() && includeMdc) {
|
||||
return LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("%X "); }
|
||||
else if (isTracingEnabled && includeTrace) {
|
||||
return LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} ");
|
||||
}
|
||||
return LoggingOptions.DEFAULT_LOG_FORMAT;
|
||||
}
|
||||
|
||||
private static String upperCase(String value, ConfigSourceInterceptorContext context) {
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package org.keycloak.quarkus.runtime.logging;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerResponseContext;
|
||||
import jakarta.ws.rs.container.ContainerResponseFilter;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
import org.keycloak.logging.MappedDiagnosticContextUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Response filter that clears custom properties from MDC.
|
||||
*
|
||||
* @author <a href="mailto:b.eicki@gmx.net">Björn Eickvonder</a>
|
||||
*/
|
||||
@Provider
|
||||
@Priority(0)
|
||||
public class ClearMappedDiagnosticContextFilter implements ContainerResponseFilter {
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext,
|
||||
ContainerResponseContext responseContext) throws IOException {
|
||||
MappedDiagnosticContextUtil.clearMdc();
|
||||
}
|
||||
}
|
||||
@ -147,42 +147,61 @@ public class TracingConfigurationTest extends AbstractConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void consoleLogTraceOn() {
|
||||
assertLogFormat(LoggingOptions.Handler.console, true, LoggingOptions.DEFAULT_LOG_TRACING_FORMAT);
|
||||
assertLogFormat(LoggingOptions.Handler.console, true, false, LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consoleLogMdcOn() {
|
||||
assertLogFormat(LoggingOptions.Handler.console, true, true, LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("%X "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consoleLogTraceOff() {
|
||||
assertLogFormat(LoggingOptions.Handler.console, false, LoggingOptions.DEFAULT_LOG_FORMAT);
|
||||
assertLogFormat(LoggingOptions.Handler.console, false, false, LoggingOptions.DEFAULT_LOG_FORMAT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileLogTraceOn() {
|
||||
assertLogFormat(LoggingOptions.Handler.file, true, LoggingOptions.DEFAULT_LOG_TRACING_FORMAT);
|
||||
assertLogFormat(LoggingOptions.Handler.file, true, false, LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileLogMdcOn() {
|
||||
assertLogFormat(LoggingOptions.Handler.file, true, true, LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("%X "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileLogTraceOff() {
|
||||
assertLogFormat(LoggingOptions.Handler.file, false, LoggingOptions.DEFAULT_LOG_FORMAT);
|
||||
assertLogFormat(LoggingOptions.Handler.file, false, false, LoggingOptions.DEFAULT_LOG_FORMAT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syslogLogTraceOn() {
|
||||
assertLogFormat(LoggingOptions.Handler.syslog, true, LoggingOptions.DEFAULT_LOG_TRACING_FORMAT);
|
||||
assertLogFormat(LoggingOptions.Handler.syslog, true, false, LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syslogLogMdcOn() {
|
||||
assertLogFormat(LoggingOptions.Handler.syslog, true, true, LoggingOptions.DEFAULT_LOG_FORMAT_FUNC.apply("%X "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syslogLogTraceOff() {
|
||||
assertLogFormat(LoggingOptions.Handler.syslog, false, LoggingOptions.DEFAULT_LOG_FORMAT);
|
||||
assertLogFormat(LoggingOptions.Handler.syslog, false, false, LoggingOptions.DEFAULT_LOG_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert log format for individual log handlers with different `includeTrace` option.
|
||||
* It also checks the log format is unchanged despite the `includeTrace` option, when explicitly specified.
|
||||
*/
|
||||
protected void assertLogFormat(LoggingOptions.Handler loggerType, boolean includeTrace, String expectedFormat) {
|
||||
protected void assertLogFormat(LoggingOptions.Handler loggerType, boolean includeTrace, boolean includeMdc, String expectedFormat) {
|
||||
var envVars = new HashMap<String, String>();
|
||||
envVars.put("KC_TRACING_ENABLED", "true");
|
||||
if (includeMdc) {
|
||||
envVars.put("KC_LOG_MDC_ENABLED", "true");
|
||||
}
|
||||
envVars.put("KC_LOG_" + loggerType.name().toUpperCase() + "_INCLUDE_TRACE", Boolean.toString(includeTrace));
|
||||
envVars.put("KC_LOG_" + loggerType.name().toUpperCase() + "_INCLUDE_MDC", Boolean.toString(includeMdc));
|
||||
|
||||
putEnvVars(envVars);
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.keycloak.it.cli.dist;
|
||||
|
||||
import static io.restassured.RestAssured.when;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
@ -31,7 +32,6 @@ import java.nio.charset.Charset;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.config.LoggingOptions;
|
||||
@ -42,13 +42,12 @@ import org.keycloak.it.junit5.extension.RawDistOnly;
|
||||
import org.keycloak.it.utils.KeycloakDistribution;
|
||||
import org.keycloak.it.utils.RawDistRootPath;
|
||||
import org.keycloak.it.utils.RawKeycloakDistribution;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
|
||||
|
||||
import io.quarkus.deployment.util.FileUtil;
|
||||
import io.quarkus.test.junit.main.Launch;
|
||||
|
||||
@DistributionTest
|
||||
@DistributionTest(keepAlive = true)
|
||||
@RawDistOnly(reason = "Too verbose for docker and enough to check raw dist")
|
||||
@Tag(DistributionTest.SLOW)
|
||||
public class LoggingDistTest {
|
||||
@ -266,6 +265,16 @@ public class LoggingDistTest {
|
||||
cliResult.assertStartedDevMode();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Launch({ "start-dev", "--features=log-mdc","--log-mdc-enabled=true", "--log-level=org.keycloak:debug" })
|
||||
void testLogMdcShowingInTheLogs(CLIResult cliResult) {
|
||||
|
||||
when().get("http://127.0.0.1:8080/realms/master/.well-known/openid-configuration").then()
|
||||
.statusCode(200);
|
||||
assertTrue(cliResult.getOutput().contains("{kc.realm=master} DEBUG [org.keycloak."));
|
||||
cliResult.assertStartedDevMode();
|
||||
}
|
||||
|
||||
protected static String readDefaultFileLog(RawDistRootPath path) {
|
||||
Path logFilePath = Paths.get(path.getDistRootPath() + File.separator + LoggingOptions.DEFAULT_LOG_PATH);
|
||||
File logFile = new File(logFilePath.toString());
|
||||
|
||||
@ -214,6 +214,10 @@ Logging:
|
||||
The format of unstructured console log entries. If the format has spaces in
|
||||
it, escape the value using "<format>". Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Console log handler is activated.
|
||||
--log-console-include-mdc <true|false>
|
||||
Include mdc information in the console log. If the 'log-console-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
Console log handler and MDC logging are activated.
|
||||
--log-console-include-trace <true|false>
|
||||
Include tracing information in the console log. If the 'log-console-format'
|
||||
option is specified, this option has no effect. Default: true. Available
|
||||
@ -247,6 +251,10 @@ Logging:
|
||||
Set a format specific to file log entries. Default: %d{yyyy-MM-dd HH:mm:ss,
|
||||
SSS} %-5p [%c] (%t) %s%e%n. Available only when File log handler is
|
||||
activated.
|
||||
--log-file-include-mdc <true|false>
|
||||
Include MDC information in the file log. If the 'log-file-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
File log handler and MDC logging are activated.
|
||||
--log-file-include-trace <true|false>
|
||||
Include tracing information in the file log. If the 'log-file-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -274,6 +282,15 @@ Logging:
|
||||
The log level of a category. Takes precedence over the 'log-level' option.
|
||||
Possible values are (case insensitive): off, fatal, error, warn, info,
|
||||
debug, trace, all.
|
||||
--log-mdc-enabled <true|false>
|
||||
Indicates whether to add information about the realm and other information to
|
||||
the mapped diagnostic context. All elements will be prefixed with 'kc.'
|
||||
Default: false. Available only when log-mdc preview feature is enabled.
|
||||
--log-mdc-keys <keys>
|
||||
Defines which information should be added to the mapped diagnostic context as
|
||||
a comma-separated list. Possible values are: realm, clientId, userId,
|
||||
ipAddress, org. Default: realm,org,clientId. Available only when MDC logging
|
||||
is enabled.
|
||||
--log-syslog-app-name <name>
|
||||
Set the app name used when formatting the message in RFC5424 format. Default:
|
||||
keycloak. Available only when Syslog is activated.
|
||||
@ -297,6 +314,10 @@ Logging:
|
||||
--log-syslog-format <format>
|
||||
Set a format specific to Syslog entries. Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Syslog is activated.
|
||||
--log-syslog-include-mdc <true|false>
|
||||
Include MDC information in the Syslog. If the 'log-syslog-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
Syslog handler and MDC logging are activated.
|
||||
--log-syslog-include-trace <true|false>
|
||||
Include tracing information in the Syslog. If the 'log-syslog-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -420,4 +441,4 @@ Bootstrap Admin:
|
||||
--bootstrap-admin-username <username>
|
||||
Temporary bootstrap admin username. Used only when the master realm is
|
||||
created. Available only when bootstrap admin password is set. Default:
|
||||
temp-admin.
|
||||
temp-admin.
|
||||
|
||||
@ -214,6 +214,10 @@ Logging:
|
||||
The format of unstructured console log entries. If the format has spaces in
|
||||
it, escape the value using "<format>". Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Console log handler is activated.
|
||||
--log-console-include-mdc <true|false>
|
||||
Include mdc information in the console log. If the 'log-console-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
Console log handler and MDC logging are activated.
|
||||
--log-console-include-trace <true|false>
|
||||
Include tracing information in the console log. If the 'log-console-format'
|
||||
option is specified, this option has no effect. Default: true. Available
|
||||
@ -247,6 +251,10 @@ Logging:
|
||||
Set a format specific to file log entries. Default: %d{yyyy-MM-dd HH:mm:ss,
|
||||
SSS} %-5p [%c] (%t) %s%e%n. Available only when File log handler is
|
||||
activated.
|
||||
--log-file-include-mdc <true|false>
|
||||
Include MDC information in the file log. If the 'log-file-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
File log handler and MDC logging are activated.
|
||||
--log-file-include-trace <true|false>
|
||||
Include tracing information in the file log. If the 'log-file-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -274,6 +282,15 @@ Logging:
|
||||
The log level of a category. Takes precedence over the 'log-level' option.
|
||||
Possible values are (case insensitive): off, fatal, error, warn, info,
|
||||
debug, trace, all.
|
||||
--log-mdc-enabled <true|false>
|
||||
Indicates whether to add information about the realm and other information to
|
||||
the mapped diagnostic context. All elements will be prefixed with 'kc.'
|
||||
Default: false. Available only when log-mdc preview feature is enabled.
|
||||
--log-mdc-keys <keys>
|
||||
Defines which information should be added to the mapped diagnostic context as
|
||||
a comma-separated list. Possible values are: realm, clientId, userId,
|
||||
ipAddress, org. Default: realm,org,clientId. Available only when MDC logging
|
||||
is enabled.
|
||||
--log-syslog-app-name <name>
|
||||
Set the app name used when formatting the message in RFC5424 format. Default:
|
||||
keycloak. Available only when Syslog is activated.
|
||||
@ -297,6 +314,10 @@ Logging:
|
||||
--log-syslog-format <format>
|
||||
Set a format specific to Syslog entries. Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Syslog is activated.
|
||||
--log-syslog-include-mdc <true|false>
|
||||
Include MDC information in the Syslog. If the 'log-syslog-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
Syslog handler and MDC logging are activated.
|
||||
--log-syslog-include-trace <true|false>
|
||||
Include tracing information in the Syslog. If the 'log-syslog-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -414,4 +435,4 @@ Bootstrap Admin:
|
||||
--bootstrap-admin-username <username>
|
||||
Temporary bootstrap admin username. Used only when the master realm is
|
||||
created. Available only when bootstrap admin password is set. Default:
|
||||
temp-admin.
|
||||
temp-admin.
|
||||
|
||||
@ -445,6 +445,10 @@ Logging:
|
||||
The format of unstructured console log entries. If the format has spaces in
|
||||
it, escape the value using "<format>". Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Console log handler is activated.
|
||||
--log-console-include-mdc <true|false>
|
||||
Include mdc information in the console log. If the 'log-console-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
Console log handler and MDC logging are activated.
|
||||
--log-console-include-trace <true|false>
|
||||
Include tracing information in the console log. If the 'log-console-format'
|
||||
option is specified, this option has no effect. Default: true. Available
|
||||
@ -478,6 +482,10 @@ Logging:
|
||||
Set a format specific to file log entries. Default: %d{yyyy-MM-dd HH:mm:ss,
|
||||
SSS} %-5p [%c] (%t) %s%e%n. Available only when File log handler is
|
||||
activated.
|
||||
--log-file-include-mdc <true|false>
|
||||
Include MDC information in the file log. If the 'log-file-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
File log handler and MDC logging are activated.
|
||||
--log-file-include-trace <true|false>
|
||||
Include tracing information in the file log. If the 'log-file-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -505,6 +513,15 @@ Logging:
|
||||
The log level of a category. Takes precedence over the 'log-level' option.
|
||||
Possible values are (case insensitive): off, fatal, error, warn, info,
|
||||
debug, trace, all.
|
||||
--log-mdc-enabled <true|false>
|
||||
Indicates whether to add information about the realm and other information to
|
||||
the mapped diagnostic context. All elements will be prefixed with 'kc.'
|
||||
Default: false. Available only when log-mdc preview feature is enabled.
|
||||
--log-mdc-keys <keys>
|
||||
Defines which information should be added to the mapped diagnostic context as
|
||||
a comma-separated list. Possible values are: realm, clientId, userId,
|
||||
ipAddress, org. Default: realm,org,clientId. Available only when MDC logging
|
||||
is enabled.
|
||||
--log-syslog-app-name <name>
|
||||
Set the app name used when formatting the message in RFC5424 format. Default:
|
||||
keycloak. Available only when Syslog is activated.
|
||||
@ -528,6 +545,10 @@ Logging:
|
||||
--log-syslog-format <format>
|
||||
Set a format specific to Syslog entries. Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Syslog is activated.
|
||||
--log-syslog-include-mdc <true|false>
|
||||
Include MDC information in the Syslog. If the 'log-syslog-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
Syslog handler and MDC logging are activated.
|
||||
--log-syslog-include-trace <true|false>
|
||||
Include tracing information in the Syslog. If the 'log-syslog-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -651,4 +672,4 @@ Bootstrap Admin:
|
||||
Do NOT start the server using this command when deploying to production.
|
||||
|
||||
Use 'kc.sh start-dev --help-all' to list all available options, including build
|
||||
options.
|
||||
options.
|
||||
|
||||
@ -446,6 +446,10 @@ Logging:
|
||||
The format of unstructured console log entries. If the format has spaces in
|
||||
it, escape the value using "<format>". Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Console log handler is activated.
|
||||
--log-console-include-mdc <true|false>
|
||||
Include mdc information in the console log. If the 'log-console-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
Console log handler and MDC logging are activated.
|
||||
--log-console-include-trace <true|false>
|
||||
Include tracing information in the console log. If the 'log-console-format'
|
||||
option is specified, this option has no effect. Default: true. Available
|
||||
@ -479,6 +483,10 @@ Logging:
|
||||
Set a format specific to file log entries. Default: %d{yyyy-MM-dd HH:mm:ss,
|
||||
SSS} %-5p [%c] (%t) %s%e%n. Available only when File log handler is
|
||||
activated.
|
||||
--log-file-include-mdc <true|false>
|
||||
Include MDC information in the file log. If the 'log-file-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
File log handler and MDC logging are activated.
|
||||
--log-file-include-trace <true|false>
|
||||
Include tracing information in the file log. If the 'log-file-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -506,6 +514,15 @@ Logging:
|
||||
The log level of a category. Takes precedence over the 'log-level' option.
|
||||
Possible values are (case insensitive): off, fatal, error, warn, info,
|
||||
debug, trace, all.
|
||||
--log-mdc-enabled <true|false>
|
||||
Indicates whether to add information about the realm and other information to
|
||||
the mapped diagnostic context. All elements will be prefixed with 'kc.'
|
||||
Default: false. Available only when log-mdc preview feature is enabled.
|
||||
--log-mdc-keys <keys>
|
||||
Defines which information should be added to the mapped diagnostic context as
|
||||
a comma-separated list. Possible values are: realm, clientId, userId,
|
||||
ipAddress, org. Default: realm,org,clientId. Available only when MDC logging
|
||||
is enabled.
|
||||
--log-syslog-app-name <name>
|
||||
Set the app name used when formatting the message in RFC5424 format. Default:
|
||||
keycloak. Available only when Syslog is activated.
|
||||
@ -529,6 +546,10 @@ Logging:
|
||||
--log-syslog-format <format>
|
||||
Set a format specific to Syslog entries. Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Syslog is activated.
|
||||
--log-syslog-include-mdc <true|false>
|
||||
Include MDC information in the Syslog. If the 'log-syslog-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
Syslog handler and MDC logging are activated.
|
||||
--log-syslog-include-trace <true|false>
|
||||
Include tracing information in the Syslog. If the 'log-syslog-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -656,4 +677,4 @@ By default, this command tries to update the server configuration by running a
|
||||
$ kc.sh start '--optimized'
|
||||
|
||||
By doing that, the server should start faster based on any previous
|
||||
configuration you have set when manually running the 'build' command.
|
||||
configuration you have set when manually running the 'build' command.
|
||||
|
||||
@ -384,6 +384,10 @@ Logging:
|
||||
The format of unstructured console log entries. If the format has spaces in
|
||||
it, escape the value using "<format>". Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Console log handler is activated.
|
||||
--log-console-include-mdc <true|false>
|
||||
Include mdc information in the console log. If the 'log-console-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
Console log handler and MDC logging are activated.
|
||||
--log-console-include-trace <true|false>
|
||||
Include tracing information in the console log. If the 'log-console-format'
|
||||
option is specified, this option has no effect. Default: true. Available
|
||||
@ -417,6 +421,10 @@ Logging:
|
||||
Set a format specific to file log entries. Default: %d{yyyy-MM-dd HH:mm:ss,
|
||||
SSS} %-5p [%c] (%t) %s%e%n. Available only when File log handler is
|
||||
activated.
|
||||
--log-file-include-mdc <true|false>
|
||||
Include MDC information in the file log. If the 'log-file-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
File log handler and MDC logging are activated.
|
||||
--log-file-include-trace <true|false>
|
||||
Include tracing information in the file log. If the 'log-file-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -444,6 +452,11 @@ Logging:
|
||||
The log level of a category. Takes precedence over the 'log-level' option.
|
||||
Possible values are (case insensitive): off, fatal, error, warn, info,
|
||||
debug, trace, all.
|
||||
--log-mdc-keys <keys>
|
||||
Defines which information should be added to the mapped diagnostic context as
|
||||
a comma-separated list. Possible values are: realm, clientId, userId,
|
||||
ipAddress, org. Default: realm,org,clientId. Available only when MDC logging
|
||||
is enabled.
|
||||
--log-syslog-app-name <name>
|
||||
Set the app name used when formatting the message in RFC5424 format. Default:
|
||||
keycloak. Available only when Syslog is activated.
|
||||
@ -467,6 +480,10 @@ Logging:
|
||||
--log-syslog-format <format>
|
||||
Set a format specific to Syslog entries. Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Syslog is activated.
|
||||
--log-syslog-include-mdc <true|false>
|
||||
Include MDC information in the Syslog. If the 'log-syslog-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
Syslog handler and MDC logging are activated.
|
||||
--log-syslog-include-trace <true|false>
|
||||
Include tracing information in the Syslog. If the 'log-syslog-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -571,4 +588,4 @@ By default, this command tries to update the server configuration by running a
|
||||
$ kc.sh start '--optimized'
|
||||
|
||||
By doing that, the server should start faster based on any previous
|
||||
configuration you have set when manually running the 'build' command.
|
||||
configuration you have set when manually running the 'build' command.
|
||||
|
||||
@ -445,6 +445,10 @@ Logging:
|
||||
The format of unstructured console log entries. If the format has spaces in
|
||||
it, escape the value using "<format>". Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Console log handler is activated.
|
||||
--log-console-include-mdc <true|false>
|
||||
Include mdc information in the console log. If the 'log-console-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
Console log handler and MDC logging are activated.
|
||||
--log-console-include-trace <true|false>
|
||||
Include tracing information in the console log. If the 'log-console-format'
|
||||
option is specified, this option has no effect. Default: true. Available
|
||||
@ -478,6 +482,10 @@ Logging:
|
||||
Set a format specific to file log entries. Default: %d{yyyy-MM-dd HH:mm:ss,
|
||||
SSS} %-5p [%c] (%t) %s%e%n. Available only when File log handler is
|
||||
activated.
|
||||
--log-file-include-mdc <true|false>
|
||||
Include MDC information in the file log. If the 'log-file-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
File log handler and MDC logging are activated.
|
||||
--log-file-include-trace <true|false>
|
||||
Include tracing information in the file log. If the 'log-file-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -505,6 +513,15 @@ Logging:
|
||||
The log level of a category. Takes precedence over the 'log-level' option.
|
||||
Possible values are (case insensitive): off, fatal, error, warn, info,
|
||||
debug, trace, all.
|
||||
--log-mdc-enabled <true|false>
|
||||
Indicates whether to add information about the realm and other information to
|
||||
the mapped diagnostic context. All elements will be prefixed with 'kc.'
|
||||
Default: false. Available only when log-mdc preview feature is enabled.
|
||||
--log-mdc-keys <keys>
|
||||
Defines which information should be added to the mapped diagnostic context as
|
||||
a comma-separated list. Possible values are: realm, clientId, userId,
|
||||
ipAddress, org. Default: realm,org,clientId. Available only when MDC logging
|
||||
is enabled.
|
||||
--log-syslog-app-name <name>
|
||||
Set the app name used when formatting the message in RFC5424 format. Default:
|
||||
keycloak. Available only when Syslog is activated.
|
||||
@ -528,6 +545,10 @@ Logging:
|
||||
--log-syslog-format <format>
|
||||
Set a format specific to Syslog entries. Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Syslog is activated.
|
||||
--log-syslog-include-mdc <true|false>
|
||||
Include MDC information in the Syslog. If the 'log-syslog-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
Syslog handler and MDC logging are activated.
|
||||
--log-syslog-include-trace <true|false>
|
||||
Include tracing information in the Syslog. If the 'log-syslog-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -646,4 +667,4 @@ Bootstrap Admin:
|
||||
--bootstrap-admin-username <username>
|
||||
Temporary bootstrap admin username. Used only when the master realm is
|
||||
created. Available only when bootstrap admin password is set. Default:
|
||||
temp-admin.
|
||||
temp-admin.
|
||||
|
||||
@ -443,6 +443,10 @@ Logging:
|
||||
The format of unstructured console log entries. If the format has spaces in
|
||||
it, escape the value using "<format>". Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Console log handler is activated.
|
||||
--log-console-include-mdc <true|false>
|
||||
Include mdc information in the console log. If the 'log-console-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
Console log handler and MDC logging are activated.
|
||||
--log-console-include-trace <true|false>
|
||||
Include tracing information in the console log. If the 'log-console-format'
|
||||
option is specified, this option has no effect. Default: true. Available
|
||||
@ -476,6 +480,10 @@ Logging:
|
||||
Set a format specific to file log entries. Default: %d{yyyy-MM-dd HH:mm:ss,
|
||||
SSS} %-5p [%c] (%t) %s%e%n. Available only when File log handler is
|
||||
activated.
|
||||
--log-file-include-mdc <true|false>
|
||||
Include MDC information in the file log. If the 'log-file-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
File log handler and MDC logging are activated.
|
||||
--log-file-include-trace <true|false>
|
||||
Include tracing information in the file log. If the 'log-file-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -503,6 +511,15 @@ Logging:
|
||||
The log level of a category. Takes precedence over the 'log-level' option.
|
||||
Possible values are (case insensitive): off, fatal, error, warn, info,
|
||||
debug, trace, all.
|
||||
--log-mdc-enabled <true|false>
|
||||
Indicates whether to add information about the realm and other information to
|
||||
the mapped diagnostic context. All elements will be prefixed with 'kc.'
|
||||
Default: false. Available only when log-mdc preview feature is enabled.
|
||||
--log-mdc-keys <keys>
|
||||
Defines which information should be added to the mapped diagnostic context as
|
||||
a comma-separated list. Possible values are: realm, clientId, userId,
|
||||
ipAddress, org. Default: realm,org,clientId. Available only when MDC logging
|
||||
is enabled.
|
||||
--log-syslog-app-name <name>
|
||||
Set the app name used when formatting the message in RFC5424 format. Default:
|
||||
keycloak. Available only when Syslog is activated.
|
||||
@ -526,6 +543,10 @@ Logging:
|
||||
--log-syslog-format <format>
|
||||
Set a format specific to Syslog entries. Default: %d{yyyy-MM-dd HH:mm:ss,SSS} %
|
||||
-5p [%c] (%t) %s%e%n. Available only when Syslog is activated.
|
||||
--log-syslog-include-mdc <true|false>
|
||||
Include MDC information in the Syslog. If the 'log-syslog-format' option is
|
||||
specified, this option has no effect. Default: true. Available only when
|
||||
Syslog handler and MDC logging are activated.
|
||||
--log-syslog-include-trace <true|false>
|
||||
Include tracing information in the Syslog. If the 'log-syslog-format' option
|
||||
is specified, this option has no effect. Default: true. Available only when
|
||||
@ -644,4 +665,4 @@ Bootstrap Admin:
|
||||
--bootstrap-admin-username <username>
|
||||
Temporary bootstrap admin username. Used only when the master realm is
|
||||
created. Available only when bootstrap admin password is set. Default:
|
||||
temp-admin.
|
||||
temp-admin.
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
package org.keycloak.logging;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakContext;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
|
||||
/**
|
||||
* Provider interface for updating the Mapped Diagnostic Context (MDC) with key/value pairs based on the current keycloak context.
|
||||
* All keys in the MDC will be prefixed with "kc." to avoid conflicts.
|
||||
*
|
||||
* @author <a href="mailto:b.eicki@gmx.net">Björn Eickvonder</a>
|
||||
*/
|
||||
public interface MappedDiagnosticContextProvider extends Provider {
|
||||
|
||||
String MDC_PREFIX = "kc.";
|
||||
|
||||
/**
|
||||
* Updates the Mapped Diagnostic Context (MDC) with key/value pairs based on the current Keycloak context.
|
||||
* This method is called when a Keycloak Session is set and when the authentication session property of the
|
||||
* Keycloak context is updated.
|
||||
*
|
||||
* @param keycloakContext the current Keycloak context, never null
|
||||
* @param session the authentication session
|
||||
*/
|
||||
void update(KeycloakContext keycloakContext, AuthenticationSessionModel session);
|
||||
|
||||
/**
|
||||
* Updates the Mapped Diagnostic Context (MDC) with key/value pairs based on the current Keycloak context.
|
||||
* This method is called when a Keycloak Session is set and when the realm property of the Keycloak context
|
||||
* is updated.
|
||||
*
|
||||
* @param keycloakContext the current Keycloak context, never null
|
||||
* @param realm the realm
|
||||
*/
|
||||
void update(KeycloakContext keycloakContext, RealmModel realm);
|
||||
|
||||
/**
|
||||
* Updates the Mapped Diagnostic Context (MDC) with key/value pairs based on the current Keycloak context.
|
||||
* This method is called when a Keycloak Session is set and when the client property of the Keycloak context
|
||||
* is updated.
|
||||
*
|
||||
* @param keycloakContext the current Keycloak context, never null
|
||||
* @param client the client
|
||||
*/
|
||||
void update(KeycloakContext keycloakContext, ClientModel client);
|
||||
|
||||
/**
|
||||
* Updates the Mapped Diagnostic Context (MDC) with key/value pairs based on the current Keycloak context.
|
||||
* This method is called when a Keycloak Session is set and when the organization property of the Keycloak context
|
||||
* is updated.
|
||||
*
|
||||
* @param keycloakContext the current Keycloak context, never null
|
||||
* @param organization the organization
|
||||
*/
|
||||
void update(KeycloakContext keycloakContext, OrganizationModel organization);
|
||||
|
||||
/**
|
||||
* Updates the Mapped Diagnostic Context (MDC) with key/value pairs based on the current Keycloak context.
|
||||
* This method is called when a Keycloak Session is set and when the user session property of the Keycloak context
|
||||
* is updated.
|
||||
*
|
||||
* @param keycloakContext the current Keycloak context, never null
|
||||
* @param userSession the user session
|
||||
*/
|
||||
void update(KeycloakContext keycloakContext, UserSessionModel userSession);
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package org.keycloak.logging;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:b.eicki@gmx.net">Björn Eickvonder</a>
|
||||
*/
|
||||
public interface MappedDiagnosticContextProviderFactory extends ProviderFactory<MappedDiagnosticContextProvider> {
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package org.keycloak.logging;
|
||||
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* This SPI is used to define the MDC keys and values that should be set for each request.
|
||||
*
|
||||
* @author <a href="mailto:b.eicki@gmx.net">Björn Eickvonder</a>
|
||||
*/
|
||||
public class MappedDiagnosticContextSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "mappedDiagnosticContext";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MappedDiagnosticContextProvider> getProviderClass() {
|
||||
return MappedDiagnosticContextProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MappedDiagnosticContextProviderFactory> getProviderFactoryClass() {
|
||||
return MappedDiagnosticContextProviderFactory.class;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package org.keycloak.logging;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.MDC;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public final class MappedDiagnosticContextUtil {
|
||||
|
||||
private static final Logger log = Logger.getLogger(MappedDiagnosticContextUtil.class);
|
||||
private static final MappedDiagnosticContextProvider NOOP_PROVIDER = new NoopMappedDiagnosticContextProvider();
|
||||
private static volatile Collection<String> keysToClear = Collections.emptySet();
|
||||
|
||||
public static MappedDiagnosticContextProvider getMappedDiagnosticContextProvider(KeycloakSession session) {
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.LOG_MDC)) {
|
||||
return NOOP_PROVIDER;
|
||||
}
|
||||
if (session == null) {
|
||||
log.warn("Cannot obtain session from thread to init MappedDiagnosticContextProvider. Return Noop provider.");
|
||||
return NOOP_PROVIDER;
|
||||
}
|
||||
MappedDiagnosticContextProvider provider = session.getProvider(MappedDiagnosticContextProvider.class);
|
||||
if (provider == null) {
|
||||
return NOOP_PROVIDER;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static void setKeysToClear(Collection<String> keys) {
|
||||
// As the MDC.getMap() clones the context and is possibly expensive, we instead iterate over the list of all known keys
|
||||
keysToClear = keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the Mapped Diagnostic Context (MDC), but only clears the key/value pairs that were set by this provider.
|
||||
*/
|
||||
public static void clearMdc() {
|
||||
for (String key : keysToClear) {
|
||||
MDC.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package org.keycloak.logging;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakContext;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
|
||||
public class NoopMappedDiagnosticContextProvider implements MappedDiagnosticContextProvider {
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, AuthenticationSessionModel session) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, RealmModel realm) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, ClientModel client) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, OrganizationModel organization) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, UserSessionModel userSession) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@
|
||||
package org.keycloak.services.scheduled;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.logging.MappedDiagnosticContextUtil;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
@ -76,6 +77,7 @@ public class ScheduledTaskRunner implements TaskRunner {
|
||||
logger.errorf(t, "Failed to run scheduled task %s", task.getTaskName());
|
||||
} finally {
|
||||
tracing.close();
|
||||
MappedDiagnosticContextUtil.clearMdc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -104,3 +104,4 @@ org.keycloak.health.LoadBalancerCheckSpi
|
||||
org.keycloak.cookie.CookieSpi
|
||||
org.keycloak.organization.OrganizationSpi
|
||||
org.keycloak.securityprofile.SecurityProfileSpi
|
||||
org.keycloak.logging.MappedDiagnosticContextSpi
|
||||
|
||||
@ -24,6 +24,8 @@ import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.http.HttpRequest;
|
||||
import org.keycloak.http.HttpResponse;
|
||||
import org.keycloak.locale.LocaleSelectorProvider;
|
||||
import org.keycloak.logging.MappedDiagnosticContextProvider;
|
||||
import org.keycloak.logging.MappedDiagnosticContextUtil;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
@ -118,7 +120,8 @@ public abstract class DefaultKeycloakContext implements KeycloakContext {
|
||||
public void setRealm(RealmModel realm) {
|
||||
this.realm = realm;
|
||||
this.uriInfo = null;
|
||||
trace(this.realm);
|
||||
trace(realm);
|
||||
mdc().update(this, realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,7 +137,8 @@ public abstract class DefaultKeycloakContext implements KeycloakContext {
|
||||
@Override
|
||||
public void setClient(ClientModel client) {
|
||||
this.client = client;
|
||||
trace(this.client);
|
||||
trace(client);
|
||||
mdc().update(this, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -145,6 +149,7 @@ public abstract class DefaultKeycloakContext implements KeycloakContext {
|
||||
@Override
|
||||
public void setOrganization(OrganizationModel organization) {
|
||||
this.organization = organization;
|
||||
mdc().update(this, organization);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -174,7 +179,8 @@ public abstract class DefaultKeycloakContext implements KeycloakContext {
|
||||
@Override
|
||||
public void setAuthenticationSession(AuthenticationSessionModel authenticationSession) {
|
||||
this.authenticationSession = authenticationSession;
|
||||
trace(this.authenticationSession);
|
||||
trace(authenticationSession);
|
||||
mdc().update(this, authenticationSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -230,7 +236,8 @@ public abstract class DefaultKeycloakContext implements KeycloakContext {
|
||||
@Override
|
||||
public void setUserSession(UserSessionModel userSession) {
|
||||
this.userSession = userSession;
|
||||
trace(this.userSession);
|
||||
trace(userSession);
|
||||
mdc().update(this, userSession);
|
||||
}
|
||||
|
||||
// Tracing
|
||||
@ -309,4 +316,8 @@ public abstract class DefaultKeycloakContext implements KeycloakContext {
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private MappedDiagnosticContextProvider mdc() {
|
||||
return MappedDiagnosticContextUtil.getMappedDiagnosticContextProvider(session);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
package org.keycloak.services.logging;
|
||||
|
||||
import org.jboss.logging.MDC;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.logging.MappedDiagnosticContextProvider;
|
||||
import org.keycloak.logging.MappedDiagnosticContextProviderFactory;
|
||||
import org.keycloak.logging.MappedDiagnosticContextUtil;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The default provider factory can be configured via --spi-mapped-diagnostic-context-default-mdc-keys to define mdc
|
||||
* keys to add as a comma-separated list. By default, "realm", "clientId", "userId", "ipAddress" and "org" are supported by the default provider implementation.
|
||||
* If you need further keys, you need to extend the provider.
|
||||
*
|
||||
* @author <a href="mailto:b.eicki@gmx.net">Björn Eickvonder</a>
|
||||
*/
|
||||
public class DefaultMappedDiagnosticContextProviderFactory implements MappedDiagnosticContextProviderFactory, MappedDiagnosticContextProvider, EnvironmentDependentProviderFactory {
|
||||
|
||||
public static final String MDC_KEY_REALM = MDC_PREFIX + "realm";
|
||||
public static final String MDC_KEY_CLIENT_ID = MDC_PREFIX + "clientId";
|
||||
public static final String MDC_KEY_USER_ID = MDC_PREFIX + "userId";
|
||||
public static final String MDC_KEY_IP_ADDRESS = MDC_PREFIX + "ipAddress";
|
||||
public static final String MDC_KEY_ORGANIZATION = MDC_PREFIX + "org";
|
||||
|
||||
public static final String MDC_KEYS = "mdcKeys";
|
||||
private Set<String> mdcKeys;
|
||||
|
||||
@Override
|
||||
public MappedDiagnosticContextProvider create(KeycloakSession session) {
|
||||
// not using session, thus implementing MappedDiagnosticContextProvider here and handling it as singleton is fine
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
this.mdcKeys = Arrays.stream(Objects.requireNonNullElse(config.getArray(MDC_KEYS), new String[] {})).map(s -> MDC_PREFIX + s).collect(Collectors.toSet());
|
||||
MappedDiagnosticContextUtil.setKeysToClear(mdcKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigMetadata() {
|
||||
ProviderConfigurationBuilder builder = ProviderConfigurationBuilder.create();
|
||||
|
||||
builder.property()
|
||||
.name(MDC_KEYS)
|
||||
.type("string")
|
||||
.helpText("Comma-separated list of MDC keys to add to the Mapped Diagnostic Context.")
|
||||
.options(Stream.of(MDC_KEY_REALM, MDC_KEY_CLIENT_ID, MDC_KEY_USER_ID, MDC_KEY_IP_ADDRESS, MDC_KEY_ORGANIZATION).map(s -> s.substring(MDC_PREFIX.length())).collect(Collectors.toList()))
|
||||
.add();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(Config.Scope config) {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.LOG_MDC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, AuthenticationSessionModel session) {
|
||||
// nothing of interest here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, RealmModel realm) {
|
||||
if (mdcKeys.contains(MDC_KEY_REALM)) {
|
||||
putMdc(MDC_KEY_REALM, realm != null ? realm.getName() : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, ClientModel client) {
|
||||
if (mdcKeys.contains(MDC_KEY_CLIENT_ID)) {
|
||||
putMdc(MDC_KEY_CLIENT_ID, client != null ? client.getClientId() : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, OrganizationModel organization) {
|
||||
if (mdcKeys.contains(MDC_KEY_ORGANIZATION)) {
|
||||
putMdc(MDC_KEY_ORGANIZATION, organization != null ? organization.getAlias() : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(KeycloakContext keycloakContext, UserSessionModel userSession) {
|
||||
if (mdcKeys.contains(MDC_KEY_USER_ID)) {
|
||||
putMdc(MDC_KEY_USER_ID, userSession != null && userSession.getUser() != null ? userSession.getUser().getId() : null);
|
||||
}
|
||||
if (mdcKeys.contains(MDC_KEY_IP_ADDRESS)) {
|
||||
putMdc(MDC_KEY_IP_ADDRESS, userSession != null ? userSession.getIpAddress() : null);
|
||||
}
|
||||
}
|
||||
|
||||
protected void putMdc(String key, String value) {
|
||||
if (value != null) {
|
||||
MDC.put(key, value);
|
||||
} else {
|
||||
MDC.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
org.keycloak.services.logging.DefaultMappedDiagnosticContextProviderFactory
|
||||
Loading…
x
Reference in New Issue
Block a user