Yeah, I think you’re right, Ralph. Thanks for reasoning this over with me. 
Returning quickly is still a good idea.

—
Matt Sicker

> On Dec 29, 2022, at 01:16, Ralph Goers <ralph.go...@dslextreme.com> wrote:
> 
> The reason a DefaultConfiguration is created and NOT the identified 
> configuration is that a) we would have to block while the configuration is 
> created and b) creating a Configuration isn’t necessarily very fast depending 
> on what is in it (some of which we cannot control). We do want logging to be 
> available quickly and only logging errors to the console during the 
> initialization period seems like a fair compromise.  It is not at all 
> inconceivable that an application will have started multiple threads that 
> perform logging while logging is initializing and in general, we want Log4j 
> to be as lock free as possible.
> 
> So your “fairly innocuous” change is not something I would support as I 
> explicitly rejected that idea when I implemented it in the first place. I am 
> also not in favor of a configuration option that makes the start up logic 
> even more complicated and fragile.
> 
> Ralph
> 
>> On Dec 28, 2022, at 6:23 PM, Matt Sicker <m...@musigma.org> wrote:
>> 
>> And with this detail about the possibility for a Logger to be returned while 
>> LoggerContext::start is being executed is indeed a reason for why 
>> DefaultConfiguration _normally_ exists. I’m looking at two additional 
>> scenarios:
>> 
>> 1. What if you provide a configuration location String or URI to the 
>> LoggerContext constructor? We already have a configuration source in this 
>> case (or at least we do if the URI corresponds to a local file), but we 
>> ignore this source until we start the LoggerContext. It is this situation 
>> where I thought it may be possible to start loading ConfigurationFactory 
>> plugins here to load and parse the specified configuration as the initial 
>> Configuration instance rather than an instance of DefaultConfiguration. This 
>> wasn’t previously possible due to various code dependencies, but given the 
>> fact that we have access to an initialized Injector instance inside the 
>> LoggerContext constructor (this may be a key detail I haven’t been too 
>> explicit about) means that we can start loading whatever subset of plugins 
>> we want at this point.
>> 
>> 2. If you don’t provide a configuration location, we could still attempt to 
>> load the ConfigurationFactory plugins to bootstrap here. This is even more 
>> realistic now that we’ve removed the plugin package scanning feature, so we 
>> know that plugin service classes will already be available to load at this 
>> time.
>> 
>> What I’m thinking here is a fairly innocuous-looking change may allow us to 
>> load the configuration earlier. As it is now, the LoggerContext is 
>> getOrCreated by the ContextSelector before Log4jContextSelector checks its 
>> state to see if it should be started (in which case it will then load 
>> ConfigurationFactory plugins to start the real configuration). What I think 
>> might be possible is moving this ConfigurationFactory bit deeper into the 
>> call chain by creating it when the LoggerContext is being created. This 
>> would mean the LoggerContext would have the custom configuration instance 
>> _before_ LoggerContext::start is invoked.
>> 
>> One of the main tradeoffs here would be startup time I suppose. By deferring 
>> configuration loading until LoggerContext::start is invoked, we do indeed 
>> get out of the way as soon as possible to start accepting log messages and 
>> returning control to user code. So I suppose even if it turns out to be 
>> possible to load the configuration right away, this would by definition 
>> cause blocking as the configuration is loaded, so this would probably make 
>> sense as a configurable option.
>> —
>> Matt Sicker
>> 
>>>> On Dec 28, 2022, at 11:44, Ralph Goers <ralph.go...@dslextreme.com> wrote:
>>> 
>>> 
>>> 
>>>> On Dec 28, 2022, at 10:37 AM, Ralph Goers <ralph.go...@dslextreme.com> 
>>>> wrote:
>>>> 
>>>> 
>>>> 
>>>> Ralph
>>>> 
>>>>> On Dec 28, 2022, at 7:01 AM, Piotr P. Karwasz <piotr.karw...@gmail.com> 
>>>>> wrote:
>>>>> 
>>>>> Hi Matt,
>>>>> 
>>>>> On Sun, 18 Dec 2022 at 20:30, Matt Sicker <m...@musigma.org> wrote:
>>>>>> During this bootstrapping, if the configuration location is available 
>>>>>> (such as for a unit test), should LoggerContext set up the configuration 
>>>>>> provided? Or is there some sort of cyclic dependency here preventing us 
>>>>>> from loading ConfigurationFactory right away? So far, the only cyclic 
>>>>>> dependencies I’ve found are related to plugins created in the 
>>>>>> DefaultConfiguration (or the NullConfiguration in some cases), but those 
>>>>>> are already commented as such (like in PatternLayout).
>>>>> 
>>>>> I think we should rely more on our `LifeCycle` abstraction:
>>>>> `Configuration` starts in the "initializing" state and does not have
>>>>> any subcomponents (especially those that require a `LoggerContext` to
>>>>> be present) until `initialize()` is called.
>>>> 
>>>> Actually, a LoggerContext is hard-wired with a DefaultConfiguration. So as 
>>>> soon as it exists it has a Configuration. Once the Configuration 
>>>> identified from the configLocation is created the DefaultConfiguration is 
>>>> replaced.  This is the discussion Matt was having in his previous email 
>>>> and didn’t understand why it is required to work that way. Note that once 
>>>> the LoggerContext is constructed it will be “wired” by the ContextSelector 
>>>> and will be usable by any thread.
>>>> 
>>>>> 
>>>>> We can do the same thing with `LoggerContext`: after the constructor
>>>>> exits it does not have a configuration and is in the "initializing"
>>>>> state.
>>>> 
>>>> After the Constructor exists is has a DefaultConfiguration.
>>>> 
>>>>> The configuration will be created on an `initialize()` call
>>>>> (maybe chained from `start()`). By then we can safely pass a reference
>>>>> to `LoggerContext` to the `AbstractConfiguration` constructor.
>>>>> 
>>>>> Logging does not occur until `start()` is called.
>>>> 
>>>> I don’t believe this is true. Once the ContextSelector registers it any 
>>>> calls to log will use it.
>>>> 
>>>> Ralph
>>> 
>>> Note that LoggerContext.start() uses tryLock. If initialization is in 
>>> progress then start() will simply return. So other threads will log while 
>>> initialization is occurring. This is intentional.
>>> 
>>> Ralph
>> 
>> 
> 

Reply via email to