[ 
https://issues.apache.org/jira/browse/LOG4J2-952?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14718315#comment-14718315
 ] 

Bart S. commented on LOG4J2-952:
--------------------------------

Pff. Confusing, everything. I think the assembler solution you have arrived at 
is confusing in any case... :(.

One, thing, first:

The change from {{get}} methods to {{new}} methods is the best one you have 
suggested, Gary! That feels really good. Indeed they are all factory or 
construction things.

Look, I am not much a fan of the "Builder" pattern because I'm not much fan of 
_patterns_. Whenever someone talks about "design patterns" I try to run away as 
far as I can because it kills me, it kills the vibe, it kills the spirit. 
Programming is fun and creative, but these patterns are boring and reactive. 
They seem to think or agree that there is a set way of doing things, when 
creativity is the opposite of that.

So I agree with ralph  that you have to think outside of the box and feel what 
feels right for you.

The problem I have with your solution Gary to not call {{.assemble()}} 
yourself, is that you have an object that is half finished; by using 
compositing assemblers; it is exposed ANYWAY. You either choose NOT to expose 
them (and not have to deal with assemble() calls at all in the public 
interface) or you choose to expose them and complete the assembling/building.

Because what happens if a user does call assemble() even when it is not 
intended? Are you going to make it protected? That will make it even more ugly.

Like I've said before [in 
LOG4J2-1095|https://issues.apache.org/jira/browse/LOG4J2-1095] I feel the only 
right way is to use specifications. I also don't like the "factory" pattern as 
a must for doing things. Why a factory? Why these factories everywhere? Java is 
littered with them. And with "impl" classes and methods. I do not understand 
that. My mind is very intuitive and it does not understand that. It will have 
to _learn_ that, it does not come of itself, because it is not truth.

I think you should have a very good reason for using a factory, if you don't 
have it, don't use it. The Log4J framework uses factories in one of these ill 
places for which there is not really a good reason (other than conforming to 
the pattern). So you have to work with that which makes any solution that 
actually is really elegant, it has to become less elegant to fit in, or rather, 
in order to harmonize it has to fit the existing model.

Not wanting to insult the framework here ;-).

So when I see this API and IMPL packages I immediately get scared and want to 
run away ;-). And it becomes incomprehensible to me.

Because it's just a pattern that someone made up for no good reason. (The worst 
is the _anti_patterns. People who start to discuss everything people do WRONG; 
how insightful, how constructive, how embellishing, how nurturing!). I guess 
I'm one of those now, I'm anti-patterning the anti-pattern :P.

Anyway, let's see if Gary made more good comments.

Assembler vs. Builder. You see we are in a pinch because you can feel and Ralph 
does feel likely and apparently and perhaps obviously (so) that the builder 
'pattern' in itself might not be suitable.

There is really very little reason, for instance, to actually make a Builder 
interface. How many times do you really need to pass abstract builder instances 
around? That you type with generics?. I mean generic builder instances that 
implement some master interface? It is a bit weird and redundant. The only 
purpose such an interface really has is to "designate it as a pattern use 
case". It's a signature, nothing more, but not for the compiler, but for the 
programmer who cares about these things. From a functional perspective it's a 
bit superfluous. Much like generics itself, it's not very functional for the 
execution of actual programming code. If an apple falls from the tree and lands 
on my head, I do not care about what some God has written about how apples 
/should/ fall, I only care about the fact that it bounces off and I can eat it.

So we are like researching, you and I, and Ralph mostly with the code he has 
written, which is of course very instructive perhaps only how not to do it ;-) 
but in any case it is something that makes everything clearer, as he said to me 
when he wanted me to write real code in the emails or that he would like to 
write real code instead of only debating.

So the code is a great advancement, that at first. So thank you people in any 
case :).

And I know I'm probably a turd in saying these things and an arrogant asshole, 
but still.

When I devised my idea for Behrooz or what's his name's existing code offering 
I was not all that happy about SpecificationBuilder.newAppenderSpecBuilder() 
either of course. That's the compositing thing.

I was hinting at SpecificationBuilder.addAppender(real, parameters, for, that, 
thing) without any compositing taking place, or even 
SpecificationBuilder.addAppender("name).setParam().setParam();, which is still 
the best thing I have come up with, even if it is incongruent or even a bit 
dissonant with itself.

You see {{SpecificationBuilder.addAppender()}} would result a 
AppenderSpecBuilder -- what would happen is this:.

- addAppender registers the new SpecBuilder(of type Appender)
- the registered object takes new values from its setParam or addAttribute or 
whatever methods
- there is never any build method called on the thing because there is no build 
method or perhaps it is hidden; in any case when the specification is processed 
it is checked for incomplete objects (mandatory arguments) and such; this is at 
the time probably of creating the Configuration; by the factory that receives 
the specification. It could also be earlier but I would think validation is 
best when it is actually used.

Here is the key: by using a thing like this, we are using a more scripting 
approach than a compile-type-thing approach. Even the regular config files for 
Log4J are a scripting approach; they are validated when used, not at "compile 
time" (when you write the spec in your text editor). It is important to 
understand that an XML file is also a SPEC.

And the Node Tree that results from it is also a SPEC.

And the configuration that results from it (it is created now with {{start()}} 
but I really think THAT is TOO late, but that aside for now) --- why should 
START be the thing that CREATES? It makes no sense really..... 

but if the solution has to fall within THAT system, it would probably be 
suboptimal from a good user's point of view.

Everything is intertwined and the 'feel' of one part of the system is going to 
be the same as the feel of another part in the system, because the system has 
to function as a whole. If there are important architectural constraints that 
dictate that within the system the "best" solution is to make use of those 
methods (like start()) but if those constraints are not of a high 
energy/frequency/faith/trust/belief/truth/nature if those constraints are not 
as beautiful or as pretty (goes the asshole again ;-)) it means...

Just saying that you have to work with what you have but what you have might 
render anything you create suboptimal or not elegant from a user point of view 
or even a developer point of view.

Because it also has to harmonize with the system that is.
----

I would make the following suggestions:

# If you break away from the idea or requirement or truth that the 
Configuration is to be actually constructed and composed (including all of its 
objects) at START time, and towards the idea that all of it is constructed at 
CREATE time (e.g. by its factory) then you will end up seeing a better solution 
and the end solution you arrive at will be more elegant and more useful to a 
user actually using this thing.

Because simply put, this design choice favours any type of solution that chimes 
in with the existing XML-to-Node hierarchy and quite puts any other kind of 
solution at a disadvantage.
To make it even unworkable.

I don't mind creating a solution of my own, as indicated, if only for 
exploration and study but it might take a bit of time as I don't understand the 
system very well but it could at least be a proof of concept as to what I say, 
but I need to get my system in working order again in any case first :(.

I believe the power of Ralph is that he just transforms the programmatic thing 
into ' XML ' and that means he can address every possible object, class, 
configuration and type of objects, appenders, etc., with very little code.

Anything I could write would probably require support for every single class 
unless I can find a way around that (perhaps by generating code).

And it's clear I don't know enough about the system to do that, which is also 
why I have been holding back.

So that's recommendation number one: ensure that the Configuration can be 
created fully at create time if you want this to be good. I'm not even sure if 
that is possible.

Next I believe it is still possible to turn it into more of a fluid code. 
Fluent code. You can still let assembler methods return all an assembler 
themselves. Makes for prettier code.

So to recap, key points:

- we are talking about SPECs
- coding is script-like rather than compile-like
- new is better than get
- a specification is processed by a factory that puts out objects
- a start method should really not construct any objects (???????).
- once you have a configuration you should be able to manipulate its objects
- it should be possible to maintain multiple configurations independently and 
by hand
- it should be possible to install new configurations with ease
- the flow from object to object needs to improve, because there are too many 
entry-points to the code
- there are too many objects that perform a function of control, without there 
being a path from the one to the other
- I personally always prefer to store even a single important object in my 
application and use it to access every other important object, but perhaps 
that's just me.
- libraries should not be dealing with these important objects anyway, as they 
need to abstract away from the logging framework used
- even if they do not abstract away, they still need to abstract away from 
using these control objects, as it should be the application that's in control, 
not the library
- it would not be bad if the library could on the other hand indicate a kind of 
default configuration (in terms of levels, perhaps)
- that configuration would probably be some kind of default config file for the 
library (like a cascading system of config files?........ dunno?.........).
- unless the library really has its own logging facility it should be up to the 
application to configure and start?.
- I think SLF4J is a shameless plug ;-).

I think it would be very powerful to have Configurations that you can install 
at will. Personally my only use case at this point is to change logger levels 
en masse according to a certain setup - that doesn't even require new appenders 
and such, and as such perhaps not even a new Configuration object. You might 
imagine a different kind of mapping from LoggerConfig to Level and you just 
install that LevelSetup into the configuration in the sense of 
Configuration.applyLevelScheme() or even Context.applyLevelScheme(). Thoughts? 
Is that a good idea?.... Perhaps too soon for it.

Anyway I need to break. I'll leave it at this for now. Regards.

> FAQ: How do I configure log4j2 programmatically in code without a 
> configuration file?
> -------------------------------------------------------------------------------------
>
>                 Key: LOG4J2-952
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-952
>             Project: Log4j 2
>          Issue Type: Bug
>          Components: API, Configurators, Documentation
>    Affects Versions: 2.1
>            Reporter: Joe Merten
>         Attachments: LOG4J2-952-2.patch, LOG4J2-952-3.patch, 
> LOG4J2-952-4.patch, LOG4J2-952.patch
>
>
> I found [this 
> link|http://logging.apache.org/log4j/2.x/faq.html#config_from_code] which 
> said:
> {quote}
> You could use the static method #initialize(String contextName, ClassLoader 
> loader, String configLocation) in 
> org.apache.logging.log4j.core.config.Configurator. (You can pass null for the 
> class loader.) Be aware that this class is not part of the public API so your 
> code may break with any minor release.
> {quote}
> This documentation is unclear because it points to a member function which 
> needs a filename {{configLocation}} where as the topic is »without a 
> configuration file«.
> It shoud rather point to the member function 
> {{org.apache.logging.log4j.core.config.Configurator.initialize(ClassLoader 
> loader, ConfigurationSource source)}}.
> Example:
> {code:java}
> import org.apache.logging.log4j.core.config.ConfigurationSource;
> import org.apache.logging.log4j.core.config.Configurator;
> final String hardCodedXmlConfig =
>         "<?xml version='1.0' encoding='UTF-8'?>\n" +
>         "<Configuration status='INFO'>\n" +
>         "  <Appenders>\n" +
>         "    <Console name='Console' target='SYSTEM_OUT'>\n" +
>         "      <PatternLayout pattern='%d{HH:mm:ss.SSS} [%t] %-5level 
> %logger{36} - %msg%n'/>\n" +
>         "    </Console>\n" +
>         "  </Appenders>\n" +
>         "  <Loggers>\n" +
>         "    <Root level='debug'>\n" +
>         "      <AppenderRef ref='Console'/>\n" +
>         "    </Root>\n" +
>         "  </Loggers>\n" +
>         "</Configuration>\n";
> try {
>     Configurator.initialize(null, new ConfigurationSource(new 
> ByteArrayInputStream(hardCodedXmlConfig.getBytes())));
> } catch (IOException e) {
>     e.printStackTrace();
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to