Support OpenTelemetry tracing

Closes #28581

Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Co-authored-by: Steven Hawkins <shawkins@redhat.com>
This commit is contained in:
Martin Bartoš 2024-08-08 15:48:29 +01:00 committed by GitHub
parent 10fae5de7a
commit 5b83a7993c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 802 additions and 9 deletions

View file

@ -40,6 +40,10 @@
<groupId>org.infinispan</groupId>
<artifactId>infinispan-commons</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
</dependencies>
</project>

View file

@ -5,8 +5,11 @@ import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import static java.lang.String.format;
public class LoggingOptions {
public static final Handler DEFAULT_LOG_HANDLER = Handler.console;
@ -17,6 +20,12 @@ public class LoggingOptions {
public static final String DEFAULT_LOG_PATH = "data" + File.separator + "log" + File.separator + DEFAULT_LOG_FILENAME;
public static final Boolean GELF_ACTIVATED = isGelfActivated();
// Log format + tracing
private 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,
file,
@ -91,7 +100,13 @@ public class LoggingOptions {
public static final Option<String> LOG_CONSOLE_FORMAT = new OptionBuilder<>("log-console-format", String.class)
.category(OptionCategory.LOGGING)
.description("The format of unstructured console log entries. If the format has spaces in it, escape the value using \"<format>\".")
.defaultValue("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n")
.defaultValue(DEFAULT_LOG_FORMAT)
.build();
public static final Option<Boolean> LOG_CONSOLE_INCLUDE_TRACE = new OptionBuilder<>("log-console-include-trace", Boolean.class)
.category(OptionCategory.LOGGING)
.description(format("Include tracing 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)
@ -120,7 +135,13 @@ public class LoggingOptions {
public static final Option<String> LOG_FILE_FORMAT = new OptionBuilder<>("log-file-format", String.class)
.category(OptionCategory.LOGGING)
.description("Set a format specific to file log entries.")
.defaultValue("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n")
.defaultValue(DEFAULT_LOG_FORMAT)
.build();
public static final Option<Boolean> LOG_FILE_INCLUDE_TRACE = new OptionBuilder<>("log-file-include-trace", Boolean.class)
.category(OptionCategory.LOGGING)
.description(format("Include tracing 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)
@ -158,7 +179,13 @@ public class LoggingOptions {
public static final Option<String> LOG_SYSLOG_FORMAT = new OptionBuilder<>("log-syslog-format", String.class)
.category(OptionCategory.LOGGING)
.description("Set a format specific to syslog entries.")
.defaultValue("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n")
.defaultValue(DEFAULT_LOG_FORMAT)
.build();
public static final Option<Boolean> LOG_SYSLOG_INCLUDE_TRACE = new OptionBuilder<>("log-syslog-include-trace", Boolean.class)
.category(OptionCategory.LOGGING)
.description(format("Include tracing 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)

View file

@ -15,6 +15,7 @@ public enum OptionCategory {
PROXY("Proxy", 90, ConfigSupportLevel.SUPPORTED),
VAULT("Vault", 100, ConfigSupportLevel.SUPPORTED),
LOGGING("Logging", 110, ConfigSupportLevel.SUPPORTED),
TRACING("Tracing", 111, ConfigSupportLevel.PREVIEW),
TRUSTSTORE("Truststore", 115, ConfigSupportLevel.SUPPORTED),
SECURITY("Security", 120, ConfigSupportLevel.SUPPORTED),
EXPORT("Export", 130, ConfigSupportLevel.SUPPORTED),

View file

@ -0,0 +1,77 @@
/*
* Copyright 2024 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.config;
import io.quarkus.opentelemetry.runtime.config.build.SamplerType;
import java.util.Arrays;
public class TracingOptions {
public static final Option<Boolean> TRACING_ENABLED = new OptionBuilder<>("tracing-enabled", Boolean.class)
.category(OptionCategory.TRACING)
.description("Enables the OpenTelemetry tracing.")
.defaultValue(Boolean.FALSE)
.buildTime(true)
.build();
public static final Option<String> TRACING_ENDPOINT = new OptionBuilder<>("tracing-endpoint", String.class)
.category(OptionCategory.TRACING)
.description("OpenTelemetry endpoint to connect to.")
.defaultValue("http://localhost:4317")
.build();
public static final Option<Boolean> TRACING_JDBC_ENABLED = new OptionBuilder<>("tracing-jdbc-enabled", Boolean.class)
.category(OptionCategory.TRACING)
.description("Enables the OpenTelemetry JDBC tracing.")
.defaultValue(true)
.buildTime(true)
.build();
public static final Option<String> TRACING_PROTOCOL = new OptionBuilder<>("tracing-protocol", String.class)
.category(OptionCategory.TRACING)
.description("OpenTelemetry protocol used for the telemetry data.")
.defaultValue("grpc")
.expectedValues("grpc", "http/protobuf")
.build();
public static final Option<String> TRACING_SAMPLER_TYPE = new OptionBuilder<>("tracing-sampler-type", String.class)
.category(OptionCategory.TRACING)
.description("OpenTelemetry sampler to use for tracing.")
.defaultValue(SamplerType.TRACE_ID_RATIO.getValue())
.expectedValues(Arrays.stream(SamplerType.values()).map(SamplerType::getValue).toList())
.buildTime(true)
.build();
public static final Option<Double> TRACING_SAMPLER_RATIO = new OptionBuilder<>("tracing-sampler-ratio", Double.class)
.category(OptionCategory.TRACING)
.description("OpenTelemetry sampler ratio. Probability that a span will be sampled. Expected double value in interval <0,1).")
.defaultValue(1.0d)
.build();
public enum TracingCompression {
gzip,
none
}
public static final Option<TracingCompression> TRACING_COMPRESSION = new OptionBuilder<>("tracing-compression", TracingCompression.class)
.category(OptionCategory.TRACING)
.description("OpenTelemetry compression method used to compress payloads. If unset, compression is disabled.")
.defaultValue(TracingCompression.none)
.build();
}

View file

@ -159,6 +159,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-json-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>

View file

@ -109,6 +109,14 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-json</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.apicatalog</groupId>

View file

@ -158,9 +158,7 @@ public class IgnoredArtifacts {
);
private static Set<String> health() {
boolean isHealthEnabled = Configuration.getOptionalBooleanValue(
MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + HealthOptions.HEALTH_ENABLED.getKey()).orElse(false);
boolean isHealthEnabled = Configuration.isTrue(HealthOptions.HEALTH_ENABLED);
return !isHealthEnabled ? HEALTH : emptySet();
}
@ -173,9 +171,7 @@ public class IgnoredArtifacts {
);
private static Set<String> metrics() {
boolean isMetricsEnabled = Configuration.getOptionalBooleanValue(
MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + MetricsOptions.METRICS_ENABLED.getKey()).orElse(false);
boolean isMetricsEnabled = Configuration.isTrue(MetricsOptions.METRICS_ENABLED);
return !isMetricsEnabled ? METRICS : emptySet();
}
}

View file

@ -1,6 +1,7 @@
package org.keycloak.quarkus.runtime.configuration.mappers;
import static java.util.Optional.of;
import static org.keycloak.config.LoggingOptions.DEFAULT_LOG_FORMAT;
import static org.keycloak.config.LoggingOptions.GELF_ACTIVATED;
import static org.keycloak.quarkus.runtime.configuration.Configuration.isTrue;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
@ -15,10 +16,13 @@ import java.util.stream.Stream;
import org.apache.commons.lang3.ArrayUtils;
import org.jboss.logmanager.LogContext;
import org.keycloak.config.LoggingOptions;
import org.keycloak.config.Option;
import org.keycloak.config.TracingOptions;
import org.keycloak.quarkus.runtime.Messages;
import org.keycloak.quarkus.runtime.cli.PropertyException;
import io.smallrye.config.ConfigSourceInterceptorContext;
import org.keycloak.quarkus.runtime.configuration.Configuration;
public final class LoggingPropertyMappers {
@ -46,6 +50,11 @@ 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))
.build(),
fromOption(LoggingOptions.LOG_CONSOLE_INCLUDE_TRACE)
.isEnabled(() -> LoggingPropertyMappers.isConsoleEnabled() && TracingPropertyMappers.isTracingEnabled(),
"Console log handler and Tracing is activated")
.build(),
fromOption(LoggingOptions.LOG_CONSOLE_COLOR)
.isEnabled(LoggingPropertyMappers::isConsoleEnabled, CONSOLE_ENABLED_MSG)
@ -72,6 +81,11 @@ 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))
.build(),
fromOption(LoggingOptions.LOG_FILE_INCLUDE_TRACE)
.isEnabled(() -> LoggingPropertyMappers.isFileEnabled() && TracingPropertyMappers.isTracingEnabled(),
"File log handler and Tracing is activated")
.build(),
fromOption(LoggingOptions.LOG_FILE_OUTPUT)
.isEnabled(LoggingPropertyMappers::isFileEnabled, FILE_ENABLED_MSG)
@ -112,6 +126,11 @@ 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))
.build(),
fromOption(LoggingOptions.LOG_SYSLOG_INCLUDE_TRACE)
.isEnabled(() -> LoggingPropertyMappers.isSyslogEnabled() && TracingPropertyMappers.isTracingEnabled(),
"Syslog handler and Tracing is activated")
.build(),
fromOption(LoggingOptions.LOG_SYSLOG_OUTPUT)
.isEnabled(LoggingPropertyMappers::isSyslogEnabled, SYSLOG_ENABLED_MSG)
@ -265,4 +284,19 @@ public final class LoggingPropertyMappers {
return of(Boolean.TRUE.toString());
}
/**
* Add tracing info to the log if the format is not explicitly set, and tracing and {@code includeTraceOption} options are enabled
*/
private static Optional<String> addTracingInfo(Optional<String> value, Option<Boolean> includeTraceOption) {
var isTracingEnabled = Configuration.isTrue(TracingOptions.TRACING_ENABLED);
var includeTrace = Configuration.isTrue(includeTraceOption);
var isChangedLogFormat = !DEFAULT_LOG_FORMAT.equals(value.get());
if (!isTracingEnabled || !includeTrace || isChangedLogFormat) {
return value;
}
return Optional.of(LoggingOptions.DEFAULT_LOG_TRACING_FORMAT);
}
}

View file

@ -304,6 +304,11 @@ public class PropertyMapper<T> {
return this;
}
public Builder<T> mapFrom(Option<?> mapFrom) {
this.mapFrom = mapFrom.getKey();
return this;
}
public Builder<T> mapFrom(String mapFrom) {
this.mapFrom = mapFrom;
return this;

View file

@ -58,6 +58,7 @@ public final class PropertyMappers {
MAPPERS.addAll(VaultPropertyMappers.getVaultPropertyMappers());
MAPPERS.addAll(FeaturePropertyMappers.getMappers());
MAPPERS.addAll(LoggingPropertyMappers.getMappers());
MAPPERS.addAll(TracingPropertyMappers.getMappers());
MAPPERS.addAll(TransactionPropertyMappers.getTransactionPropertyMappers());
MAPPERS.addAll(ClassLoaderPropertyMappers.getMappers());
MAPPERS.addAll(SecurityPropertyMappers.getMappers());

View file

@ -0,0 +1,125 @@
/*
* Copyright 2024 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.quarkus.runtime.configuration.mappers;
import io.smallrye.config.ConfigValue;
import org.keycloak.quarkus.runtime.cli.PropertyException;
import org.keycloak.quarkus.runtime.configuration.Configuration;
import org.keycloak.utils.StringUtil;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import static org.keycloak.config.TracingOptions.TRACING_COMPRESSION;
import static org.keycloak.config.TracingOptions.TRACING_ENABLED;
import static org.keycloak.config.TracingOptions.TRACING_ENDPOINT;
import static org.keycloak.config.TracingOptions.TRACING_JDBC_ENABLED;
import static org.keycloak.config.TracingOptions.TRACING_PROTOCOL;
import static org.keycloak.config.TracingOptions.TRACING_SAMPLER_RATIO;
import static org.keycloak.config.TracingOptions.TRACING_SAMPLER_TYPE;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
public class TracingPropertyMappers {
private static final String TRACING_ENABLED_MSG = "Tracing is enabled";
private TracingPropertyMappers() {
}
public static PropertyMapper<?>[] getMappers() {
return new PropertyMapper[]{
fromOption(TRACING_ENABLED)
.to("quarkus.otel.traces.enabled")
.build(),
fromOption(TRACING_ENDPOINT)
.isEnabled(TracingPropertyMappers::isTracingEnabled, TRACING_ENABLED_MSG)
.to("quarkus.otel.exporter.otlp.traces.endpoint")
.paramLabel("url")
.validator(TracingPropertyMappers::validateEndpoint)
.build(),
fromOption(TRACING_PROTOCOL)
.isEnabled(TracingPropertyMappers::isTracingEnabled, TRACING_ENABLED_MSG)
.to("quarkus.otel.exporter.otlp.traces.protocol")
.paramLabel("protocol")
.build(),
fromOption(TRACING_SAMPLER_TYPE)
.isEnabled(TracingPropertyMappers::isTracingEnabled, TRACING_ENABLED_MSG)
.to("quarkus.otel.traces.sampler")
.paramLabel("type")
.build(),
fromOption(TRACING_SAMPLER_RATIO)
.isEnabled(TracingPropertyMappers::isTracingEnabled, TRACING_ENABLED_MSG)
.to("quarkus.otel.traces.sampler.arg")
.validator(TracingPropertyMappers::validateRatio)
.paramLabel("ratio")
.build(),
fromOption(TRACING_COMPRESSION)
.isEnabled(TracingPropertyMappers::isTracingEnabled, TRACING_ENABLED_MSG)
.to("quarkus.otel.exporter.otlp.traces.compression")
.paramLabel("method")
.build(),
fromOption(TRACING_JDBC_ENABLED)
.mapFrom(TRACING_ENABLED)
.isEnabled(TracingPropertyMappers::isTracingEnabled, TRACING_ENABLED_MSG)
.to("quarkus.datasource.jdbc.telemetry")
.build()
};
}
private static void validateEndpoint(PropertyMapper<String> mapper, ConfigValue value) {
if (value == null || StringUtil.isBlank(value.getValue())) {
throw new PropertyException("URL specified in 'tracing-endpoint' option must not be empty.");
}
if (!isValidUrl(value.getValue())) {
throw new PropertyException("URL specified in 'tracing-endpoint' option is invalid.");
}
}
private static void validateRatio(PropertyMapper<Double> mapper, ConfigValue value) {
if (value == null || StringUtil.isBlank(value.getValue())) {
throw new PropertyException("Ratio in 'tracing-sampler-ratio' option must not be empty.");
}
try {
var ratio = Double.parseDouble(value.getValue());
if (ratio <= 0.0 || ratio > 1.0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
throw new PropertyException("Ratio in 'tracing-sampler-ratio' option must be a double value in interval <0,1).");
}
}
public static boolean isTracingEnabled() {
return Configuration.isTrue(TRACING_ENABLED);
}
public static boolean isTracingJdbcEnabled() {
return Configuration.isTrue(TRACING_JDBC_ENABLED);
}
private static boolean isValidUrl(String url) {
try {
new URL(url).toURI();
return true;
} catch (MalformedURLException | URISyntaxException e) {
return false;
}
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright 2024 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.quarkus.runtime.configuration.test;
import io.quarkus.opentelemetry.runtime.config.build.SamplerType;
import org.junit.Test;
import org.keycloak.config.LoggingOptions;
import org.keycloak.config.TracingOptions;
import java.util.HashMap;
import java.util.Map;
public class TracingConfigurationTest extends AbstractConfigurationTest {
@Test
public void defaultValues() {
initConfig();
assertConfig(Map.of(
"tracing-enabled", "false",
"tracing-endpoint", "http://localhost:4317",
"tracing-protocol", "grpc",
"tracing-jdbc-enabled", "false",
"tracing-sampler-type", SamplerType.TRACE_ID_RATIO.getValue(),
"tracing-sampler-ratio", "1.0",
"tracing-compression", TracingOptions.TracingCompression.none.name(),
"log-console-include-trace", "true",
"log-file-include-trace", "true",
"log-syslog-include-trace", "true"
));
assertExternalConfig(Map.of(
"quarkus.otel.traces.enabled", "false",
"quarkus.otel.exporter.otlp.traces.endpoint", "http://localhost:4317",
"quarkus.otel.exporter.otlp.traces.protocol", "grpc",
"quarkus.datasource.jdbc.telemetry", "false",
"quarkus.otel.traces.sampler", SamplerType.TRACE_ID_RATIO.getValue(),
"quarkus.otel.traces.sampler.arg", "1.0",
"quarkus.otel.exporter.otlp.traces.compression", TracingOptions.TracingCompression.none.name()
));
}
@Test
public void differentValues() {
putEnvVars(Map.of(
"KC_TRACING_ENABLED", "true",
"KC_TRACING_ENDPOINT", "http://something:4444",
"KC_TRACING_PROTOCOL", "http/protobuf",
"KC_TRACING_JDBC_ENABLED", "false",
"KC_TRACING_SAMPLER_TYPE", SamplerType.PARENT_BASED_ALWAYS_ON.getValue(),
"KC_TRACING_SAMPLER_RATIO", "0.5",
"KC_TRACING_COMPRESSION", TracingOptions.TracingCompression.gzip.name(),
"KC_LOG_CONSOLE_INCLUDE_TRACE", "false",
"KC_LOG_FILE_INCLUDE_TRACE", "false",
"KC_LOG_SYSLOG_INCLUDE_TRACE", "false"
));
initConfig();
assertConfig(Map.of(
"tracing-enabled", "true",
"tracing-endpoint", "http://something:4444",
"tracing-protocol", "http/protobuf",
"tracing-jdbc-enabled", "false",
"tracing-sampler-type", SamplerType.PARENT_BASED_ALWAYS_ON.getValue(),
"tracing-sampler-ratio", "0.5",
"tracing-compression", TracingOptions.TracingCompression.gzip.name(),
"log-console-include-trace", "false",
"log-file-include-trace", "false",
"log-syslog-include-trace", "false"
));
assertExternalConfig(Map.of(
"quarkus.otel.traces.enabled", "true",
"quarkus.otel.exporter.otlp.traces.endpoint", "http://something:4444",
"quarkus.otel.exporter.otlp.traces.protocol", "http/protobuf",
"quarkus.datasource.jdbc.telemetry", "false",
"quarkus.otel.traces.sampler", SamplerType.PARENT_BASED_ALWAYS_ON.getValue(),
"quarkus.otel.traces.sampler.arg", "0.5",
"quarkus.otel.exporter.otlp.traces.compression", TracingOptions.TracingCompression.gzip.name()
));
}
@Test
public void consoleLogTraceOn() {
assertLogFormat(LoggingOptions.Handler.console, true, LoggingOptions.DEFAULT_LOG_TRACING_FORMAT);
}
@Test
public void consoleLogTraceOff() {
assertLogFormat(LoggingOptions.Handler.console, false, LoggingOptions.DEFAULT_LOG_FORMAT);
}
@Test
public void fileLogTraceOn() {
assertLogFormat(LoggingOptions.Handler.file, true, LoggingOptions.DEFAULT_LOG_TRACING_FORMAT);
}
@Test
public void fileLogTraceOff() {
assertLogFormat(LoggingOptions.Handler.file, false, LoggingOptions.DEFAULT_LOG_FORMAT);
}
@Test
public void syslogLogTraceOn() {
assertLogFormat(LoggingOptions.Handler.syslog, true, LoggingOptions.DEFAULT_LOG_TRACING_FORMAT);
}
@Test
public void syslogLogTraceOff() {
assertLogFormat(LoggingOptions.Handler.syslog, 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) {
var envVars = new HashMap<String, String>();
envVars.put("KC_TRACING_ENABLED", "true");
envVars.put("KC_LOG_" + loggerType.name().toUpperCase() + "_INCLUDE_TRACE", Boolean.toString(includeTrace));
putEnvVars(envVars);
initConfig();
assertConfig(Map.of(
"tracing-enabled", "true",
"log-" + loggerType.name() + "-include-trace", Boolean.toString(includeTrace)
));
assertExternalConfig(Map.of(
"quarkus.otel.traces.enabled", "true",
"quarkus.log." + loggerType.name() + ".format", expectedFormat
));
// Assert no effect on the format when explicitly set
envVars.put("KC_LOG_" + loggerType.name().toUpperCase() + "_FORMAT", "someFormat");
putEnvVars(envVars);
initConfig();
assertConfig(Map.of(
"tracing-enabled", "true",
"log-" + loggerType.name() + "-include-trace", Boolean.toString(includeTrace)
));
assertExternalConfig(Map.of(
"quarkus.otel.traces.enabled", "true",
"quarkus.log." + loggerType.name() + ".format", "someFormat"
));
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright 2024 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.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DistributionTest
@RawDistOnly(reason = "Containers are immutable")
public class TracingDistTest {
private void assertTracingEnabled(CLIResult result) {
result.assertMessage("opentelemetry");
result.assertMessage("service.name=\"Keycloak\"");
}
private void assertTracingDisabled(CLIResult result) {
result.assertMessage("opentelemetry");
result.assertNoMessage("service.name=\"Keycloak\"");
result.assertNoMessage("Failed to export spans.");
result.assertNoMessage("Connection refused: localhost/127.0.0.1:4317");
}
@Test
@Order(1)
@Launch({"start-dev", "--log-level=io.opentelemetry:fine"})
void disabled(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertStartedDevMode();
assertTracingDisabled(cliResult);
}
@Test
@Order(2)
@Launch({"start-dev", "--tracing-enabled=true", "--log-level=io.opentelemetry:fine"})
void enabledJdbc(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertStartedDevMode();
assertTracingEnabled(cliResult);
}
@Test
@Order(3)
@Launch({"build", "--tracing-enabled=true"})
void buildTracingEnabled(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertBuild();
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--log-level=io.opentelemetry:fine"})
void enabled(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertStarted();
assertTracingEnabled(cliResult);
// Initial system logs do not have any tracing data
cliResult.assertMessage("traceId=, parentId=, spanId=, sampled=");
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--tracing-endpoint=http://endpoint:8888", "--log-level=io.opentelemetry:fine"})
void differentEndpoint(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertStarted();
assertTracingEnabled(cliResult);
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--tracing-endpoint="})
void emptyEndpoint(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("URL specified in 'tracing-endpoint' option must not be empty.");
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--tracing-endpoint=ht://wrong"})
void invalidUrl(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("URL specified in 'tracing-endpoint' option is invalid.");
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--tracing-protocol=http/protobuf", "--log-level=io.opentelemetry:fine"})
void protocolHttpProtobuf(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
assertTracingEnabled(cliResult);
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--tracing-protocol=wrong"})
void unknownProtocol(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("Invalid value for option '--tracing-protocol': wrong. Expected values are: grpc, http/protobuf");
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--tracing-sampler-ratio=0.0"})
void wrongSamplerRatio(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("Ratio in 'tracing-sampler-ratio' option must be a double value in interval <0,1).");
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--tracing-compression=wrong"})
void wrongCompression(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("Invalid value for option '--tracing-compression': wrong. Expected values are: gzip, none");
}
@Test
@Launch({"start", "--hostname-strict=false", "--http-enabled=true", "--optimized", "--log-console-include-trace=false"})
void hideTracingInfoInConsoleLog(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
// Initial system logs do not have any tracing data
cliResult.assertNoMessage("traceId=, parentId=, spanId=, sampled=");
cliResult.assertStarted();
}
}

View file

@ -125,6 +125,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-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
only when Console log handler and Tracing is activated.
--log-console-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when Console log
@ -135,6 +139,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-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
File log handler and Tracing is activated.
--log-file-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when File log
@ -181,6 +189,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-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
Syslog handler and Tracing is activated.
--log-syslog-output <output>
Set the syslog output to JSON or default (plain) unstructured logging.
Possible values are: default, json. Default: default. Available only when
@ -189,6 +201,34 @@ Logging:
Sets the protocol used to connect to the syslog server. Possible values are:
tcp, udp, ssl-tcp. Default: tcp. Available only when Syslog is activated.
Tracing (Preview):
--tracing-compression <method>
Preview: OpenTelemetry compression method used to compress payloads. If unset,
compression is disabled. Possible values are: gzip, none. Default: none.
Available only when Tracing is enabled.
--tracing-enabled <true|false>
Preview: Enables the OpenTelemetry tracing. Default: false.
--tracing-endpoint <url>
Preview: OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
Available only when Tracing is enabled.
--tracing-jdbc-enabled <true|false>
Preview: Enables the OpenTelemetry JDBC tracing. Default: true. Available only
when Tracing is enabled.
--tracing-protocol <protocol>
Preview: OpenTelemetry protocol used for the telemetry data. Possible values
are: grpc, http/protobuf. Default: grpc. Available only when Tracing is
enabled.
--tracing-sampler-ratio <ratio>
Preview: OpenTelemetry sampler ratio. Probability that a span will be sampled.
Expected double value in interval <0,1). Default: 1.0. Available only when
Tracing is enabled.
--tracing-sampler-type <type>
Preview: OpenTelemetry sampler to use for tracing. Possible values are:
always_on, always_off, traceidratio, parentbased_always_on,
parentbased_always_off, parentbased_traceidratio. Default: traceidratio.
Available only when Tracing is enabled.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>

View file

@ -125,6 +125,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-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
only when Console log handler and Tracing is activated.
--log-console-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when Console log
@ -135,6 +139,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-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
File log handler and Tracing is activated.
--log-file-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when File log
@ -181,6 +189,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-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
Syslog handler and Tracing is activated.
--log-syslog-output <output>
Set the syslog output to JSON or default (plain) unstructured logging.
Possible values are: default, json. Default: default. Available only when
@ -189,6 +201,34 @@ Logging:
Sets the protocol used to connect to the syslog server. Possible values are:
tcp, udp, ssl-tcp. Default: tcp. Available only when Syslog is activated.
Tracing (Preview):
--tracing-compression <method>
Preview: OpenTelemetry compression method used to compress payloads. If unset,
compression is disabled. Possible values are: gzip, none. Default: none.
Available only when Tracing is enabled.
--tracing-enabled <true|false>
Preview: Enables the OpenTelemetry tracing. Default: false.
--tracing-endpoint <url>
Preview: OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
Available only when Tracing is enabled.
--tracing-jdbc-enabled <true|false>
Preview: Enables the OpenTelemetry JDBC tracing. Default: true. Available only
when Tracing is enabled.
--tracing-protocol <protocol>
Preview: OpenTelemetry protocol used for the telemetry data. Possible values
are: grpc, http/protobuf. Default: grpc. Available only when Tracing is
enabled.
--tracing-sampler-ratio <ratio>
Preview: OpenTelemetry sampler ratio. Probability that a span will be sampled.
Expected double value in interval <0,1). Default: 1.0. Available only when
Tracing is enabled.
--tracing-sampler-type <type>
Preview: OpenTelemetry sampler to use for tracing. Possible values are:
always_on, always_off, traceidratio, parentbased_always_on,
parentbased_always_off, parentbased_traceidratio. Default: traceidratio.
Available only when Tracing is enabled.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>

View file

@ -335,6 +335,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-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
only when Console log handler and Tracing is activated.
--log-console-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when Console log
@ -345,6 +349,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-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
File log handler and Tracing is activated.
--log-file-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when File log
@ -391,6 +399,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-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
Syslog handler and Tracing is activated.
--log-syslog-output <output>
Set the syslog output to JSON or default (plain) unstructured logging.
Possible values are: default, json. Default: default. Available only when
@ -399,6 +411,34 @@ Logging:
Sets the protocol used to connect to the syslog server. Possible values are:
tcp, udp, ssl-tcp. Default: tcp. Available only when Syslog is activated.
Tracing (Preview):
--tracing-compression <method>
Preview: OpenTelemetry compression method used to compress payloads. If unset,
compression is disabled. Possible values are: gzip, none. Default: none.
Available only when Tracing is enabled.
--tracing-enabled <true|false>
Preview: Enables the OpenTelemetry tracing. Default: false.
--tracing-endpoint <url>
Preview: OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
Available only when Tracing is enabled.
--tracing-jdbc-enabled <true|false>
Preview: Enables the OpenTelemetry JDBC tracing. Default: true. Available only
when Tracing is enabled.
--tracing-protocol <protocol>
Preview: OpenTelemetry protocol used for the telemetry data. Possible values
are: grpc, http/protobuf. Default: grpc. Available only when Tracing is
enabled.
--tracing-sampler-ratio <ratio>
Preview: OpenTelemetry sampler ratio. Probability that a span will be sampled.
Expected double value in interval <0,1). Default: 1.0. Available only when
Tracing is enabled.
--tracing-sampler-type <type>
Preview: OpenTelemetry sampler to use for tracing. Possible values are:
always_on, always_off, traceidratio, parentbased_always_on,
parentbased_always_off, parentbased_traceidratio. Default: traceidratio.
Available only when Tracing is enabled.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>

View file

@ -336,6 +336,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-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
only when Console log handler and Tracing is activated.
--log-console-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when Console log
@ -346,6 +350,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-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
File log handler and Tracing is activated.
--log-file-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when File log
@ -392,6 +400,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-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
Syslog handler and Tracing is activated.
--log-syslog-output <output>
Set the syslog output to JSON or default (plain) unstructured logging.
Possible values are: default, json. Default: default. Available only when
@ -400,6 +412,34 @@ Logging:
Sets the protocol used to connect to the syslog server. Possible values are:
tcp, udp, ssl-tcp. Default: tcp. Available only when Syslog is activated.
Tracing (Preview):
--tracing-compression <method>
Preview: OpenTelemetry compression method used to compress payloads. If unset,
compression is disabled. Possible values are: gzip, none. Default: none.
Available only when Tracing is enabled.
--tracing-enabled <true|false>
Preview: Enables the OpenTelemetry tracing. Default: false.
--tracing-endpoint <url>
Preview: OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
Available only when Tracing is enabled.
--tracing-jdbc-enabled <true|false>
Preview: Enables the OpenTelemetry JDBC tracing. Default: true. Available only
when Tracing is enabled.
--tracing-protocol <protocol>
Preview: OpenTelemetry protocol used for the telemetry data. Possible values
are: grpc, http/protobuf. Default: grpc. Available only when Tracing is
enabled.
--tracing-sampler-ratio <ratio>
Preview: OpenTelemetry sampler ratio. Probability that a span will be sampled.
Expected double value in interval <0,1). Default: 1.0. Available only when
Tracing is enabled.
--tracing-sampler-type <type>
Preview: OpenTelemetry sampler to use for tracing. Possible values are:
always_on, always_off, traceidratio, parentbased_always_on,
parentbased_always_off, parentbased_traceidratio. Default: traceidratio.
Available only when Tracing is enabled.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>

View file

@ -287,6 +287,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-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
only when Console log handler and Tracing is activated.
--log-console-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when Console log
@ -297,6 +301,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-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
File log handler and Tracing is activated.
--log-file-output <output>
Set the log output to JSON or default (plain) unstructured logging. Possible
values are: default, json. Default: default. Available only when File log
@ -343,6 +351,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-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
Syslog handler and Tracing is activated.
--log-syslog-output <output>
Set the syslog output to JSON or default (plain) unstructured logging.
Possible values are: default, json. Default: default. Available only when
@ -351,6 +363,24 @@ Logging:
Sets the protocol used to connect to the syslog server. Possible values are:
tcp, udp, ssl-tcp. Default: tcp. Available only when Syslog is activated.
Tracing (Preview):
--tracing-compression <method>
Preview: OpenTelemetry compression method used to compress payloads. If unset,
compression is disabled. Possible values are: gzip, none. Default: none.
Available only when Tracing is enabled.
--tracing-endpoint <url>
Preview: OpenTelemetry endpoint to connect to. Default: http://localhost:4317.
Available only when Tracing is enabled.
--tracing-protocol <protocol>
Preview: OpenTelemetry protocol used for the telemetry data. Possible values
are: grpc, http/protobuf. Default: grpc. Available only when Tracing is
enabled.
--tracing-sampler-ratio <ratio>
Preview: OpenTelemetry sampler ratio. Probability that a span will be sampled.
Expected double value in interval <0,1). Default: 1.0. Available only when
Tracing is enabled.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>