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

WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance. #204

Closed
wolkenschieber opened this issue Dec 16, 2020 · 8 comments
Labels

Comments

@wolkenschieber
Copy link

wolkenschieber commented Dec 16, 2020

When spinning up a Lambda with Java 11 and log4j2 logging, the first message is

WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.

This probably is induced by log4j2.

My logging depencies are

	<dependencies>
		<dependency>
			<groupId>com.amazonaws</groupId>
			<artifactId>aws-lambda-java-log4j2</artifactId>
			<version>1.2.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>2.14.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.14.0</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.30</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-slf4j-impl</artifactId>
			<version>2.14.0</version>
		</dependency>
	</dependencies>

The shade configuration is

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
				<version>3.2.4</version>
				<configuration>
					<createDependencyReducedPom>false</createDependencyReducedPom>
					<filters>
						<filter>
							<artifact>*:*</artifact>
							<excludes>
								<exclude>META-INF/*.SF</exclude>
								<exclude>META-INF/*.DSA</exclude>
								<exclude>META-INF/*.RSA</exclude>
							</excludes>
						</filter>
					</filters>
				</configuration>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>shade</goal>
						</goals>
						<configuration>
							<transformers>
								<transformer
									implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
									<manifestEntries>
										<Multi-Release>true</Multi-Release>
									</manifestEntries>
								</transformer>
								<transformer
									implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
								<transformer
									implementation="com.github.edwgiz.maven_shade_plugin.log4j2_cache_transformer.PluginsCacheFileTransformer">
								</transformer>
							</transformers>
						</configuration>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>com.github.edwgiz</groupId>
						<artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
						<version>2.14.0</version>
					</dependency>
				</dependencies>
			</plugin>
@dankirkd
Copy link

dankirkd commented Aug 30, 2021

@msailes Can we get an official response on this question? Is there an upcoming change that will address it? Thanks.

@dankirkd
Copy link

I've seen this online at https://stackoverflow.com/a/67976381/7174346

According to my AWS account rep, AWS Lambdas do not support Multi-Release JARs at this time (2021-06-14)

Can someone please confirm?

@msailes
Copy link
Collaborator

msailes commented Jan 7, 2022

Hi @wolkenschieber, @dankirkd ,

From the developer guide

Lambda loads JAR files in Unicode alphabetical order. If multiple JAR files in the lib directory contain the same class, the first one is used. You can use the following shell script to identify duplicate classes:

mkdir -p expanded
unzip path/to/my/function.zip -d expanded
find ./expanded/lib -name '*.jar' | xargs -n1 zipinfo -1 | grep '.*.class' | sort | uniq -c | sort

Mark

@msailes msailes closed this as completed May 13, 2022
@eirikbakke
Copy link

What is the solution here, if Multi-Release cannot be used? What is the correct way to get rid of this warning message?

@shivamtiwari18
Copy link

using Graylog version 5 + java 11 = WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.

showing the same issue
Is their any issue with the java version with graylog 5.

@loveyang2012
Copy link

spinning up a Lambda with Java 11 and log4j2 logging, t

me too, have you gotten any soution?

@garretwilson
Copy link

garretwilson commented Jun 5, 2023

Here's what's happening. (See LOG4J2-2537: Log4j 2 Performance issue with Java 11 for more back-story.) Log4J uses a org.apache.logging.log4j.util.Stackwalker to walk up the stack. The old version uses sun.reflect.Reflection.getCallerClass(int). Here's an excerpt from the old pre Java 9 Stackwalker source code:

… the JDK team agreed to restore getCallerClass(int) and keep its existing behavior for the rest of Java 7. However, the method is deprecated in Java 8, and current Java 9 development has not addressed this API. Therefore, the functionality of this class cannot be relied upon for all future versions of Java. It does, however, work just fine in Sun JDK 1.6, OpenJDK 1.6, Oracle/OpenJDK 1.7, and Oracle/OpenJDK 1.8. Other Java environments may fall back to using Throwable#getStackTrace() which is significantly slower due to examination of every virtual frame of execution.

I infer that the new Java 9+ version of Log4j Stackwalker sidesteps the whole issue of sun.reflect.Reflection.getCallerClass, but doesn't work with earlier Java versions, so they created a multi-release JAR. (See JEP 238.) Unfortunately even if you use <Multi-Release>true</Multi-Release> in your Maven Shade ManifestResourceTransformer configuration, AWS Lambda doesn't know how to deal with multi-release JARs. See AWS Lambda using incorrect classfiles from a Multi-Release JAR?

Basically in the multi-release JAR there is a META-INF/versions/9/ directory, under which is kept the Java 9+ version of Stackwalker and related classes, which don't use sun.reflect.Reflection.getCallerClass. If you're targeting Java 9+ you can do what the JVM would do and use these classes rather than the ones not inside META-INF/. The Maven Shade Plugin doesn't seem to have a way to do this manually, but it appears you can brute-force the issue by (mis?)using the Maven Shade Plugin <relocations> facility to copy over the version under META-INF/versions/9/, overwriting the old ones that use sun.reflect.Reflection.getCallerClass. One other trick: specify a fuller path to the classes, so you won't copy over the metadata file under META-INF/versions/9/ itself.

Thus it appears (after limited testing) that adding the following to your Maven Shade Plugin <configuration> section will produce a JAR using the Java 9+ version of Stackwalker, which doesn't even look for sun.reflect.Reflection.getCallerClass, thus preventing the warning:

<relocations>
  <relocation>
    <pattern>META-INF/versions/9/org/apache/logging/log4j/</pattern>
    <shadedPattern>org/apache/logging/log4j/</shadedPattern>
  </relocation>
</relocations>

Using this technique, you can remove the <Multi-Release>true</Multi-Release> of your ManifestResourceTransformer, because there's no point in making a multi-release JAR anymore, as you're manually creating a single-release JAR with the Java 9+ content.

Note that this is more important than just preventing the warnings. Apparently no one realized that following the AWS docs and using Log4j with the Maven Shade Plugin was leaving everyone using Java 9+ with old pre-Java 9 versions of some Log4j classes.

The AWS Lambda Power Tools team is considering using the SLF4J API directly instead of requiring Log4j (see aws-powertools/powertools-lambda-java#965) so hopefully that effort gets some traction. Unfortunately that won't help those who are using Log4j with com.amazonaws:aws-lambda-java-log4j2. And it doesn't address the larger problem that AWS Lambda doesn't support multi-release JARs.

@smirnoal
Copy link
Contributor

smirnoal commented Jun 6, 2023

there's a note in public docs about how to deploy multi release jars to lambda: https://docs.aws.amazon.com/lambda/latest/dg/java-package.html

search for MRJAR there

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

No branches or pull requests

8 participants