Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion docs/guides/server/logging.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<#import "/templates/guide.adoc" as tmpl>
<#import "/templates/kc.adoc" as kc>
<#import "/templates/links.adoc" as links>
<#import "/templates/profile.adoc" as profile>

<@tmpl.guide
title="Configuring logging"
Expand All @@ -12,7 +13,9 @@ Keycloak uses the JBoss Logging framework. The following is a high-level overvie
* root
** console (_default_)
** file
<@profile.ifCommunity>
** GELF
</@profile.ifCommunity>

== Logging configuration
Logging is done on a per-category basis in Keycloak. You can configure logging for the root log level or for more specific categories such as `org.hibernate` or `org.keycloak`. This {section} describes how to configure logging.
Expand Down Expand Up @@ -69,7 +72,14 @@ To enable log handlers, enter the following command:

<@kc.start parameters="--log=\"<handler1>,<handler2>\""/>

The available handlers are `console`, `file` and `gelf`. The more specific handler configuration mentioned below will only take effect when the handler is added to this comma-separated list.
The available handlers are
<@profile.ifCommunity>
`console`, `file` and `gelf`.
</@profile.ifCommunity>
<@profile.ifProduct>
`console` and `file`.
</@profile.ifProduct>
The more specific handler configuration mentioned below will only take effect when the handler is added to this comma-separated list.

== Console log handler
The console log handler is enabled by default, providing unstructured log messages for the console.
Expand Down Expand Up @@ -178,6 +188,8 @@ To configure a different logging format for the file log handler, enter the foll

See <<Configuring the console log format>> for more information and a table of the available pattern configuration.

<@profile.ifCommunity>

== Centralized logging using GELF
Keycloak can send logs to a centralized log management system such as the following:

Expand Down Expand Up @@ -497,4 +509,6 @@ Currently, the Keycloak configuration does not support partly dynamic configurat

To add user-defined fields, you can provide these fields through a quarkus.properties file. See <@links.server id="configuration"/> and the _Using raw Quarkus properties_ section.

</@profile.ifCommunity>

</@tmpl.guide>
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.keycloak.config;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.function.Predicate;

public class LoggingOptions {

Expand All @@ -11,16 +13,27 @@ public class LoggingOptions {
public static final Output DEFAULT_CONSOLE_OUTPUT = Output.DEFAULT;
public static final String DEFAULT_LOG_FILENAME = "keycloak.log";
public static final String DEFAULT_LOG_PATH = "data" + File.separator + "log" + File.separator + DEFAULT_LOG_FILENAME;
public static final Boolean GELF_ACTIVATED = isGelfActivated();

public enum Handler {
console,
file,
gelf
}

public static List<String> getAvailableHandlerNames() {
final Predicate<Handler> checkGelf = (handler) -> GELF_ACTIVATED || !handler.equals(Handler.gelf);

return Arrays.stream(Handler.values())
.filter(checkGelf)
.map(Handler::name)
.toList();
}

public static final Option LOG = new OptionBuilder("log", List.class, Handler.class)
.category(OptionCategory.LOGGING)
.description("Enable one or more log handlers in a comma-separated list.")
.expectedValues(() -> getAvailableHandlerNames())
.defaultValue(DEFAULT_LOG_HANDLER)
.build();

Expand Down Expand Up @@ -168,4 +181,13 @@ public String toString() {
.description("Include source code location.")
.defaultValue(Boolean.TRUE)
.build();

private static boolean isGelfActivated() {
try {
Thread.currentThread().getContextClassLoader().loadClass("io.quarkus.logging.gelf.GelfConfig");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
21 changes: 17 additions & 4 deletions quarkus/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-json-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-gelf-deployment</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
Expand Down Expand Up @@ -197,4 +193,21 @@
</plugins>
</build>

<profiles>
<profile>
<id>includeGelf</id>
<activation>
<property>
<name>!product</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-gelf-deployment</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>

</project>
21 changes: 17 additions & 4 deletions quarkus/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-json</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-gelf</artifactId>
</dependency>

<!-- SmallRye -->
<dependency>
Expand Down Expand Up @@ -736,4 +732,21 @@
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>includeGelf</id>
<activation>
<property>
<name>!product</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-gelf</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package org.keycloak.quarkus.runtime.configuration.mappers;

import static java.util.Optional.of;
import static org.keycloak.config.LoggingOptions.GELF_ACTIVATED;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitializationException;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.logging.Level;
import java.util.stream.Collectors;

import org.apache.commons.lang3.ArrayUtils;
import org.jboss.logmanager.LogContext;
import org.keycloak.config.LoggingOptions;
import org.keycloak.quarkus.runtime.Messages;
Expand All @@ -24,7 +24,7 @@ public final class LoggingPropertyMappers {
private LoggingPropertyMappers(){}

public static PropertyMapper[] getMappers() {
return new PropertyMapper[] {
PropertyMapper[] defaultMappers = new PropertyMapper[]{
fromOption(LoggingOptions.LOG)
.paramLabel("<handler>")
.build(),
Expand Down Expand Up @@ -68,7 +68,14 @@ public static PropertyMapper[] getMappers() {
.to("quarkus.log.level")
.transformer(LoggingPropertyMappers::resolveLogLevel)
.paramLabel("category:level")
.build(),
.build()
};

return GELF_ACTIVATED ? ArrayUtils.addAll(defaultMappers, getGelfMappers()) : defaultMappers;
}

public static PropertyMapper[] getGelfMappers() {
return new PropertyMapper[]{
fromOption(LoggingOptions.LOG_GELF_ENABLED)
.mapFrom("log")
.to("quarkus.log.handler.gelf.enabled")
Expand Down Expand Up @@ -126,7 +133,7 @@ private static BiFunction<Optional<String>, ConfigSourceInterceptorContext, Opti
}

String[] logHandlerValues = handlers.split(",");
List<String> availableLogHandlers = Arrays.stream(LoggingOptions.Handler.values()).map(Enum::name).collect(Collectors.toList());
final List<String> availableLogHandlers = LoggingOptions.getAvailableHandlerNames();

if (!availableLogHandlers.containsAll(List.of(logHandlerValues))) {
addInitializationException(Messages.notRecognizedValueInList("log", handlers, String.join(",", availableLogHandlers)));
Expand Down
20 changes: 20 additions & 0 deletions quarkus/tests/integration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,26 @@
</plugins>
</build>
</profile>
<profile>
<id>includeGelf</id>
<activation>
<property>
<name>!product</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<includeGelf>true</includeGelf>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.it.cli.dist;

import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import org.junit.jupiter.api.Test;
import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
import org.keycloak.quarkus.runtime.cli.command.StartDev;

@DistributionTest
@RawDistOnly(reason = "Verifying the help message output doesn't need long spin-up of docker dist tests.")
public class GelfRemovedTest {

public static final String INCLUDE_GELF_PROPERTY = "includeGelf";

@Test
@Launch({StartDev.NAME, "--help-all"})
void checkGelfRemoved(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
if (Boolean.getBoolean(INCLUDE_GELF_PROPERTY)) {
cliResult.assertMessage("gelf");
} else {
cliResult.assertNoMessage("gelf");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@
package org.keycloak.it.cli.dist;

import static org.junit.Assert.assertEquals;
import static org.keycloak.it.cli.dist.GelfRemovedTest.INCLUDE_GELF_PROPERTY;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.OPTIMIZED_BUILD_OPTION_LONG;

import java.util.List;

import org.approvaltests.Approvals;
import org.approvaltests.namer.NamedEnvironment;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.OS;
import org.keycloak.it.approvaltests.KcNamerFactory;
Expand All @@ -44,6 +47,11 @@
@RawDistOnly(reason = "Verifying the help message output doesn't need long spin-up of docker dist tests.")
public class HelpCommandDistTest {

@BeforeAll
public static void assumeGelfEnabled() {
Assumptions.assumeTrue(Boolean.getBoolean(INCLUDE_GELF_PROPERTY), "Assume GELF support is given in order to simplify these test cases");
}

@Test
@Launch({})
void testDefaultToHelp(LaunchResult result) {
Expand All @@ -52,7 +60,7 @@ void testDefaultToHelp(LaunchResult result) {
}

@Test
@Launch({ "--help" })
@Launch({"--help"})
void testHelp(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
assertHelp(cliResult);
Expand Down