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:
Björn Eickvonder 2025-07-16 17:46:46 +02:00 committed by GitHub
parent 180745b65f
commit d62d5030fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 693 additions and 34 deletions

View File

@ -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>.
*/

View File

@ -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].

View File

@ -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.

View File

@ -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();
}

View File

@ -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.

View File

@ -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) {

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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());

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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);
}

View File

@ -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> {
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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
}
}

View File

@ -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();
}
}

View File

@ -104,3 +104,4 @@ org.keycloak.health.LoadBalancerCheckSpi
org.keycloak.cookie.CookieSpi
org.keycloak.organization.OrganizationSpi
org.keycloak.securityprofile.SecurityProfileSpi
org.keycloak.logging.MappedDiagnosticContextSpi

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1 @@
org.keycloak.services.logging.DefaultMappedDiagnosticContextProviderFactory