Re: Redundant abstractions: property sources, lookups and pattern converters

2024-07-17 Thread Piotr P. Karwasz
Hi Ralph,

On Tue, 16 Jul 2024 at 15:17, Ralph Goers  wrote:
> > * we have a `SpringLookup` and a `SpringPropertySource`.
>
> SpringLookup returns the value of a key. A property source locates a set of 
> keys. So comparing them is apples to oranges. Or rather - an apple to a 
> bushel of apples. PropertySources are NOT available to the logging 
> configuration. However, a Lookup can certainly use a PropertySource to locate 
> the keys it is to resolve.

Yes, property sources can not be addressed directly, since they are
not namespaced, as you remark below.
Other than that lookups and property sources are pretty similar: the
`forEach()` methods of property sources are only useful for caching
and I am not sure caching dozens of not Log4j related properties is
useful.

> > * we have a `${date:...}` lookup and a `%d{...}`. Note that
>
> > `$${date:...}` and `%d{...}` give the same result in a
> > `PatternLayout`!
>
> While they do in the Layout they do not have the same behavior when used in 
> the FilePattern on a Rolling Appender.

Good point, I have a note about that in the revamped
RollingFileAppender description.

Although `$${date:...}` and `%d{...}` are not equivalent for
`filePattern`, I don't see a reason for users to use the former.
A file pattern like `$${date:-MM}/%d{-MM-dd}.log` that I often
see in user questions, simply doesn't do what the user wants. The
`2024-06-30.log` file ends up in the `2024-07` folder!
The user should use `%d{-MM}/%d{-MM-dd}.log`, which works
correctly since 2012 according to Git.

> IMO, it was a poor decision to use the data in the file pattern to determine 
> the rollover interval.

I share the same opinion. Autodetection is very useful for simple
cases, but we might want to add a `frequency` config attribute to
allow users to override autodetection.

Same thing applies to the autodetection of compress actions: users
might want to configure those explicitly, e.g., if they want to
configure the compression level and other parameters.

> > ## Equivalent concepts in other frameworks
> >
> > Spring Boot's equivalent of both `PropertiesUtil` and `Interpolator`
> > is the single `Environment`[1] concept:
>
> However, Spring’s variables are primarily used while configuring the 
> application. The same is true with PropertySources. OTOH Lookups are meant to 
> be used while the application is running.

If we exclude RoutingAppender, most lookups are used at configuration
time. Less than 10 attributes accept lookups at runtime. I have
documented them all recently:

https://logging.staged.apache.org/log4j/2.x/manual/configuration.html#lazy-property-substitution

> > What do you think?
>
> I am not convinced.
>
> The advantage with Lookups is that they can be namespaced. i.e. ${ctx:myKey}. 
> This is a nice short way of expressing which Map you want to look in. 
> Specifying ${myKey} would require merging all the Maps together.

Namespacing can be both an advantage and a disadvantage:

* you don't want ephemeral context data to pollute the global
namespace, so `${ctx:myKey}` is necessary. However in many places
(like the `pattern` of a `Routes`) component, it could be replaced by
`%X{myKey}`.
* often users are startled by the necessity of adding a namespace,
e.g. `${sys:myKey}`, especially if the migrate from Log4j 1.
The `sys` and `env` lookups should often be used together, e.g.
`${sys:myKey:-${env:myKey}}`. This would be much simpler if we remove
the namespace.

> I am not a fan of making either of these pluggable. Making StrSubstitutor 
> pluggable is a security risk. PropertiesUtil is pluggable by way of custom 
> PropertySources.

It is a security risk, but it is not **our** security risk.
If we make `StrSubstitutor` pluggable and Spring decides to use its
SpEL processor to evaluate configuration attributes, it is up to them
to make sure it is secure.

The advantage of delegating string interpolation and configuration
properties to the runtime environment is that users will have a
coherent experience.
Right now SpringPropertySource is the property source with highest
priority. But, there are still other property sources, so Spring users
need to know about both `log4j2.component.properties` and
`application.properties`.
If we make `PropertiesUtil` pluggable, they can forget about the latter.

The same applies to `StrSubstitutor`: a Spring user might want to use
`${value:default}` without necessarily learning our
`${value:-default}` syntax.
And if Spring Boot maintainers decide it is safe enough, Spring users
could use `#{...}` SpEL expressions at runtime.

> Compared to a Lookup a PatternConverter is fairly expensive. A Lookup simply 
> returns the value of a key from a Map. OTOH a PatternConverter is really a 
> formatter. Granted we do have things like the upper Lookup that acts as a 
> formatter but its capabilities are purposefully limited.

It depends on the application: if users employ `$${ctx:myKey}` in a
PatternLayout, this will be more expensive than

Re: Redundant abstractions: property sources, lookups and pattern converters

2024-07-17 Thread Matt Sicker
I’ll note one design constraint behind property sources and lookups. Property 
sources are defined in the API while lookups are defined in Core. Besides that, 
property sources are intended for use with configuration (either for components 
outside the config file or for reuse in a config file) while lookups are 
intended for use with log events, though the ability to use properties in log 
events makes this confusing.

> On Jul 15, 2024, at 08:30, Piotr P. Karwasz  wrote:
> 
> Since the creation of Log4j 2, the concepts of `PropertySource` and
> `StrLookup` and the concepts of `StrLookup` and
> `LogEventPatternConverter` have strongly converged to each other.
> We might consider removing some of them in Log4j Core 4.
> 
> ## Problem
> 
> Log4j Core uses multiple map-like abstractions that evaluate strings:
> 
> * `PropertySource`s are used to provide additional sources of
> **externalized configuration** to
> `PropertiesUtil/PropertyEnvironment`, which is used to modify default
> values of Log4j components.
> * `StrLookup`s are used by `Interpolator` to interpolate the
> attributes of the configuration file, which is something a
> `PropertiesUtil/PropertyEnvironment` could also do.
> The `Interpolator` is also used at runtime by `PatternLayout` to
> format log events.
> * `LogEventPatternConverter`s, which are used by `PatternLayout` to
> format log events.
> 
> Since the domains of these abstractions overlap, we end up
> implementing these in pairs. For example:
> 
> * we have a `SpringLookup` and a `SpringPropertySource`.
> * we have a `${date:...}` lookup and a `%d{...}`. Note that
> `$${date:...}` and `%d{...}` give the same result in a
> `PatternLayout`!
> 
> ## Equivalent concepts in other frameworks
> 
> Spring Boot's equivalent of both `PropertiesUtil` and `Interpolator`
> is the single `Environment`[1] concept:
> 
> * The `Environment` provides default values of Spring Boot beans, like
> `PropertiesUtil` does.
> * `${name}` expressions can be used in XML bean definitions[2], which
> is the concept that resembles our configuration file.
> 
> If `${name}` expressions are too restrictive (e.g. you can use them to
> get the current date), SpEL expressions can be used. Therefore SpEL
> expressions ressemble the way we use pattern converters.
> 
> The Jakarta world also released a `Config`[3] concept, which works
> pretty much like Spring's `Environment`.
> 
> ## Possible solutions
> 
> For Log4j 4 we could consider:
> 
> * removing the `StrLookup` concept and provide a simple `Interpolator`
> that uses `PropertiesUtil`.
> * make both `PropertiesUtil` and `StrSubstitutor` pluggable: external
> frameworks might want to replace our implementations of these
> components entirely with their own implementations.
> * enhance the few configuration attributes that accept lazy lookups to
> accept `PatternLayout` patterns instead.
> 
> What do you think?
> 
> [1] 
> https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/Environment.html
> [2] 
> https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-properties-detailed.html
> [3] 
> https://download.eclipse.org/microprofile/microprofile-config-3.0/microprofile-config-spec-3.0.html#configprovider



Re: Redundant abstractions: property sources, lookups and pattern converters

2024-07-17 Thread Piotr P. Karwasz
Hi Matt,

On Wed, 17 Jul 2024 at 19:03, Matt Sicker  wrote:
> I’ll note one design constraint behind property sources and lookups. Property 
> sources are defined in the API while lookups are defined in Core.

Since Log4j Core 3 has a different properties system, property sources
are technically defined in the API, but are almost unused in the API.
They are only used:

1. For the `log4j.provider` property[1],
2. For the `SimpleLoggerContext` and related classes[2].

Status logger since 2.23.0 does not depend on `PropertiesUtil`[3].
The remaining properties (including the configuration of
`ThreadContextMap`) are used in Log4j Core. In this way Log4j Core 3
can have its own properties system.

> Besides that, property sources are intended for use with configuration 
> (either for components outside the config file or for reuse in a config file) 
> while lookups are intended for use with log events, though the ability to use 
> properties in log events makes this confusing.

Most lookups don't really profit from the `LogEvent` parameter[4] and
those that do, have a corresponding `PatternConverter`.

Piotr

[1] 
https://logging.staged.apache.org/log4j/2.x/manual/systemproperties.html#properties-log4j-api
[2] https://logging.staged.apache.org/log4j/2.x/manual/simple-logger.html#config
[3] 
https://logging.staged.apache.org/log4j/2.x/manual/status-logger.html#properties
[4] https://logging.staged.apache.org/log4j/2.x/manual/lookups.html#collection


Re: Redundant abstractions: property sources, lookups and pattern converters

2024-07-17 Thread Ralph Goers



> On Jul 17, 2024, at 3:09 AM, Piotr P. Karwasz  wrote:
> 
> Hi Ralph,
> 
> On Tue, 16 Jul 2024 at 15:17, Ralph Goers  wrote:
>>> * we have a `SpringLookup` and a `SpringPropertySource`.
>> 
>> SpringLookup returns the value of a key. A property source locates a set of 
>> keys. So comparing them is apples to oranges. Or rather - an apple to a 
>> bushel of apples. PropertySources are NOT available to the logging 
>> configuration. However, a Lookup can certainly use a PropertySource to 
>> locate the keys it is to resolve.
> 
> Yes, property sources can not be addressed directly, since they are
> not namespaced, as you remark below.
> Other than that lookups and property sources are pretty similar: the
> `forEach()` methods of property sources are only useful for caching
> and I am not sure caching dozens of not Log4j related properties is
> useful.
> 
>>> * we have a `${date:...}` lookup and a `%d{...}`. Note that
>> 
>>> `$${date:...}` and `%d{...}` give the same result in a
>>> `PatternLayout`!
>> 
>> While they do in the Layout they do not have the same behavior when used in 
>> the FilePattern on a Rolling Appender.
> 
> Good point, I have a note about that in the revamped
> RollingFileAppender description.
> 
> Although `$${date:...}` and `%d{...}` are not equivalent for
> `filePattern`, I don't see a reason for users to use the former.
> A file pattern like `$${date:-MM}/%d{-MM-dd}.log` that I often
> see in user questions, simply doesn't do what the user wants. The
> `2024-06-30.log` file ends up in the `2024-07` folder!
> The user should use `%d{-MM}/%d{-MM-dd}.log`, which works
> correctly since 2012 according to Git.

Really? It only has a 50% chance of being correct as only one of those can be 
used to determine the rollover interval. As I said, this should be changed so 
that the rollover interval is in a separate attribute.


> 
>> IMO, it was a poor decision to use the data in the file pattern to determine 
>> the rollover interval.
> 
> I share the same opinion. Autodetection is very useful for simple
> cases, but we might want to add a `frequency` config attribute to
> allow users to override autodetection.
> 
> Same thing applies to the autodetection of compress actions: users
> might want to configure those explicitly, e.g., if they want to
> configure the compression level and other parameters.
> 
>>> ## Equivalent concepts in other frameworks
>>> 
>>> Spring Boot's equivalent of both `PropertiesUtil` and `Interpolator`
>>> is the single `Environment`[1] concept:
>> 
>> However, Spring’s variables are primarily used while configuring the 
>> application. The same is true with PropertySources. OTOH Lookups are meant 
>> to be used while the application is running.
> 
> If we exclude RoutingAppender, most lookups are used at configuration
> time. Less than 10 attributes accept lookups at runtime. I have
> documented them all recently:
> 
> https://logging.staged.apache.org/log4j/2.x/manual/configuration.html#lazy-property-substitution

Any sentence that starts with “If we exclude…” means you want to break those 
things being excluded.

> 
>>> What do you think?
>> 
>> I am not convinced.
>> 
>> The advantage with Lookups is that they can be namespaced. i.e. 
>> ${ctx:myKey}. This is a nice short way of expressing which Map you want to 
>> look in. Specifying ${myKey} would require merging all the Maps together.
> 
> Namespacing can be both an advantage and a disadvantage:
> 
> * you don't want ephemeral context data to pollute the global
> namespace, so `${ctx:myKey}` is necessary. However in many places
> (like the `pattern` of a `Routes`) component, it could be replaced by
> `%X{myKey}`.
> * often users are startled by the necessity of adding a namespace,
> e.g. `${sys:myKey}`, especially if the migrate from Log4j 1.
> The `sys` and `env` lookups should often be used together, e.g.
> `${sys:myKey:-${env:myKey}}`. This would be much simpler if we remove
> the namespace.

There are better ways to deal with this than dumping namespaces entirely. For 
example, creating a lookup that is an alias for the system property lookup 
followed by the environment lookup. Or a dynamic way to create a new lookup by 
listing the lookups you want to include and their order.

> 
>> I am not a fan of making either of these pluggable. Making StrSubstitutor 
>> pluggable is a security risk. PropertiesUtil is pluggable by way of custom 
>> PropertySources.
> 
> It is a security risk, but it is not **our** security risk.
> If we make `StrSubstitutor` pluggable and Spring decides to use its
> SpEL processor to evaluate configuration attributes, it is up to them
> to make sure it is secure.

Uhh, no. It will be OUR security risk for opening this up to allow people to do 
stupid stuff (just like we did). 


> 
> The advantage of delegating string interpolation and configuration
> properties to the runtime environment is that users will have a
> coherent experience.
> Right now SpringPropertySo

Re: Redundant abstractions: property sources, lookups and pattern converters

2024-07-17 Thread Ralph Goers



> On Jul 17, 2024, at 2:11 PM, Piotr P. Karwasz  wrote:
> 
> Hi Matt,
> 
> On Wed, 17 Jul 2024 at 19:03, Matt Sicker  wrote:
>> I’ll note one design constraint behind property sources and lookups. 
>> Property sources are defined in the API while lookups are defined in Core.
> 
> Since Log4j Core 3 has a different properties system, property sources
> are technically defined in the API, but are almost unused in the API.
> They are only used:
> 
> 1. For the `log4j.provider` property[1],
> 2. For the `SimpleLoggerContext` and related classes[2].
> 
> Status logger since 2.23.0 does not depend on `PropertiesUtil`[3].
> The remaining properties (including the configuration of
> `ThreadContextMap`) are used in Log4j Core. In this way Log4j Core 3
> can have its own properties system.
> 
>> Besides that, property sources are intended for use with configuration 
>> (either for components outside the config file or for reuse in a config 
>> file) while lookups are intended for use with log events, though the ability 
>> to use properties in log events makes this confusing.
> 
> Most lookups don't really profit from the `LogEvent` parameter[4] and
> those that do, have a corresponding `PatternConverter`.

Conversely, most PatternConverters are only useful in a log event. Allowing 
them to be used outside of one would be awful. The only exception that comes to 
mind is the DateConverter.

Ralph