StructuredLogFormatterFactory Class — spring-boot Architecture
Architecture documentation for the StructuredLogFormatterFactory class in StructuredLogFormatterFactory.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java lines 52–253
public class StructuredLogFormatterFactory<E> {
private static final FailureHandler failureHandler = (type, implementationName, failure) -> {
if (!(failure instanceof ClassNotFoundException)) {
throw new IllegalArgumentException(
"Unable to instantiate " + implementationName + " [" + type.getName() + "]", failure);
}
};
private final SpringFactoriesLoader factoriesLoader;
private final Class<E> logEventType;
private final Instantiator<?> instantiator;
private final CommonFormatters<E> commonFormatters;
/**
* Create a new {@link StructuredLogFormatterFactory} instance.
* @param logEventType the log event type
* @param environment the Spring {@link Environment}
* @param availableParameters callback used to configure available parameters for the
* specific logging system
* @param commonFormatters callback used to define supported common formatters
*/
public StructuredLogFormatterFactory(Class<E> logEventType, Environment environment,
@Nullable Consumer<AvailableParameters> availableParameters,
Consumer<CommonFormatters<E>> commonFormatters) {
this(SpringFactoriesLoader.forDefaultResourceLocation(), logEventType, environment, availableParameters,
commonFormatters);
}
StructuredLogFormatterFactory(SpringFactoriesLoader factoriesLoader, Class<E> logEventType, Environment environment,
@Nullable Consumer<AvailableParameters> availableParameters,
Consumer<CommonFormatters<E>> commonFormatters) {
StructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment);
this.factoriesLoader = factoriesLoader;
this.logEventType = logEventType;
this.instantiator = new Instantiator<>(Object.class, (allAvailableParameters) -> {
allAvailableParameters.add(Environment.class, environment);
allAvailableParameters.add(StructuredLoggingJsonMembersCustomizer.class,
new JsonMembersCustomizerBuilder(properties).build());
allAvailableParameters.add(StructuredLoggingJsonMembersCustomizer.Builder.class,
new JsonMembersCustomizerBuilder(properties));
allAvailableParameters.add(StackTracePrinter.class, (type) -> getStackTracePrinter(properties));
allAvailableParameters.add(ContextPairs.class, (type) -> getContextPairs(properties));
if (availableParameters != null) {
availableParameters.accept(allAvailableParameters);
}
}, failureHandler);
this.commonFormatters = new CommonFormatters<>();
commonFormatters.accept(this.commonFormatters);
}
private @Nullable StackTracePrinter getStackTracePrinter(@Nullable StructuredLoggingJsonProperties properties) {
return (properties != null && properties.stackTrace() != null) ? properties.stackTrace().createPrinter() : null;
}
private ContextPairs getContextPairs(@Nullable StructuredLoggingJsonProperties properties) {
Context contextProperties = (properties != null) ? properties.context() : null;
contextProperties = (contextProperties != null) ? contextProperties : new Context(true, null);
return new ContextPairs(contextProperties.include(), contextProperties.prefix());
}
/**
* Get a new {@link StructuredLogFormatter} instance for the specified format.
* @param format the format requested (either a {@link CommonStructuredLogFormat} ID
* or a fully-qualified class name)
* @return a new {@link StructuredLogFormatter} instance
* @throws IllegalArgumentException if the format is unknown
*/
public StructuredLogFormatter<E> get(String format) {
StructuredLogFormatter<E> formatter = this.commonFormatters.get(this.instantiator, format);
formatter = (formatter != null) ? formatter : getUsingClassName(format);
if (formatter != null) {
return formatter;
}
throw new IllegalArgumentException(
"Unknown format '%s'. Values can be a valid fully-qualified class name or one of the common formats: %s"
.formatted(format, this.commonFormatters.getCommonNames()));
}
@SuppressWarnings("unchecked")
private @Nullable StructuredLogFormatter<E> getUsingClassName(String className) {
Object formatter = this.instantiator.instantiate(className);
if (formatter != null) {
Assert.state(formatter instanceof StructuredLogFormatter,
() -> "'%s' is not a StructuredLogFormatter".formatted(className));
checkTypeArgument(formatter);
}
return (StructuredLogFormatter<E>) formatter;
}
private void checkTypeArgument(Object formatter) {
Class<?> typeArgument = GenericTypeResolver.resolveTypeArgument(formatter.getClass(),
StructuredLogFormatter.class);
Assert.state(this.logEventType.equals(typeArgument),
() -> "Type argument of %s must be %s but was %s".formatted(formatter.getClass().getName(),
this.logEventType.getName(), (typeArgument != null) ? typeArgument.getName() : "null"));
}
/**
* Callback used for configure the {@link CommonFormatterFactory} to use for a given
* {@link CommonStructuredLogFormat}.
*
* @param <E> the log event type
*/
public static class CommonFormatters<E> {
private final Map<CommonStructuredLogFormat, CommonFormatterFactory<E>> factories = new TreeMap<>();
/**
* Add the factory that should be used for the given
* {@link CommonStructuredLogFormat}.
* @param format the common structured log format
* @param factory the factory to use
*/
public void add(CommonStructuredLogFormat format, CommonFormatterFactory<E> factory) {
this.factories.put(format, factory);
}
Collection<String> getCommonNames() {
return this.factories.keySet().stream().map(CommonStructuredLogFormat::getId).toList();
}
@Nullable StructuredLogFormatter<E> get(Instantiator<?> instantiator, String format) {
CommonStructuredLogFormat commonFormat = CommonStructuredLogFormat.forId(format);
CommonFormatterFactory<E> factory = (commonFormat != null) ? this.factories.get(commonFormat) : null;
return (factory != null) ? factory.createFormatter(instantiator) : null;
}
}
/**
* Factory used to create a {@link StructuredLogFormatter} for a given
* {@link CommonStructuredLogFormat}.
*
* @param <E> the log event type
*/
@FunctionalInterface
public interface CommonFormatterFactory<E> {
/**
* Create the {@link StructuredLogFormatter} instance.
* @param instantiator instantiator that can be used to obtain arguments
* @return a new {@link StructuredLogFormatter} instance
*/
StructuredLogFormatter<E> createFormatter(Instantiator<?> instantiator);
}
/**
* {@link StructuredLoggingJsonMembersCustomizer.Builder} implementation.
*/
class JsonMembersCustomizerBuilder implements StructuredLoggingJsonMembersCustomizer.Builder<E> {
private final @Nullable StructuredLoggingJsonProperties properties;
private boolean nested;
JsonMembersCustomizerBuilder(@Nullable StructuredLoggingJsonProperties properties) {
this.properties = properties;
}
@Override
public JsonMembersCustomizerBuilder nested(boolean nested) {
this.nested = nested;
return this;
}
@Override
public StructuredLoggingJsonMembersCustomizer<E> build() {
return (members) -> {
List<StructuredLoggingJsonMembersCustomizer<?>> customizers = new ArrayList<>();
if (this.properties != null) {
customizers.add(new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
StructuredLogFormatterFactory.this.instantiator, this.properties, this.nested));
}
customizers.addAll(loadStructuredLoggingJsonMembersCustomizers());
invokeCustomizers(members, customizers);
};
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private List<StructuredLoggingJsonMembersCustomizer<?>> loadStructuredLoggingJsonMembersCustomizers() {
return (List) StructuredLogFormatterFactory.this.factoriesLoader.load(
StructuredLoggingJsonMembersCustomizer.class,
ArgumentResolver.from(StructuredLogFormatterFactory.this.instantiator::getArg));
}
@SuppressWarnings("unchecked")
private void invokeCustomizers(Members<E> members,
List<StructuredLoggingJsonMembersCustomizer<?>> customizers) {
LambdaSafe.callbacks(StructuredLoggingJsonMembersCustomizer.class, customizers, members)
.withFilter(LambdaSafe.Filter.allowAll())
.invoke((customizer) -> customizer.customize(members));
}
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free