ppkarwasz commented on code in PR #2696:
URL: https://github.com/apache/logging-log4j2/pull/2696#discussion_r1662526780


##########
src/site/antora/modules/ROOT/pages/manual/customconfig.adoc:
##########
@@ -14,372 +14,232 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 ////
-= Programmatic Configuration
+= Programmatic configuration
 
-Log4j 2 provides a few ways for applications to create their own
-programmatic configuration:
+Next to xref:manual/configuration.adoc[configuration files], Log4j Core can be 
configured programmatically too.
+In this page, we will explore utilities helping with programmatic 
configuration and demonstrate how they can be leveraged for certain use cases.
 
-* Specify a custom `ConfigurationFactory` to start Log4j with a
-programmatic configuration
-* Use the `Configurator` to replace the configuration after Log4j started
-* Initialize Log4j with a combination of a configuration file and
-programmatic configuration
-* Modify the current `Configuration` after initialization
+[#prelim]
+== Preliminaries
+
+To begin with, we strongly encourage you to check out the 
xref:manual/architecture.adoc[] page first.
+Let's repeat some basic definitions of particular interest:
+
+xref:manual/architecture.adoc#LoggerContext[`LoggerContext`]::
+It is the anchor of the logging system.
+Generally there is one, statically-accessible, global `LoggerContext` for most 
applications.
+But there can be multiple ``LoggerContext``s, for instance, to use in tests, 
in Java EE web applications, etc.
+
+xref:manual/architecture.adoc#Configuration[`Configuration`]::
+It encapsulates a Log4j Core configuration (properties, appenders, loggers, 
etc.) and is associated with a `LoggerContext`.
+
+[#tooling]
+== Tooling
+
+For programmatic configuration, Log4j Core essentially provides the following 
tooling:
+
+<<ConfigurationBuilder>>:: for declaratively creating a `Configuration`
+
+<<Configurator>>:: for associating a `Configuration` with a `LoggerContext`
+
+<<ConfigurationFactory>>:: for registering a `Configuration` factory to 
xref:manual/configuration.adoc[the configuration file mechanism]
+
+In short, we will create ``Configuration``s using `ConfigurationBuilder`, and 
activate them using `Configurator`.
 
 [#ConfigurationBuilder]
-== The ConfigurationBuilder API
-
-Starting with release 2.4, Log4j provides a `ConfigurationBuilder` and a
-set of component builders that allow a `Configuration` to be created
-fairly easily. Actual configuration objects like `LoggerConfig` or
-`Appender` can be unwieldy; they require a lot of knowledge about Log4j
-internals which makes them difficult to work with if all you want is to
-create a `Configuration`.
-
-The new `ConfigurationBuilder` API (in the
-`org.apache.logging.log4j.core.config.builder.api` package) allows users
-to create Configurations in code by constructing component
-_definitions_. There is no need to work directly with actual
-configuration objects. Component definitions are added to the
-`ConfigurationBuilder`, and once all the definitions have been collected
-all the actual configuration objects (like Loggers and Appenders) are
-constructed.
-
-`ConfigurationBuilder` has convenience methods for the base components
-that can be configured such as Loggers, Appenders, Filter, Properties,
-etc. However, Log4j 2's plugin mechanism means that users can create any
-number of custom components. As a trade-off, the `ConfigurationBuilder`
-API provides only a limited number of "strongly typed" convenience
-methods like `newLogger()`, `newLayout()` etc. The generic
-`builder.newComponent()` method can be used if no convenience method
-exists for the component you want to configure.
-
-For example, the builder does not know what sub-components can be
-configured on specific components such as the RollingFileAppender vs.
-the RoutingAppender. To specify a triggering policy on a
-RollingFileAppender you would use builder.newComponent().
-
-Examples of using the `ConfigurationBuilder` API are in the sections that
-follow.
+=== `ConfigurationBuilder`
 
-[#ConfigurationFactory]
-== Understanding ConfigurationFactory
-
-During initialization, Log4j 2 will search for available
-xref:manual/extending.adoc#ConfigurationFactory[ConfigurationFactories] and
-then select the one to use. The selected `ConfigurationFactory` creates
-the `Configuration` that Log4j will use. Here is how Log4j finds the
-available ConfigurationFactories:
-
-1.  A system property named `log4j2.configurationFactory` can be set
-with the name of the ConfigurationFactory to be used.
-2.  `ConfigurationFactory.setConfigurationFactory(ConfigurationFactory)`
-can be called with the instance of the `ConfigurationFactory` to be used.
-This must be called before any other calls to Log4j.
-3.  A `ConfigurationFactory` implementation can be added to the classpath
-and configured as a plugin in the "ConfigurationFactory" category. The
-`@Order` annotation can be used to specify the relative priority when
-multiple applicable ConfigurationFactories are found.
-
-ConfigurationFactories have the concept of "supported types", which
-basically maps to the file extension of the configuration file that the
-ConfigurationFactory can handle. If a configuration file location is
-specified, ConfigurationFactories whose supported type does not include
-"*" or the matching file extension will not be used.
-
-[#Example]
-== Initialize Log4j Using ConfigurationBuilder with a Custom 
ConfigurationFactory
-
-One way to programmatically configure Log4j 2 is to create a custom
-`ConfigurationFactory` that uses the
-<<ConfigurationBuilder,`ConfigurationBuilder`>> to create a
-Configuration. The below example overrides the `getConfiguration()`
-method to return a `Configuration` created by the `ConfigurationBuilder`.
-This will cause the `Configuration` to automatically be hooked into Log4j
-when the `LoggerContext` is created. In the example below, because it
-specifies a supported type of "*" it will override any configuration
-files provided.
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.html[`ConfigurationBuilder`]
 interface models a fluent API to programmatically create 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]s.
+If you have ever created a xref:manual/configuration.adoc[Log4j Core 
configuration file], consider `ConfigurationBuilder` as a convenience utility 
to model the very same declarative configuration structure programmatically, in 
a type-safe way.
+
+Let's show `ConfigurationBuilder` usage with an example.
+Consider the following Log4j Core configuration file:
+
+[tabs]
+====
+XML::
++
+.Snippet from an example 
{antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.xml[`log4j2.xml`]
+[source,xml]
+----
+include::example$manual/customconfig/ConfigurationBuilder/log4j2.xml[lines=24..34,indent=0]
+----
+
+JSON::
++
+.Snippet from an example 
{antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.json[`log4j2.json`]
+[source,json]
+----
+include::example$manual/customconfig/ConfigurationBuilder/log4j2.json[lines=3..16,indent=0]
+----
+
+YAML::
++
+.Snippet from an example 
{antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.yaml[`log4j2.yaml`]
+[source,yaml]
+----
+include::example$manual/customconfig/ConfigurationBuilder/log4j2.yaml[lines=19..-1,indent=0]
+----
 
+Properties::
++
+.Snippet from an example 
{antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.properties[`log4j2.properties`]
+[source,properties]
+----
+include::example$manual/customconfig/ConfigurationBuilder/log4j2.properties[lines=17..-1]
+----
+====
+
+Above Log4j Core configuration can be programmatically built using 
`ConfigurationBuilder` as follows:
+
+.Snippet from an example 
{antora-examples-url}/manual/customconfig/Usage.java[`Usage.java`]
 [source,java]
 ----
-@Namespace(ConfigurationFactory.NAMESPACE)
-@Plugin
-@Order(50)
-public class CustomConfigurationFactory extends ConfigurationFactory {
-
-    static Configuration createConfiguration(final String name, 
ConfigurationBuilder<BuiltConfiguration> builder) {
-        builder.setConfigurationName(name);
-        builder.setStatusLevel(Level.ERROR);
-        builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, 
Filter.Result.NEUTRAL).
-            addAttribute("level", Level.DEBUG));
-        AppenderComponentBuilder appenderBuilder = 
builder.newAppender("Stdout", "CONSOLE").
-            addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
-        appenderBuilder.add(builder.newLayout("PatternLayout").
-            addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
-        appenderBuilder.add(builder.newFilter("MarkerFilter", 
Filter.Result.DENY,
-            Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
-        builder.add(appenderBuilder);
-        builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
-            add(builder.newAppenderRef("Stdout")).
-            addAttribute("additivity", false));
-        
builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
-        return builder.build();
-    }
-
-    @Override
-    public Configuration getConfiguration(final LoggerContext loggerContext, 
final ConfigurationSource source) {
-        return getConfiguration(loggerContext, source.toString(), null);
-    }
-
-    @Override
-    public Configuration getConfiguration(final LoggerContext loggerContext, 
final String name, final URI configLocation) {
-        ConfigurationBuilder<BuiltConfiguration> builder = 
newConfigurationBuilder();
-        return createConfiguration(name, builder);
-    }
-
-    @Override
-    protected String[] getSupportedTypes() {
-        return new String[] {"*"};
-    }
-}
+include::example$manual/customconfig/Usage.java[tag=createConfiguration,indent=0]
 ----
+<1> The default `ConfigurationBuilder` instance is obtained using 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilderFactory.html#newConfigurationBuilder()[`ConfigurationBuilderFactory.newConfigurationBuilder()`]
 static method
+<2> Add the appender along with the layout
+<3> Add the root logger along with a level and appender reference
+<4> Create the configuration, but *don't initialize* it
++
+[TIP]
+====
+It is a good practice to not initialize ``Configuration``s when they are 
constructed.
+This task should ideally be delegated to <<Configurator>>.

Review Comment:
   No, I am not.
   
   We probably should add to `ConfigurationBuilder` a `build()` method 
equivalent to `build(false)` and deprecate the latter.
   IDEA reminds me each time that `boolean`s in public methods are a code smell.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to