Remove workaround for handling Syslog counting framing (#40989)

Closes #40683

Signed-off-by: Martin Bartoš <mabartos@redhat.com>
This commit is contained in:
Martin Bartoš 2025-07-18 17:01:10 +02:00 committed by GitHub
parent 6c7be65456
commit a7019c638f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 47 additions and 46 deletions

View File

@ -1,5 +1,6 @@
package org.keycloak.config;
import io.quarkus.runtime.logging.LogRuntimeConfig;
import org.jboss.logmanager.handlers.SyslogHandler;
import java.io.File;
@ -296,14 +297,12 @@ public class LoggingOptions {
.description("Set the Syslog output to JSON or default (plain) unstructured logging.")
.build();
// we can use SyslogConfig.CountingFraming type once https://github.com/quarkusio/quarkus/pull/48479 is present
public static final String SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT = "protocol-dependent";
public static final Option<String> LOG_SYSLOG_COUNTING_FRAMING = new OptionBuilder<>("log-syslog-counting-framing", String.class)
public static final Option<LogRuntimeConfig.SyslogConfig.CountingFraming> LOG_SYSLOG_COUNTING_FRAMING = new OptionBuilder<>("log-syslog-counting-framing", LogRuntimeConfig.SyslogConfig.CountingFraming.class)
.category(OptionCategory.LOGGING)
.expectedValues(Boolean.TRUE.toString(), Boolean.FALSE.toString(), SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT)
.defaultValue(SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT)
.transformEnumValues(true)
.defaultValue(LogRuntimeConfig.SyslogConfig.CountingFraming.PROTOCOL_DEPENDENT)
.description("If 'true', the message being sent is prefixed with the size of the message. If '%s', the default value is 'true' when '%s' is 'tcp' or 'ssl-tcp', otherwise 'false'."
.formatted(SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT, LOG_SYSLOG_PROTOCOL.getKey()))
.formatted(Option.transformEnumValue(LogRuntimeConfig.SyslogConfig.CountingFraming.PROTOCOL_DEPENDENT.name()), LOG_SYSLOG_PROTOCOL.getKey()))
.build();
// Syslog async

View File

@ -1,5 +1,7 @@
package org.keycloak.config;
import com.google.common.base.CaseFormat;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@ -128,4 +130,12 @@ public class Option<T> {
}
return String.valueOf(value);
}
/**
* Transform enum values from upper underscore to lower hyphen
* Transform enum type HAS_SOMETHING -> has-something
*/
public static String transformEnumValue(String value) {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, value);
}
}

View File

@ -23,6 +23,7 @@ public class OptionBuilder<T> {
private String description;
private Optional<T> defaultValue;
private List<String> expectedValues;
private boolean transformEnumValues;
// Denotes whether a custom value can be provided among the expected values
private boolean strictExpectedValues;
private boolean caseInsensitiveExpectedValues;
@ -100,6 +101,14 @@ public class OptionBuilder<T> {
return expectedValues(Stream.of(expected).map(Object::toString).collect(Collectors.toList()));
}
/**
* For more details, see the {@link Option#transformEnumValue(String)}
*/
public OptionBuilder<T> transformEnumValues(boolean transform) {
this.transformEnumValues = transform;
return this;
}
public OptionBuilder<T> strictExpectedValues(boolean strictExpectedValues) {
this.strictExpectedValues = strictExpectedValues;
return this;
@ -135,10 +144,12 @@ public class OptionBuilder<T> {
expected = auxiliaryType;
}
boolean isEnumType = Enum.class.isAssignableFrom(expected);
if (expectedValues == null) {
if (Boolean.class.equals(expected)) {
expectedValues(BOOLEAN_TYPE_VALUES);
} else if (Enum.class.isAssignableFrom(expected)) {
} else if (isEnumType) {
expectedValues((Class<? extends Enum>) expected);
} else {
expectedValues = List.of();
@ -149,6 +160,15 @@ public class OptionBuilder<T> {
defaultValue = Optional.of((T) Boolean.FALSE);
}
if (transformEnumValues) {
if (isEnumType) {
expectedValues(expectedValues.stream().map(Option::transformEnumValue).toList());
defaultValue.ifPresent(t -> defaultValue(Optional.of((T) Option.transformEnumValue(t.toString()))));
} else {
throw new IllegalArgumentException("You can use 'transformEnumValues' only for Enum types");
}
}
return new Option<T>(type, key, category, hidden, build, description, defaultValue, expectedValues, strictExpectedValues, caseInsensitiveExpectedValues, deprecatedMetadata);
}

View File

@ -4,7 +4,6 @@ import static org.keycloak.config.LoggingOptions.DEFAULT_LOG_FORMAT;
import static org.keycloak.config.LoggingOptions.LOG_CONSOLE_ENABLED;
import static org.keycloak.config.LoggingOptions.LOG_FILE_ENABLED;
import static org.keycloak.config.LoggingOptions.LOG_SYSLOG_ENABLED;
import static org.keycloak.config.LoggingOptions.SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT;
import static org.keycloak.quarkus.runtime.configuration.Configuration.isSet;
import static org.keycloak.quarkus.runtime.configuration.Configuration.isTrue;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
@ -236,7 +235,6 @@ public final class LoggingPropertyMappers {
.build(),
fromOption(LoggingOptions.LOG_SYSLOG_COUNTING_FRAMING)
.isEnabled(LoggingPropertyMappers::isSyslogEnabled, SYSLOG_ENABLED_MSG)
.transformer(LoggingPropertyMappers::resolveSyslogCountingFraming)
.to("quarkus.log.syslog.use-counting-framing")
.paramLabel("strategy")
.build(),
@ -440,20 +438,4 @@ public final class LoggingPropertyMappers {
throw new PropertyException(String.format("Invalid value for option '--log-syslog-max-length': %s", e.getMessage()));
}
}
// Workaround BEGIN - for https://github.com/keycloak/keycloak/issues/39893
// Remove once the https://github.com/quarkusio/quarkus/issues/48036 is included in Keycloak as Quarkus might handle it on its own
private static String resolveSyslogCountingFraming(String value, ConfigSourceInterceptorContext context) {
if (SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT.equals(value)) {
return Configuration.getOptionalKcValue(LoggingOptions.LOG_SYSLOG_PROTOCOL)
.map(protocol -> switch (protocol) {
case "tcp", "ssl-tcp" -> Boolean.TRUE.toString();
case "udp" -> Boolean.FALSE.toString();
default -> throw new PropertyException("Invalid Syslog protocol: " + protocol);
})
.orElse(Boolean.FALSE.toString());
}
return value;
}
// Workaround END
}

View File

@ -549,7 +549,7 @@ public class PicocliTest extends AbstractConfigurationTest {
onAfter();
nonRunningPicocli = pseudoLaunch("start-dev", "--log=syslog", "--log-syslog-protocol=ssl-tcp", "--log-syslog-counting-framing=protocol-dependent");
assertThat(nonRunningPicocli.exitCode, is(CommandLine.ExitCode.OK));
assertThat(nonRunningPicocli.config.getConfigValue("quarkus.log.syslog.use-counting-framing").getValue(), is("true"));
assertThat(nonRunningPicocli.config.getConfigValue("quarkus.log.syslog.use-counting-framing").getValue(), is("protocol-dependent"));
onAfter();
nonRunningPicocli = pseudoLaunch("start-dev", "--log=syslog", "--log-syslog-counting-framing=wrong");

View File

@ -17,22 +17,20 @@
package org.keycloak.quarkus.runtime.configuration;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.keycloak.config.LoggingOptions.DEFAULT_LOG_FORMAT;
import static org.keycloak.config.LoggingOptions.DEFAULT_SYSLOG_OUTPUT;
import static org.keycloak.config.LoggingOptions.SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import io.quarkus.runtime.logging.LogRuntimeConfig;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
import org.keycloak.config.LoggingOptions;
@ -87,7 +85,7 @@ public class LoggingConfigurationTest extends AbstractConfigurationTest {
"log-syslog-protocol", "tcp",
"log-syslog-format", DEFAULT_LOG_FORMAT,
"log-syslog-output", DEFAULT_SYSLOG_OUTPUT.toString(),
"log-syslog-counting-framing", SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT
"log-syslog-counting-framing", "protocol-dependent"
));
assertThat(Configuration.getOptionalKcValue(LoggingOptions.LOG_SYSLOG_MAX_LENGTH).orElse(null), CoreMatchers.nullValue());
@ -97,7 +95,7 @@ public class LoggingConfigurationTest extends AbstractConfigurationTest {
"quarkus.log.syslog.syslog-type", "rfc5424",
"quarkus.log.syslog.app-name", "keycloak",
"quarkus.log.syslog.protocol", "tcp",
"quarkus.log.syslog.use-counting-framing", "true",
"quarkus.log.syslog.use-counting-framing", "protocol-dependent",
"quarkus.log.syslog.format", DEFAULT_LOG_FORMAT,
"quarkus.log.syslog.json.enabled", "false"
));
@ -175,34 +173,26 @@ public class LoggingConfigurationTest extends AbstractConfigurationTest {
@Test
public void syslogCountingFraming() {
assertSyslogCountingFramingProtocolDependent("tcp", true);
assertSyslogCountingFramingProtocolDependent("udp", false);
assertSyslogCountingFramingProtocolDependent("ssl-tcp", true);
try {
assertSyslogCountingFramingProtocolDependent("error", false);
fail("Wrong protocol name should throw an error");
} catch (PropertyException expected) {
assertThat(expected.getMessage(), containsString("Invalid Syslog protocol: error"));
}
assertSyslogCountingFraming(LogRuntimeConfig.SyslogConfig.CountingFraming.TRUE);
assertSyslogCountingFraming(LogRuntimeConfig.SyslogConfig.CountingFraming.FALSE);
assertSyslogCountingFraming(LogRuntimeConfig.SyslogConfig.CountingFraming.PROTOCOL_DEPENDENT);
}
protected void assertSyslogCountingFramingProtocolDependent(String protocol, boolean expectedCountingFraming) {
protected void assertSyslogCountingFraming(LogRuntimeConfig.SyslogConfig.CountingFraming countingFraming) {
putEnvVars(Map.of(
"KC_LOG", "syslog",
"KC_LOG_SYSLOG_PROTOCOL", protocol
"KC_LOG_SYSLOG_COUNTING_FRAMING", countingFraming.toString()
));
initConfig();
assertConfig(Map.of(
"log-syslog-enabled", "true",
"log-syslog-protocol", protocol,
"log-syslog-counting-framing", SYSLOG_COUNTING_FRAMING_PROTOCOL_DEPENDENT
"log-syslog-counting-framing", countingFraming.toString()
));
assertExternalConfig(Map.of(
"quarkus.log.syslog.enable", "true",
"quarkus.log.syslog.protocol", protocol,
"quarkus.log.syslog.use-counting-framing", Boolean.toString(expectedCountingFraming)
"quarkus.log.syslog.use-counting-framing", countingFraming.toString()
));
onAfter();
}