Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load pre-loaded lookups via SPI, rather than hard-code in Interpolator. #396

Closed
wants to merge 4 commits into from

Conversation

tbwork
Copy link

@tbwork tbwork commented Aug 10, 2020

test custom lookup

fix

support custom lookup
@tbwork
Copy link
Author

tbwork commented Aug 10, 2020

What's wrong with the CI? The change should have nothing to do with the error. :)

@jvz
Copy link
Member

jvz commented Aug 10, 2020

No worries about the Travis check. The GitHub Actions checks are the important ones. We need to disable our old Travis checks.

@rgoers
Copy link
Member

rgoers commented Aug 10, 2020

The only concern I have with this is the overhead of ServiceLoader during startup. I recently had to make ServiceLoader run asynchronously during startup while loading Custom ThreadContextDataProviders. This will likely cause the same problem. We should make that more generic so that components such as them can register their service for asynchronous initialization. But that would be done in a different PR.

Copy link
Member

@jvz jvz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might make more sense being named something like ServiceLookup as it specifically queries service providers. Custom sounds too generic.

@rgoers
Copy link
Member

rgoers commented Aug 10, 2020

@jvz I dislike ServiceLookup as it is describing its implementation method, not its purpose, which is to allow a way for users to hook into a Lookup that is configured to run before any standard plugins have been processed.

Perhaps that is an indication that the mechanism provided here is incorrect. Perhaps the service loader should be looking for Lookup Plugins that are also declared as services. We could replace the way all these lookups are loaded if we do that.

Copy link
Member

@rgoers rgoers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my previous comment. The more I think about this the more it seems all the pre-loaded Lookups should be loaded via ServiceLoader. So custom Lookups that want to be included in this list would just register themselves as services.

@tbwork
Copy link
Author

tbwork commented Aug 10, 2020

@rgoers Agree! This PR is intended to do that as you proposed. Hope this could be supported ASAP :) . Have a nice day.

@tbwork
Copy link
Author

tbwork commented Aug 10, 2020

@rgoers Do you mean all the pre-loaded Lookups should be loaded via ServiceLoader? I am glad to contribute to this part if you do not mind. :)

@rgoers
Copy link
Member

rgoers commented Aug 10, 2020

Yes, that is exactly what I mean. Feel free to modify this PR to do that. In essence, StrLookup would become the service interface and every plugin to be pre-loaded would be listed in the services file instead of hard coded in Interpolator.

@tbwork
Copy link
Author

tbwork commented Aug 11, 2020

@rgoers ok.

@tbwork
Copy link
Author

tbwork commented Aug 11, 2020

@jvz @rgoers It seems the Log4jPlugins class is moved from org.apache.logging.log4j.core.plugins. However in Activator class, Log4jPlugins is still imported as "org.apache.logging.log4j.core.plugins.Log4jPlugins".

Copy link
Author

@tbwork tbwork left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes are reviewed by Tommy.Tesla.

@tbwork tbwork marked this pull request as draft August 12, 2020 04:07
@tbwork tbwork changed the title support custom strlookup Reconstruct lookup load mechanism from plugin mode to SPI mode. Aug 12, 2020
@tbwork tbwork marked this pull request as ready for review August 12, 2020 04:10
@tbwork
Copy link
Author

tbwork commented Aug 14, 2020

@rgoers @jvz Hi, are you busy? Could you get round to take a review and merge :).

// JNDI check
try {
// [LOG4J2-703] We might be on Android
Loader.newCheckedInstanceOf("org.apache.logging.log4j.core.lookup.JndiLookup", StrLookup.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is trying to load itself here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah, my fault. Your r right. How about just removing them? It is not necessary in terms of SPI mode.


try {
// docker check.
Loader.newCheckedInstanceOf("org.apache.logging.log4j.docker.DockerLookup", StrLookup.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks are attempting to load the class they're in. They won't load properly when SystemLoader.load() tries to load the class itself due to the static references to optional classpath code. This check you've added is only useful for code outside this exact file. The same goes for the other classes you've added these to.

}

KubernetesLookup(Pod pod, Namespace namespace, URL masterUrl) {
this.pod = pod;
this.namespace = namespace;
this.masterUrl = masterUrl;

try {
Loader.newCheckedInstanceOf("org.apache.logging.log4j.kubernetes.KubernetesLookup", StrLookup.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@@ -40,9 +40,21 @@
private static final Pattern DEFAULT_PATTERN = Pattern.compile(DEFAULT + PATTERN);

public SpringLookup() {
try {
//Spring check.
Loader.newCheckedInstanceOf("org.apache.logging.log4j.spring.cloud.config.client.SpringLookup", StrLookup.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

super();
if (Constants.IS_WEB_APP) {
try {
Loader.newCheckedInstanceOf("org.apache.logging.log4j.web.WebLookup", StrLookup.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

// JMX check
try {
// We might be on Android
Loader.newCheckedInstanceOf("org.apache.logging.log4j.core.lookup.JmxRuntimeInputArgumentsLookup",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

/*
* Comparator for ordering pure StrLookup instances by priority.
*/
new Comparator<AbstractPureLookup>(){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use a lambda.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rogar that.

import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No star imports please!

Copy link
Author

@tbwork tbwork Aug 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rogar that. Get your point! It is an auto action did by IDEA, I've turn up the count. Thanks.

import org.apache.logging.log4j.core.lookup.MapLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.lookup.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No star imports please!

*
* Use to resolve those variables without prefix.
*
* @author tommy.tesla
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use the @author tag in javadoc.

* @author tommy.testla
* @since 3.0.0
*/
public interface BuiltInLookupCategory {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things about this:

  1. We do not use interfaces for holding string constants; we use a public final class with public static final constants and a private constructor. Using interfaces this way is an anti-pattern.
  2. Due to how you've refactored these to be dynamically looked up via services, these constants are only referenced in their respective classes now. There's no reason to factor out the constants at this point.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, got it.

@rgoers
Copy link
Member

rgoers commented Aug 15, 2020

These changes are not what I expected. All the Lookups should remain plugins. You should have only had to modify Interpolator to load the required lookups via ServiceLoader and then added the Lookups you wanted to load to the file used by ServiceLoader. The Lookups would be loaded again as normal as Plugins during configuration.

@tbwork
Copy link
Author

tbwork commented Aug 17, 2020

@rgoers I propably misunderstood your opinion:

In essence, StrLookup would become the service interface and every plugin to be pre-loaded would be listed in the services file instead of hard coded in Interpolator.

I guess following is what you want:

  1. Load all lookups as plugins via SPI.
  2. Load all lookup plugins via the plugin mechanism.

Is it right ?

@tbwork tbwork changed the title Reconstruct lookup load mechanism from plugin mode to SPI mode. Load pre-loaded lookups via SPI, rather than hard-code in Interpolator. Aug 17, 2020
@tbwork
Copy link
Author

tbwork commented Aug 17, 2020

@rgoers Hi, rgoers. After debuging and reading the log4j2 codes, I realize that the public Interpolator(final Map<String, String> properties) is called several times during factory creation stage. Is that reasonable to create so many StrLookup instances with the same type?

@rgoers
Copy link
Member

rgoers commented Aug 17, 2020

Well, the Interpolator constructor that has the hard-coded list of lookups is initializing the lookups that could be using while constructing the configuration. The other lookups would be used at runtime. There is no reason that I can think of that all the Lookups couldn't be initialized once via ServiceLoader except that it would break compatibility with users who have created their own Lookups as plugins. We could possibly load the serviceloader Lookups once and then add the ones defined as plugins later.

@vy vy deleted the branch apache:master February 28, 2023 15:02
@vy vy closed this Feb 28, 2023
@ppkarwasz
Copy link
Contributor

This was closed automatically by Github because we renamed the release-2.x branch to 2.x. Feel free to resubmit to the 2.x branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants