Skip to content

Commit

Permalink
Merge pull request quarkusio#43232 from troosan/quarkusio#23127
Browse files Browse the repository at this point in the history
Add support for Socket Logging Handler with basic ECS format logging
  • Loading branch information
cescoffier authored Nov 8, 2024
2 parents d1c3ae8 + 3d110d1 commit 901675f
Show file tree
Hide file tree
Showing 15 changed files with 565 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.quarkus.deployment.builditem;

import java.util.Optional;
import java.util.logging.Formatter;

import org.wildfly.common.Assert;

import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.runtime.RuntimeValue;

/**
* The socket format build item. Producing this item will cause the logging subsystem to disregard its
* socket logging formatting configuration and use the formatter provided instead. If multiple formatters
* are enabled at runtime, a warning message is printed and only one is used.
*/
public final class LogSocketFormatBuildItem extends MultiBuildItem {
private final RuntimeValue<Optional<Formatter>> formatterValue;

/**
* Construct a new instance.
*
* @param formatterValue the optional formatter runtime value to use (must not be {@code null})
*/
public LogSocketFormatBuildItem(final RuntimeValue<Optional<Formatter>> formatterValue) {
this.formatterValue = Assert.checkNotNullParam("formatterValue", formatterValue);
}

/**
* Get the formatter value.
*
* @return the formatter value
*/
public RuntimeValue<Optional<Formatter>> getFormatterValue() {
return formatterValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
import io.quarkus.deployment.builditem.LogConsoleFormatBuildItem;
import io.quarkus.deployment.builditem.LogFileFormatBuildItem;
import io.quarkus.deployment.builditem.LogHandlerBuildItem;
import io.quarkus.deployment.builditem.LogSocketFormatBuildItem;
import io.quarkus.deployment.builditem.LogSyslogFormatBuildItem;
import io.quarkus.deployment.builditem.NamedLogHandlersBuildItem;
import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem;
Expand Down Expand Up @@ -249,6 +250,7 @@ LoggingSetupBuildItem setupLoggingRuntimeInit(
final List<LogConsoleFormatBuildItem> consoleFormatItems,
final List<LogFileFormatBuildItem> fileFormatItems,
final List<LogSyslogFormatBuildItem> syslogFormatItems,
final List<LogSocketFormatBuildItem> socketFormatItems,
final Optional<ConsoleFormatterBannerBuildItem> possibleBannerBuildItem,
final List<LogStreamBuildItem> logStreamBuildItems,
final BuildProducer<ShutdownListenerBuildItem> shutdownListenerBuildItemBuildProducer,
Expand Down Expand Up @@ -290,6 +292,8 @@ LoggingSetupBuildItem setupLoggingRuntimeInit(
.map(LogFileFormatBuildItem::getFormatterValue).collect(Collectors.toList());
List<RuntimeValue<Optional<Formatter>>> possibleSyslogFormatters = syslogFormatItems.stream()
.map(LogSyslogFormatBuildItem::getFormatterValue).collect(Collectors.toList());
List<RuntimeValue<Optional<Formatter>>> possibleSocketFormatters = socketFormatItems.stream()
.map(LogSocketFormatBuildItem::getFormatterValue).collect(Collectors.toList());

context.registerSubstitution(InheritableLevel.ActualLevel.class, String.class, InheritableLevel.Substitution.class);
context.registerSubstitution(InheritableLevel.Inherited.class, String.class, InheritableLevel.Substitution.class);
Expand All @@ -308,6 +312,7 @@ LoggingSetupBuildItem setupLoggingRuntimeInit(
categoryMinLevelDefaults.content, alwaysEnableLogStream,
streamingDevUiLogHandler, handlers, namedHandlers,
possibleConsoleFormatters, possibleFileFormatters, possibleSyslogFormatters,
possibleSocketFormatters,
possibleSupplier, launchModeBuildItem.getLaunchMode(), true)));

List<LogCleanupFilterElement> additionalLogCleanupFilters = new ArrayList<>(logCleanupFilters.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.logging.Level;

import org.jboss.logmanager.handlers.AsyncHandler.OverflowAction;
import org.jboss.logmanager.handlers.SocketHandler;
import org.jboss.logmanager.handlers.SyslogHandler.Facility;
import org.jboss.logmanager.handlers.SyslogHandler.Protocol;
import org.jboss.logmanager.handlers.SyslogHandler.SyslogType;
Expand Down Expand Up @@ -77,6 +78,14 @@ public interface LogRuntimeConfig {
@ConfigDocSection
SyslogConfig syslog();

/**
* Socket logging.
* <p>
* Logging to a socket is also supported but not enabled by default.
*/
@ConfigDocSection
SocketConfig socket();

/**
* Logging categories.
* <p>
Expand Down Expand Up @@ -115,6 +124,15 @@ public interface LogRuntimeConfig {
@ConfigDocSection
Map<String, SyslogConfig> syslogHandlers();

/**
* Socket handlers.
* <p>
* The named socket handlers configured here can be linked to one or more categories.
*/
@WithName("handler.socket")
@ConfigDocSection
Map<String, SocketConfig> socketHandlers();

/**
* Log cleanup filters - internal use.
*/
Expand Down Expand Up @@ -396,6 +414,59 @@ interface SyslogConfig {
AsyncConfig async();
}

interface SocketConfig {

/**
* If socket logging should be enabled
*/
@WithDefault("false")
boolean enable();

/**
*
* The IP address and port of the server receiving the logs
*/
@WithDefault("localhost:4560")
@WithConverter(InetSocketAddressConverter.class)
InetSocketAddress endpoint();

/**
* Sets the protocol used to connect to the syslog server
*/
@WithDefault("tcp")
SocketHandler.Protocol protocol();

/**
* Enables or disables blocking when attempting to reconnect a
* {@link Protocol#TCP
* TCP} or {@link Protocol#SSL_TCP SSL TCP} protocol
*/
@WithDefault("false")
boolean blockOnReconnect();

/**
* The log message format
*/
@WithDefault("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n")
String format();

/**
* The log level specifying, which message levels will be logged by socket logger
*/
@WithDefault("ALL")
Level level();

/**
* The name of the filter to link to the file handler.
*/
Optional<String> filter();

/**
* Socket async logging config
*/
AsyncConfig async();
}

interface CleanupFilterConfig {
/**
* The message prefix to match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.jboss.logmanager.handlers.FileHandler;
import org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler;
import org.jboss.logmanager.handlers.SizeRotatingFileHandler;
import org.jboss.logmanager.handlers.SocketHandler;
import org.jboss.logmanager.handlers.SyslogHandler;

import io.quarkus.bootstrap.logging.InitialConfigurator;
Expand All @@ -63,6 +64,7 @@
import io.quarkus.runtime.logging.LogRuntimeConfig.CleanupFilterConfig;
import io.quarkus.runtime.logging.LogRuntimeConfig.ConsoleConfig;
import io.quarkus.runtime.logging.LogRuntimeConfig.FileConfig;
import io.quarkus.runtime.logging.LogRuntimeConfig.SocketConfig;
import io.quarkus.runtime.shutdown.ShutdownListener;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;
Expand Down Expand Up @@ -116,7 +118,7 @@ public String getName() {
new LoggingSetupRecorder(new RuntimeValue<>(consoleRuntimeConfig)).initializeLogging(logRuntimeConfig,
logBuildTimeConfig,
DiscoveredLogComponents.ofEmpty(), emptyMap(), false, null, emptyList(), emptyList(), emptyList(), emptyList(),
emptyList(), banner, LaunchMode.DEVELOPMENT, false);
emptyList(), emptyList(), banner, LaunchMode.DEVELOPMENT, false);
}

public ShutdownListener initializeLogging(
Expand All @@ -131,6 +133,7 @@ public ShutdownListener initializeLogging(
final List<RuntimeValue<Optional<Formatter>>> possibleConsoleFormatters,
final List<RuntimeValue<Optional<Formatter>>> possibleFileFormatters,
final List<RuntimeValue<Optional<Formatter>>> possibleSyslogFormatters,
final List<RuntimeValue<Optional<Formatter>>> possibleSocketFormatters,
final RuntimeValue<Optional<Supplier<String>>> possibleBannerSupplier,
final LaunchMode launchMode,
final boolean includeFilters) {
Expand Down Expand Up @@ -211,6 +214,14 @@ public void close() throws SecurityException {
}
}

if (config.socket().enable()) {
final Handler socketHandler = configureSocketHandler(config.socket(), errorManager, cleanupFiler,
namedFilters, possibleSocketFormatters, includeFilters);
if (socketHandler != null) {
handlers.add(socketHandler);
}
}

if ((launchMode.isDevOrTest() || enableWebStream)
&& streamingDevUiConsoleHandler != null
&& streamingDevUiConsoleHandler.getValue().isPresent()) {
Expand All @@ -229,7 +240,7 @@ public void close() throws SecurityException {

Map<String, Handler> namedHandlers = shouldCreateNamedHandlers(config, additionalNamedHandlers)
? createNamedHandlers(config, consoleRuntimeConfig.getValue(), additionalNamedHandlers,
possibleConsoleFormatters, possibleFileFormatters, possibleSyslogFormatters,
possibleConsoleFormatters, possibleFileFormatters, possibleSyslogFormatters, possibleSocketFormatters,
errorManager, cleanupFiler, namedFilters, launchMode,
shutdownNotifier, includeFilters)
: emptyMap();
Expand Down Expand Up @@ -328,7 +339,7 @@ public static void initializeBuildTimeLogging(
}

Map<String, Handler> namedHandlers = createNamedHandlers(config, consoleConfig, emptyList(),
emptyList(), emptyList(), emptyList(), errorManager, logCleanupFilter,
emptyList(), emptyList(), emptyList(), emptyList(), errorManager, logCleanupFilter,
emptyMap(), launchMode, dummy, false);

setUpCategoryLoggers(buildConfig, categoryDefaultMinLevels, categories, logContext, errorManager, namedHandlers);
Expand Down Expand Up @@ -388,6 +399,7 @@ private static Map<String, Handler> createNamedHandlers(
List<RuntimeValue<Optional<Formatter>>> possibleConsoleFormatters,
List<RuntimeValue<Optional<Formatter>>> possibleFileFormatters,
List<RuntimeValue<Optional<Formatter>>> possibleSyslogFormatters,
List<RuntimeValue<Optional<Formatter>>> possibleSocketFormatters,
ErrorManager errorManager, LogCleanupFilter cleanupFilter,
Map<String, Filter> namedFilters, LaunchMode launchMode,
ShutdownNotifier shutdownHandler, boolean includeFilters) {
Expand Down Expand Up @@ -422,6 +434,17 @@ private static Map<String, Handler> createNamedHandlers(
addToNamedHandlers(namedHandlers, syslogHandler, sysLogConfigEntry.getKey());
}
}
for (Entry<String, SocketConfig> socketConfigEntry : config.socketHandlers().entrySet()) {
SocketConfig namedSocketConfig = socketConfigEntry.getValue();
if (!namedSocketConfig.enable()) {
continue;
}
final Handler socketHandler = configureSocketHandler(namedSocketConfig, errorManager, cleanupFilter,
namedFilters, possibleSocketFormatters, includeFilters);
if (socketHandler != null) {
addToNamedHandlers(namedHandlers, socketHandler, socketConfigEntry.getKey());
}
}

Map<String, Handler> additionalNamedHandlersMap;
if (additionalNamedHandlers.isEmpty()) {
Expand Down Expand Up @@ -770,6 +793,53 @@ private static Handler configureSyslogHandler(final LogRuntimeConfig.SyslogConfi
}
}

private static Handler configureSocketHandler(final LogRuntimeConfig.SocketConfig config,
final ErrorManager errorManager,
final LogCleanupFilter logCleanupFilter,
final Map<String, Filter> namedFilters,
final List<RuntimeValue<Optional<Formatter>>> possibleSocketFormatters,
final boolean includeFilters) {
try {
final SocketHandler handler = new SocketHandler(config.endpoint().getHostString(), config.endpoint().getPort());
handler.setProtocol(config.protocol());
handler.setBlockOnReconnect(config.blockOnReconnect());
handler.setLevel(config.level());

Formatter formatter = null;
boolean formatterWarning = false;
for (RuntimeValue<Optional<Formatter>> value : possibleSocketFormatters) {
if (formatter != null) {
formatterWarning = true;
}
final Optional<Formatter> val = value.getValue();
if (val.isPresent()) {
formatter = val.get();
}
}
if (formatter == null) {
formatter = new PatternFormatter(config.format());
}
handler.setFormatter(formatter);

handler.setErrorManager(errorManager);
handler.setFilter(logCleanupFilter);
applyFilter(includeFilters, errorManager, logCleanupFilter, config.filter(), namedFilters, handler);

if (formatterWarning) {
handler.getErrorManager().error("Multiple socket formatters were activated", null,
ErrorManager.GENERIC_FAILURE);
}

if (config.async().enable()) {
return createAsyncHandler(config.async(), config.level(), handler);
}
return handler;
} catch (IOException e) {
errorManager.error("Failed to create socket handler", e, ErrorManager.OPEN_FAILURE);
return null;
}
}

private static AsyncHandler createAsyncHandler(LogRuntimeConfig.AsyncConfig asyncConfig, Level level, Handler handler) {
final AsyncHandler asyncHandler = new AsyncHandler(asyncConfig.queueLength());
asyncHandler.setOverflowAction(asyncConfig.overflow());
Expand Down
Loading

0 comments on commit 901675f

Please sign in to comment.