Console contains an invalid element or attribute "JsonTemplateLayout" even after adding dependency
Asked Answered
M

2

0

Below is my log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="JsonAppender" target="SYSTEM_OUT">
            <JsonTemplateLayout eventTemplateUri="classpath:LambdaJsonLayout.json" />
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="JsonLogger" level="INFO" additivity="false">
            <AppenderRef ref="JsonAppender"/>
        </Logger>
        <Root level="info">
            <AppenderRef ref="JsonAppender"/>
        </Root>
    </Loggers>
</Configuration>

and below is my pom.xml. I have added the log4j-layout-template-json dependency and tried the different versions. It works fine locally, however when deployed to lambda, the cloudwatch error shows Console contains an invalid element or attribute "JsonTemplateLayout". Appreciate any help.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <version>1.0.3</version>
    <name>ServiceLambda</name>
    <description>Service Lambda</description>

    <properties>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <log4j.version>2.19.0</log4j.version>
        <aws.powertools.version>1.12.2</aws.powertools.version>
    </properties>

    <dependencies>
        <!-- Exclude Spring Boot's Default Logging -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Add Log4j2 Dependency -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>2.6.6</version>
        </dependency>

        <dependency>
            <groupId>software.amazon.lambda</groupId>
            <artifactId>powertools-logging</artifactId>
            <version>${aws.powertools.version}</version>
        </dependency>
        <dependency>
            <groupId>software.amazon.lambda</groupId>
            <artifactId>powertools-sqs</artifactId>
            <version>${aws.powertools.version}</version>
        </dependency>
        <dependency>
            <groupId>io.github.crac</groupId>
            <artifactId>org-crac</artifactId>
            <version>0.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws.serverless</groupId>
            <artifactId>aws-serverless-java-container-springboot2</artifactId>
            <version>1.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>dynamodb</artifactId>
            <version>2.17.292</version>
            <exclusions>
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>netty-nio-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>apache-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>aws-crt-client</artifactId>
            <version>2.17.282-PREVIEW</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-layout-template-json</artifactId>
            <version>2.18.0</version>
        </dependency>
        <!-- OpenAPI docs -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.6.14</version>
        </dependency>

        <!-- Test dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.4.0</version>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                    <filters>
                        <filter>
                            <artifact>*:*</artifact>
                            <excludes>
                                <exclude>**/Log4j2Plugins.dat</exclude>
                            </excludes>
                        </filter>
                    </filters>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <artifactSet>
                                <excludes>
                                    <exclude>org.apache.tomcat.embed:*</exclude>
                                </excludes>
                            </artifactSet>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.14.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <complianceLevel>1.8</complianceLevel>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>software.amazon.lambda</groupId>
                            <artifactId>powertools-logging</artifactId>
                        </aspectLibrary>
                        <aspectLibrary>
                            <groupId>software.amazon.lambda</groupId>
                            <artifactId>powertools-sqs</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

enter image description here

Misti answered 24/3, 2023 at 23:18 Comment(0)
A
0

Your problem is a variation of the recurrent "Maven Shade Plugin breaks Log4j2" problem (cf. this SO question or this Github question).

This is caused by this configuration snippet:

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                ...
                <configuration>
                    <filters>
                        <filter>
                            <artifact>*:*</artifact>
                            <excludes>
                                <exclude>**/Log4j2Plugins.dat</exclude>
                            </excludes>
                        </filter>
                    </filters>
                </configuration>
                ...
            </plugin>

Although this "solution" often appears in SO answers, it breaks the main (and fastest) plugin detection mechanism used by Log4j 2.x. This causes Log4j 2.x to fall back onto a (much slower) package scanning mechanism that detects only the plugins in log4j-core. That is why JsonTemplateLayout is not detected.

Solution (edited): Since you are using spring-boot-starter-parent as project's parent, just drop the maven-shade-plugin and add the spring-boot-maven-plugin to the build:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

The spring-boot-maven-plugin configuration you inherit from the parent POM performs the same job as the maven-shade-plugin but does not break apart dependency JARs (cf. executable JAR format).

Alby answered 27/3, 2023 at 9:0 Comment(3)
Removing just the execution tag does not log any messages at all.Misti
Thanks @Piotr, do you mean to say, drop the entire plugin or drop just the execution tags from that plugin. Dropping the entire plugin starts giving error as below: Error loading class com/amazonaws/serverless/exceptions/ContainerInitializationException: java.lang.NoClassDefFoundError java.lang.NoClassDefFoundError: com/amazonaws/serverless/exceptions/ContainerInitializationException at java.base/java.lang.Class.forName0(Native Method) at java.base/java.lang.Class.forName(Unknown Source) Caused by: java.lang.ClassNotFoundExceptionMisti
@VaibhavDhore: sorry, I didn't notice that the spring-boot-maven-plugin was not added by default to the build. I edited the solution accordingly.Alby
R
0

So the answer by Piotr P. Karwasz is not necessarily wrong but I would say is incomplete as far as what needs to be corrected. It is more a statement of what is wrong or highly specific to Spring than what is necessary to fix the issue. He is correct in saying that using shadowJar and log4j2 does not work correctly and falls back to a much simpler version of logging and while adding in the <exclude>**/Log4j2Plugins.dat</exclude> does change the operation is not sufficient to correct the issue.

Fixing the issue in Gradle

If you are using a gradle build in the main build.gradle add the following import

import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer

and update your shadowJar block as follows

shadowJar {
    transform(Log4j2PluginsCacheFileTransformer)
}

My understanding is this is more or less performing the same task as the previously discussed exclude but with some additional corrective action.

The original post that helped me understand this is here.

Note: It is important that the shadowJar block is in the "main" build.gradle file. For some reason if you try to place this in a sub *.gradle file and apply it to the main build the import does not work correctly and the transform will not be applied

Fixing the issue in Maven

I have not personally tested this way but you can find discussion on how to do the same in maven here (this also discusses the above solution). In this case add the following imports

<dependencies>
  ...
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-log4j2</artifactId>
    <version>1.5.1</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.1</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
  </dependency>
  ....
</dependencies>

and add the following transformation

<plugins>
  ...
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.4.3</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
            <transformer
                    implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer">
            </transformer>
          </transformers>
        </configuration>
      </execution>
    </executions>
    <dependencies>
      <dependency>
        <groupId>com.github.edwgiz</groupId>
        <artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
        <version>2.8.1</version>
      </dependency>
    </dependencies>
  </plugin>
  ...
</plugins>

Other related posts

Rig answered 13/7, 2023 at 16:54 Comment(2)
The "exclude" solution is not a solution, because it removes all plugin caches. Your solutions are the correct way to shade Log4j2 in Gradle/Maven: they merge the plugin caches. Remark that edwgiz donated its plugin to Log4j: here are the new coordinatesAlby
Thanks for following up :DRig

© 2022 - 2024 — McMap. All rights reserved.