bin/kc.[sh|bat] start --log="<handler1>,<handler2>"
Logging is a key mechanism for understanding and operating Keycloak. It should help you to monitor Keycloak’s health, debug issues, and maintain an audit trail of important events.
You can configure logging for the root log level or for more specific categories such as org.hibernate or org.keycloak.
It is also possible to tailor log levels for each particular log handler.
In Keycloak, logging goes beyond setting log levels — you can direct output to different handlers, use asynchronous logging for performance, capture HTTP access logs, and more. These features make it possible to adapt logging to your operational needs and integrate with observability platforms.
Keycloak uses the JBoss Logging framework under the hood.
Console  | 
File  | 
Syslog  | 
To enable log handlers, enter the following command:
bin/kc.[sh|bat] start --log="<handler1>,<handler2>"
For more details on how to configure specific log handlers, see:
The following table defines the available log levels.
| Level | Description | 
|---|---|
FATAL  | 
Critical failures with complete inability to serve any kind of request.  | 
ERROR  | 
A significant error or problem leading to the inability to process requests.  | 
WARN  | 
A non-critical error or problem that might not require immediate correction.  | 
INFO  | 
Keycloak lifecycle events or important information. Low frequency.  | 
DEBUG  | 
More detailed information for debugging purposes, such as database logs. Higher frequency.  | 
TRACE  | 
Most detailed debugging information. Very high frequency.  | 
ALL  | 
Special level for all log messages.  | 
OFF  | 
Special level to turn logging off entirely (not recommended).  | 
When no log level configuration exists for a more specific category logger, the enclosing category is used instead. When there is no enclosing category, the root logger level is used.
To set the root log level, enter the following command:
bin/kc.[sh|bat] start --log-level=<root-level>
Use these guidelines for this command:
For <root-level>, supply a level defined in the preceding table.
The log level is case-insensitive. For example, you could either use DEBUG or debug.
If you were to accidentally set the log level twice, the last occurrence in the list becomes the log level. For example, if you included the syntax --log-level="info,…,DEBUG,…", the root logger would be DEBUG.
You can set different log levels for specific areas in Keycloak. Use this command to provide a comma-separated list of categories for which you want a different log level:
bin/kc.[sh|bat] start --log-level="<root-level>,<org.category1>:<org.category1-level>"
A configuration that applies to a category also applies to its sub-categories unless you include a more specific matching sub-category.
bin/kc.[sh|bat] start --log-level="INFO,org.hibernate:debug,org.hibernate.hql.internal.ast:info"
This example sets the following log levels:
Root log level for all loggers is set to INFO.
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.
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.
If you start the server as:
bin/kc.[sh|bat] start --log-level="INFO,org.hibernate:debug"
you can then set an environmental variable KC_LOG_LEVEL_ORG_KEYCLOAK=trace to change the log level for the org.keycloak category.
The log-level-<category> options take precedence over log-level. This allows you to override what was set in the log-level option.
For instance if you set KC_LOG_LEVEL_ORG_HIBERNATE=trace for the CLI example above, the  org.hibernate category will use the trace level instead of debug.
Bear in mind that when using the environmental variables, the category name must be in uppercase and the dots must be replaced with underscores. When using other config sources, the category name must be specified "as is", for example:
bin/kc.[sh|bat] start --log-level="INFO,org.hibernate:debug" --log-level-org.keycloak=trace
The log-level property specifies the global root log level and levels for selected categories.
However, a more fine-grained approach for log levels is necessary to comply with the modern application requirements.
To set log levels for particular handlers, properties in format log-<handler>-level (where <handler> is available log handler) were introduced.
It means properties for log level settings look like this:
log-console-level - Console log handler
log-file-level - File log handler
log-syslog-level - Syslog log handler
The log-<handler>-level properties are available only when the particular log handlers are enabled.
More information in log handlers settings below.
 | 
Only log levels specified in Log levels section are accepted, and must be in lowercase. There is no support for specifying particular categories for log handlers yet.
It is necessary to understand that setting the log levels for each particular handler does not override the root level specified in the log-level property.
Log handlers respect the root log level, which represents the maximal verbosity for the whole logging system.
It means individual log handlers can be configured to be less verbose than the root logger, but not more.
Specifically, when an arbitrary log level is defined for the handler, it does not mean the log records with the log level will be present in the output.
In that case, the root log-level must also be assessed.
Log handler levels provide the restriction for the root log level, and the default log level for log handlers is all - without any restriction.
debug for file handler, but info for console handler:bin/kc.[sh|bat] start --log=console,file --log-level=debug --log-console-level=info
The root log level is set to debug, so every log handler inherits the value - so does the file log handler.
To hide debug records in the console, we need to set the minimal (least severe) level to info for the console handler.
warn for all handlers, but debug for file handler:bin/kc.[sh|bat] start --log=console,file,syslog --log-level=debug --log-console-level=warn --log-syslog-level=warn
The root level must be set to the most verbose required level (debug in this case), and other log handlers must be amended accordingly.
info for all handlers, but debug+org.keycloak.events:trace for Syslog handler:bin/kc.[sh|bat] start --log=console,file,syslog --log-level=debug,org.keycloak.events:trace, --log-syslog-level=trace --log-console-level=info --log-file-level=info
In order to see the org.keycloak.events:trace, the trace level must be set for the Syslog handler.
| 
 Mapped Diagnostic Context (MDC) information in logs is Preview and is not fully supported. This feature is disabled by default. To enable start the server with   | 
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-enabled to enable it.
bin/kc.[sh|bat] start --features=log-mdc --log-mdc-enabled=true
2025-06-20 14:13:01,772 {kc.clientId=security-admin-console, kc.realmName=master} INFO ...
Specify which keys to be added by setting the configuration option log-mdc-keys.
Every log handler provides the ability to have structured log output in JSON format.
It can be enabled by properties in the format log-<handler>-output=json (where <handler> is a log handler).
If you need a different format of the produced JSON, you can leverage the following JSON output formats:
default (default)
ecs
The ecs value refers to the ECS (Elastic Common Schema).
ECS is an open-source, community-driven specification that defines a common set of fields to be used with Elastic solutions. The ECS specification is being converged with OpenTelemetry Semantic Conventions with the goal of creating a single standard maintained by OpenTelemetry.
In order to change the JSON output format, properties in the format log-<handler>-json-format (where <handler> is a log handler) were introduced:
log-console-json-format - Console log handler
log-file-json-format - File log handler
log-syslog-json-format - Syslog log handler
If you want to have JSON logs in ECS (Elastic Common Schema) format for the console log handler, you can enter the following command:
bin/kc.[sh|bat] start --log-console-output=json --log-console-json-format=ecs
{"@timestamp":"2025-02-03T14:53:22.539484211+01:00","event.sequence":9608,"log.logger":"io.quarkus","log.level":"INFO","message":"Keycloak 999.0.0-SNAPSHOT on JVM (powered by Quarkus 3.17.8) started in 4.615s. Listening on: http://0.0.0.0:8080","process.thread.name":"main","process.thread.id":1,"mdc":{},"ndc":"","host.hostname":"host-name","process.name":"/usr/lib/jvm/jdk-21.0.3+9/bin/java","process.pid":77561,"data_stream.type":"logs","ecs.version":"1.12.2","service.environment":"prod","service.name":"Keycloak","service.version":"999.0.0-SNAPSHOT"}
Keycloak supports asynchronous logging, which might be useful for deployments requiring high throughput and low latency. Asynchronous logging uses a separate thread to take care of processing all log records. The logging handlers are invoked in exactly the same way as with synchronous logging, only done in separate threads. You can enable asynchronous logging for all Keycloak log handlers. A dedicated thread will be created for every log handler with enabled asynchronous logging.
The underlying mechanism for asynchronous logging uses a queue for processing log records. Every new log record is added to the queue and then published to the particular log handler with enabled asynchronous logging. Every log handler has a different queue.
If the queue is already full, it blocks the main thread and waits for free space in the queue.
You need lower latencies for incoming requests
You need higher throughput
You have small worker thread pool and want to offload logging to separate threads
You want to reduce the impact of I/O-heavy log handlers
You are logging to remote destinations (e.g., network syslog servers) and want to avoid blocking worker threads
| Be aware that enabling asynchronous logging might bring some additional memory overhead due to the additional separate thread and the inner queue. In that case, it is not recommended to use it for resource-constrained environments. Additionally, unexpected server shutdowns create a risk of losing log records. | 
You can enable asynchronous logging globally for all log handlers by using log-async property as follows:
bin/kc.[sh|bat] start --log-async=true
Or you can enable the asynchronous logging for every specific handler by using properties in the format log-<handler>-async (where <handler> is a log handler).
If the property for a specific handler is not set, the value from the parent log-async property is used.
You can use these properties as follows:
bin/kc.[sh|bat] start --log-console-async=true --log-file-async=true --log-syslog-async=true
log-console-async - Console log handler
log-file-async - File log handler
log-syslog-async - Syslog log handler
You can change the size of the queue used for the asynchronous logging. The default size is 512 log records in the queue.
You can change the queue length as follows:
bin/kc.[sh|bat] start --log-console-async-queue-length=512 --log-file-async-queue-length=512 --log-syslog-async-queue-length=512
These properties are available only when asynchronous logging is enabled for these specific log handlers.
Keycloak supports HTTP access logging to record details of incoming HTTP requests. While access logs are often used for debugging and traffic analysis, they are also important for security auditing and compliance monitoring, helping administrators track access patterns, identify suspicious activity, and maintain audit trails.
These logs are written at the INFO level, so make sure your logging configuration includes this level — either globally (e.g. log-level=info) or specifically for the access log category (e.g. log-level=org.keycloak.http.access-log:info).
When HTTP access logs are enabled, they are shown by default, as INFO level is the default log level for Keycloak.
You can enable HTTP access logging by using http-access-log-enabled property as follows:
bin/kc.[sh|bat] start --http-access-log-enabled=true
You can change format/pattern of the access log records by using http-access-log-pattern property as follows:
bin/kc.[sh|bat] start --http-access-log-pattern=combined
Predefined named patterns:
common (default) - prints basic information about the request
combined - prints basic information about the request + information about referer and user agent
long - prints comprehensive information about the request with all its headers
You can even specify your own pattern with your required data to be logged, such as:
bin/kc.[sh|bat] start --http-access-log-pattern='%A %{METHOD} %{REQUEST_URL} %{i,User-Agent}'
Consult the Quarkus documentation for the full list of variables that can be used.
It is possible to exclude specific URL paths from the HTTP access logging, so they will not be recorded.
You can use regular expressions to exclude them, such as:
bin/kc.[sh|bat] start --http-access-log-exclude='/realms/my-internal-realm/.*'
In this case, all calls to the /realms/my-internal-realm/ and subsequent paths will be excluded from the HTTP Access log.
| Type or Values | Default | |
|---|---|---|
 
  | 
  | 
  | 
 
  | 
  | 
  | 
 
  | 
List  | 
  | 
 
  | 
  | 
| Type or Values | Default | |
|---|---|---|
 
 Available only when Console log handler is activated  | 
  | 
  | 
 
 Available only when Console log handler is activated and asynchronous logging is enabled  | 
Integer  | 
  | 
 
 Available only when Console log handler is activated  | 
  | 
|
 
 Available only when Console log handler is activated  | 
String  | 
  | 
 
 Available only when Console log handler and MDC logging are activated  | 
  | 
  | 
 
 Available only when Console log handler and Tracing is activated  | 
  | 
  | 
 
 Available only when Console log handler is activated and output is set to 'json'  | 
  | 
  | 
 
 Available only when Console log handler is activated  | 
  | 
  | 
 
 Available only when Console log handler is activated  | 
  | 
  | 
| Type or Values | Default | |
|---|---|---|
 
 Available only when File log handler is activated  | 
File  | 
  | 
 
 Available only when File log handler is activated  | 
  | 
  | 
 
 Available only when File log handler is activated and asynchronous logging is enabled  | 
Integer  | 
  | 
 
 Available only when File log handler is activated  | 
String  | 
  | 
 
 Available only when File log handler and MDC logging are activated  | 
  | 
  | 
 
 Available only when File log handler and Tracing is activated  | 
  | 
  | 
 
 Available only when File log handler is activated and output is set to 'json'  | 
  | 
  | 
 
 Available only when File log handler is activated  | 
  | 
  | 
 
 Available only when File log handler is activated  | 
  | 
  | 
| Type or Values | Default | |
|---|---|---|
 
 Available only when Syslog is activated  | 
String  | 
  | 
 
 Available only when Syslog is activated  | 
  | 
  | 
 
 Available only when Syslog is activated and asynchronous logging is enabled  | 
Integer  | 
  | 
 
 Available only when Syslog is activated  | 
  | 
  | 
 
 Available only when Syslog is activated  | 
String  | 
  | 
 
 Available only when Syslog is activated  | 
String  | 
  | 
 
 Available only when Syslog handler and MDC logging are activated  | 
  | 
  | 
 
 Available only when Syslog handler and Tracing is activated  | 
  | 
  | 
 
 Available only when Syslog is activated and output is set to 'json'  | 
  | 
  | 
 
 Available only when Syslog is activated  | 
  | 
  | 
 
 Available only when Syslog is activated  | 
String  | 
|
 
 Available only when Syslog is activated  | 
  | 
  | 
 
 Available only when Syslog is activated  | 
  | 
  | 
 
 Available only when Syslog is activated  | 
  | 
  | 
| Type or Values | Default | |
|---|---|---|
 
  | 
  | 
  | 
 
 Available only when HTTP Access log is enabled  | 
String  | 
|
 
 Available only when HTTP Access log is enabled  | 
  | 
  | 
| Type or Values | Default | |
|---|---|---|
 
 Available only when log-mdc preview feature is enabled  | 
  | 
  | 
 
 Available only when MDC logging is enabled  | 
  | 
  |