This is an automated email from the ASF dual-hosted git repository. pkarwasz pushed a commit to branch doc/2.x/webapp in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 4e18097e95da0cfd2c388fe58c3bc7511e3ba888 Author: Piotr P. Karwasz <[email protected]> AuthorDate: Tue Jun 25 16:15:47 2024 +0200 Revamp the `Web Applications` page (part 1) We update the `Web Applications` page by: * merging the `webapp.html`, `log4j-web.html`, `log4j-jakarta-web.xml` and `log4j-taglib.html` pages, * providing a table with all the initialization parameters, * moving the description of the web lookup and servlet appender to the right pages. --- log4j-jakarta-web/pom.xml | 1 + .../manual/appenders/servlet-appender.json | 23 ++ .../manual/appenders/servlet-appender.properties | 28 ++ .../examples/manual/appenders/servlet-appender.xml | 34 ++ .../manual/appenders/servlet-appender.yaml | 30 ++ .../ROOT/examples/manual/webapp/AsyncServlet.java | 59 +++ .../modules/ROOT/examples/manual/webapp/jndi.xml | 37 ++ .../modules/ROOT/examples/manual/webapp/web.xml | 50 +++ src/site/antora/modules/ROOT/nav.adoc | 1 + src/site/antora/modules/ROOT/pages/javadoc.adoc | 3 + .../modules/ROOT/pages/log4j-jakarta-web.adoc | 27 -- src/site/antora/modules/ROOT/pages/log4j-web.adoc | 27 -- .../modules/ROOT/pages/manual/appenders.adoc | 91 ++++- .../modules/ROOT/pages/manual/configuration.adoc | 8 +- .../antora/modules/ROOT/pages/manual/lookups.adoc | 77 ++-- .../antora/modules/ROOT/pages/manual/webapp.adoc | 400 +++++++++------------ .../manual/dependencies-log4j-1.2-api.adoc | 2 + ...pi.adoc => dependencies-log4j-jakarta-web.adoc} | 39 +- src/site/resources/.htaccess | 3 +- 19 files changed, 582 insertions(+), 358 deletions(-) diff --git a/log4j-jakarta-web/pom.xml b/log4j-jakarta-web/pom.xml index f3434f9f85..9dc6667611 100644 --- a/log4j-jakarta-web/pom.xml +++ b/log4j-jakarta-web/pom.xml @@ -32,6 +32,7 @@ <description>The Apache Log4j support for Jakarta EE 9+ web servlet containers</description> <properties> + <maven.javadoc.skip>false</maven.javadoc.skip> <!-- ~ OSGi and JPMS options diff --git a/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.json b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.json new file mode 100644 index 0000000000..dbcb98fa9f --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.json @@ -0,0 +1,23 @@ +{ + "Configuration": { + "Appenders": { + // tag::servlet[] + "Servlet": { + "name": "SERVLET", + "PatternLayout": { + "pattern": "%m%n", + "alwaysWriteExceptions": false // <1> + } + } + // end::servlet[] + }, + "Loggers": { + "Root": { + "level": "INFO", + "AppenderRef": { + "ref": "SERVLET" + } + } + } + } +} \ No newline at end of file diff --git a/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.properties b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.properties new file mode 100644 index 0000000000..b5537540fc --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.properties @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +## +# tag::servlet[] +appender.0.type = Servlet +appender.0.name = SERVLET +appender.0.layout.type = PatternLayout +appender.0.layout.pattern = %m%n +# <1> +appender.0.layout.alwaysWriteExceptions = false +# end::servlet[] + +rootLogger.level = INFO +rootLogger.appenderRef.0.ref = SERVLET diff --git a/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.xml b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.xml new file mode 100644 index 0000000000..e35402ece4 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to you under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<Configuration xmlns="https://logging.apache.org/xml/ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + https://logging.apache.org/xml/ns + https://logging.apache.org/xml/ns/log4j-config-2.xsd"> + <Appenders> + <!-- tag::servlet[] --> + <Servlet name="SERVLET"> + <PatternLayout pattern="%m%n" alwaysWriteExceptions="false"/> <!--1--> + </Servlet> + <!-- end::servlet[] --> + </Appenders> + <Loggers> + <Root level="INFO"> + <AppenderRef ref="SERVLET"/> + </Root> + </Loggers> +</Configuration> diff --git a/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.yaml b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.yaml new file mode 100644 index 0000000000..892fc58a35 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/appenders/servlet-appender.yaml @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Configuration: + Appenders: + # tag::servlet[] + Servlet: + name: "SERVLET" + PatternLayout: + pattern: "%m%n" + alwaysWriteExceptions: false # <1> + # end::servlet[] + Loggers: + Root: + level: "INFO" + AppenderRef: + ref: "SERVLET" diff --git a/src/site/antora/modules/ROOT/examples/manual/webapp/AsyncServlet.java b/src/site/antora/modules/ROOT/examples/manual/webapp/AsyncServlet.java new file mode 100644 index 0000000000..57fb03475f --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/webapp/AsyncServlet.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example; + +import javax.servlet.AsyncContext; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.web.Log4jWebSupport; +import org.apache.logging.log4j.web.WebLoggerContextUtils; + +@WebServlet(urlPatterns = "/async/*", asyncSupported = true) +public class AsyncServlet extends HttpServlet { + + private final Logger logger = LogManager.getLogger(); + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + // tag::manual[] + AsyncContext asyncContext = req.startAsync(); + Log4jWebSupport webSupport = WebLoggerContextUtils.getWebLifeCycle(getServletContext()); + asyncContext.start(() -> { + try { + webSupport.setLoggerContext(); + // Put your logic here + } finally { + webSupport.clearLoggerContext(); + } + }); + // end::manual[] + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) { + // tag::automatic[] + AsyncContext asyncContext = req.startAsync(); + asyncContext.start(WebLoggerContextUtils.wrapExecutionContext(getServletContext(), () -> { + // Put your logic here + })); + // end::automatic[] + } +} diff --git a/src/site/antora/modules/ROOT/examples/manual/webapp/jndi.xml b/src/site/antora/modules/ROOT/examples/manual/webapp/jndi.xml new file mode 100644 index 0000000000..10a71fb3c9 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/webapp/jndi.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to you under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" + version="5.0"> + <!-- tag::jndi[] --> + <context-param> + <param-name>isLog4jContextSelectorNamed</param-name> + <param-value>true</param-value> + </context-param> + <context-param> + <param-name>log4jContextName</param-name> + <param-value>your_application_name</param-value> + </context-param> + <env-entry> + <env-entry-name>log4j/context-name</env-entry-name> + <env-entry-value>your_application_name</env-entry-value> + <env-entry-type>java.lang.String</env-entry-type> + </env-entry> + <!-- end::jndi[] --> +</web-app> diff --git a/src/site/antora/modules/ROOT/examples/manual/webapp/web.xml b/src/site/antora/modules/ROOT/examples/manual/webapp/web.xml new file mode 100644 index 0000000000..9c4fdf6db9 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/webapp/web.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to you under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<web-app xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee + https://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/web-app_2_5.xsd" + version="2.5"> + <!-- tag::context-listener[] --> + <listener> + <description>Handles Log4j Core lifecycle</description> + <listener-class> + org.apache.logging.log4j.web.Log4jServletContextListener + </listener-class> + </listener> + <!-- end::context-listener[] --> + + <!-- tag::filter[] --> + <filter> + <description>Adds Log4j Core specific attributes to each request</description> + <filter-name>log4jServletFilter</filter-name> + <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class> + </filter> + <filter-mapping> + <filter-name>log4jServletFilter</filter-name> + <url-pattern>/*</url-pattern> + <dispatcher>REQUEST</dispatcher> + <dispatcher>FORWARD</dispatcher> + <dispatcher>INCLUDE</dispatcher> + <dispatcher>ERROR</dispatcher> + <!-- Servlet 3.0 with disabled auto-initialization; not supported in 2.5 + <dispatcher>ASYNC</dispatcher> + --> + </filter-mapping> + <!-- end::filter[] --> +</web-app> diff --git a/src/site/antora/modules/ROOT/nav.adoc b/src/site/antora/modules/ROOT/nav.adoc index a003d7061a..9bca0372ae 100644 --- a/src/site/antora/modules/ROOT/nav.adoc +++ b/src/site/antora/modules/ROOT/nav.adoc @@ -66,6 +66,7 @@ * xref:migrate-from-logback.adoc[] * xref:migrate-from-slf4j.adoc[] * xref:hibernate.adoc[] +* xref:manual/webapp.adoc[] * xref:manual/cloud.adoc[] * xref:development.adoc[] diff --git a/src/site/antora/modules/ROOT/pages/javadoc.adoc b/src/site/antora/modules/ROOT/pages/javadoc.adoc index b871f40c86..bb2b3c0198 100644 --- a/src/site/antora/modules/ROOT/pages/javadoc.adoc +++ b/src/site/antora/modules/ROOT/pages/javadoc.adoc @@ -26,4 +26,7 @@ The table below contains links to the Javadoc API Documentation for the componen | link:javadoc/log4j-core/index.html[Implementation] | The standard implementation, also called the Log4j 2 Core, that contains Appenders, Filters, and more. + +| link:javadoc/log4j-jakarta-web/index.html[Log4j Web] +| Tools to use Log4j in Jakarta EE applications. |=== diff --git a/src/site/antora/modules/ROOT/pages/log4j-jakarta-web.adoc b/src/site/antora/modules/ROOT/pages/log4j-jakarta-web.adoc deleted file mode 100644 index 8384e864ed..0000000000 --- a/src/site/antora/modules/ROOT/pages/log4j-jakarta-web.adoc +++ /dev/null @@ -1,27 +0,0 @@ -//// -Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -//// - -// TODO: turn this into a velocity template for all the version numbers -= Web Servlet Containers - -The Web module provides support for automatically enabling Log4j in Servlet containers. - -See the user manual page on xref:manual/webapp.adoc[Web Applications and JSPs] for details on using Log4j 2 in Web Applications. - -== Requirements - -The Web module requires Servlet 5.0 at minimum and is dependent on the Log4j 2 API and implementation. diff --git a/src/site/antora/modules/ROOT/pages/log4j-web.adoc b/src/site/antora/modules/ROOT/pages/log4j-web.adoc deleted file mode 100644 index be17df4352..0000000000 --- a/src/site/antora/modules/ROOT/pages/log4j-web.adoc +++ /dev/null @@ -1,27 +0,0 @@ -//// -Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -//// - -// TODO: turn this into a velocity template for all the version numbers -= Web Servlet Containers - -The Web module provides support for automatically enabling Log4j in Servlet containers. - -See the user manual page on xref:manual/webapp.adoc[Web Applications and JSPs] for details on using Log4j 2 in Web Applications. - -== Requirements - -The Web module requires Servlet 2.5 at minimum and is dependent on the Log4j 2 API and implementation. diff --git a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc index 484b4ff38e..a5e42037e5 100644 --- a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc @@ -2600,9 +2600,9 @@ file attribute view. |======================================================================= [#TriggeringPolicies] -== TriggeringPolicies +=== TriggeringPolicies -=== Composite Triggering Policy +==== Composite Triggering Policy The `CompositeTriggeringPolicy` combines multiple triggering policies and returns true if any of the configured policies return true. The @@ -2619,7 +2619,7 @@ For example, the following XML fragment defines policies that rollover the log w </Policies> ---- -=== Cron Triggering Policy +==== Cron Triggering Policy The `CronTriggeringPolicy` triggers rollover based on a cron expression. This policy is controlled by a timer and is asynchronous in processing log events, so it is possible that log events from the previous or next period may appear at the beginning or end of the log file. @@ -2640,7 +2640,7 @@ expression indicates a rollover should have occurred between that time and the current time the file will be immediately rolled over. |======================================================================= -=== OnStartup Triggering Policy +==== OnStartup Triggering Policy The `OnStartupTriggeringPolicy` policy causes a rollover if the log file is older than the current JVM's start time and the minimum file size is met or exceeded. @@ -2660,7 +2660,7 @@ When running in Google App Engine, the OnStartup policy causes a rollover if the and falls back to Log4J initialization time instead.) [#sizebased-triggering-policy] -=== SizeBased Triggering Policy +==== SizeBased Triggering Policy The `SizeBasedTriggeringPolicy` causes a rollover once the file has reached the specified size. The size can be specified in bytes, with the suffix KB, MB, GB, or TB for example `20MB`. @@ -2672,7 +2672,7 @@ Otherwise, the target file will be overwritten on every rollover as the SizeBase When used without a time-based triggering policy the SizeBased Triggering Policy will cause the timestamp value to change. [#timebased-triggering-policy] -=== TimeBased Triggering Policy +==== TimeBased Triggering Policy The `TimeBasedTriggeringPolicy` causes a rollover once the date/time pattern no longer applies to the active file. This policy accepts an @@ -2701,10 +2701,10 @@ load of doing so across time. |======================================================================= [#RolloverStrategies] -== RolloverStrategies +=== RolloverStrategies [#DefaultRolloverStrategy] -=== DefaultRolloverStrategy +==== DefaultRolloverStrategy Default Rollover Strategy @@ -2798,7 +2798,7 @@ archived log file during compression. |======================================================================= [#DirectWriteRolloverStrategy] -=== DirectWriteRolloverStrategy +==== DirectWriteRolloverStrategy DirectWrite Rollover Strategy @@ -2959,7 +2959,7 @@ This sample configuration is the same as the previous one but limits the number ---- [#CustomDeleteOnRollover] -=== CustomDeleteOnRollover +==== CustomDeleteOnRollover Log Archive Retention Policy: Delete on Rollover @@ -3045,7 +3045,7 @@ and must return a list with the paths to delete. |======================================================================= [#DeleteIfFileName] -== DeleteIfFileName +=== DeleteIfFileName .IfFileName Condition Parameters [cols="20%,20%,60%",options="header",] @@ -3071,7 +3071,7 @@ the path name matches). |======================================================================= [#DeleteIfLastModified] -== DeleteIfLastModified +=== DeleteIfLastModified .IfLastModified Condition Parameters [cols="20%,20%,60%",options="header",] @@ -3090,7 +3090,7 @@ the file is old enough). |======================================================================= [#DeleteIfAccumulatedFileCount] -== DeleteIfAccumulatedFileCount +=== DeleteIfAccumulatedFileCount .IfAccumulatedFileCount Condition Parameters [cols="20%,20%,60%",options="header",] @@ -3107,7 +3107,7 @@ the threshold count has been exceeded). |======================================================================= [#DeleteIfAccumulatedFileSize] -== DeleteIfAccumulatedFileSize +=== DeleteIfAccumulatedFileSize .IfAccumulatedFileSize Condition Parameters [cols="20%,20%,60%",options="header",] @@ -3201,7 +3201,7 @@ During every rollover, this configuration will delete files that match "*/app-*. ---- [#ScriptCondition] -== ScriptCondition +=== ScriptCondition .ScriptCondition Parameters [cols="20%,20%,60%",options="header",] @@ -3216,7 +3216,7 @@ how ScriptFiles and ScriptRefs can be configured. |======================================================================= [#ScriptParameters] -== ScriptParameters +=== ScriptParameters .Script Parameters [cols="20%,20%,60%",options="header",] @@ -3306,7 +3306,7 @@ The Delete action will delete all files returned by the script. ---- [#CustomPosixViewAttributeOnRollover] -== CustomPosixViewAttributeOnRollover +=== CustomPosixViewAttributeOnRollover Log Archive File Attribute View Policy: Custom file attribute on Rollover @@ -3804,6 +3804,61 @@ Note that the AuditAppender was predefined while the RollingFileAppenders are cr </Configuration> ---- +[#servlet-appender] +== Servlet appender + +The servlet appender allows users to forward all logging calls to the +https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/servletcontext#log(java.lang.String,java.lang.Throwable)[`ServletContext.log(String, Throwable)`] +methods. +You can use it by declaring an appender of type `Servlet` in your configuration file: + +[tabs] +==== +XML:: ++ +[source,xml,indent=0] +---- +include::example$manual/appenders/servlet-appender.xml[tag=servlet] +---- + +JSON:: ++ +[source,xml,indent=0] +---- +include::example$manual/appenders/servlet-appender.json[tag=servlet] +---- + +YAML:: ++ +[source,xml,indent=0] +---- +include::example$manual/appenders/servlet-appender.yaml[tag=servlet] +---- + +Properties:: ++ +[source,xml,indent=0] +---- +include::example$manual/appenders/servlet-appender.properties[tag=servlet] +---- +==== + +<1> The appender passes the exception using the `Throwable` parameter of the +https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/servletcontext#log(java.lang.String,java.lang.Throwable)[`ServletContext.log(String, Throwable)`] method. +Setting `alwaysWriteExceptions` to `false` prevents exceptions from appearing in the log file twice. + +Additional runtime dependencies are required for using the servlet appender: + +include::partial$manual/dependencies-log4j-jakarta-web.adoc[] + +See xref:manual/webapp.adoc[] for more information. + +[CAUTION] +==== +`ServletContext.log(String, Throwable)` is a very primitive logging interface. +Modern application servers usually forward its calls to a proper logging framework and use a **fixed** logging level for all the events. +==== + [[SMTPAppender]] == SMTPAppender @@ -3914,7 +3969,7 @@ As with other Appenders, the formatting can be controlled by specifying a Layout ---- [#ScriptAppenderSelector] -== ScriptAppenderSelector +=== ScriptAppenderSelector When the configuration is built, the `ScriptAppenderSelector` appender calls a `ScriptPlugin` to compute an appender name. Log4j then creates one of the appender named listed under `AppenderSet` using the name of the diff --git a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc index 5d9b94627b..d6545fb7b7 100644 --- a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc @@ -18,7 +18,7 @@ = Configuration file Users can configure Log4j Core using different file formats. -The `log4j-core` artifact includes XML, JSON, YAML, and Java properties formats factories. +The `log4j-core` artifact includes XML, JSON, YAML, and Java properties formats factories. As detailed in the table below, some configuration formats require additional dependencies on the classpath. @@ -67,8 +67,7 @@ The `<contextName>` and `<extension>` placeholders above have the following mean * for standalone Java SE applications, it is a random identifier, * for web applications, it is derived from the application descriptor. -See xref:manual/webapp.adoc#configuration[Log4j - Web application configuration] for more details. +See xref:manual/webapp.adoc#log4jContextName[Log4j Web application configuration] for more details. <extension>:: must be one of the file extensions assigned to a configuration file format: + @@ -139,7 +138,7 @@ Since XML was the original configuration format developed, the mapping from conf + [NOTE] ==== -There is an alternative XML configuration format called "XML strict format" that is activated +There is an alternative XML configuration format called "XML strict format" that is activated by setting the `strict` attribute of the main `<Configuration>` element to `true`. It allows users to use any tag names as long as they provide the plugin type using a `type` property. @@ -801,6 +800,7 @@ The same rule applies to the `name` parameter: if it contains a `${` sequence, i ===== If your configuration file contains the following definitions: + [tabs] ==== XML:: diff --git a/src/site/antora/modules/ROOT/pages/manual/lookups.adoc b/src/site/antora/modules/ROOT/pages/manual/lookups.adoc index b417b5cd9e..72a037776e 100644 --- a/src/site/antora/modules/ROOT/pages/manual/lookups.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/lookups.adoc @@ -72,6 +72,7 @@ be formatted as specified. The DockerLookup can be used to lookup attributes from the Docker container the application is running in. Log4j Docker provides access to the following container attributes: + [cols="1m,4a"] |=== |Key |Description @@ -136,6 +137,7 @@ when the `USER` environment variable is undefined, the default value </PatternLayout> </File> ---- + [#EventLookup] == Event Lookup @@ -173,6 +175,7 @@ The EventLookup provides access to fields within the log event from the configur In this example the RoutingAppender picks a route based on the presence of a Marker named "AUDIT" being present in the log event. + [source,xml] ---- <?xml version="1.0" encoding="UTF-8"?> @@ -432,9 +435,9 @@ Example usage: The MapLookup serves several purposes. -1. Provide the base for Properties declared in the configuration file. -2. Retrieve values from MapMessages in LogEvents. -3. Retrieve values set with +1. Provide the base for Properties declared in the configuration file. +2. Retrieve values from MapMessages in LogEvents. +3. Retrieve values set with link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/MapLookup.html#setMainArguments%28java.lang.String%5B%5D%29[`MapLookup.setMainArguments(String[])`] The first item simply means that the MapLookup is used to substitute @@ -540,9 +543,10 @@ check for the existence of a marker where `name` is the marker name. If the marker exists, the expression returns the name, otherwise `null`. == Resource Bundle Lookup + The resource bundle lookup retrieves values from Resource Bundles (see Java documentation). The format is `${bundle:BundleName:BundleKey}`. The bundle name follows package naming conventions, for example: `${bundle:com.domain.Messages:MyKey}`. -[source, xml] +[source,xml] ---- <File name="Application" fileName="application-${spring:profiles.active[0]}.log"> <PatternLayout> @@ -552,11 +556,12 @@ The resource bundle lookup retrieves values from Resource Bundles (see Java docu ---- == Spring Boot Lookup + The Spring Boot Lookup retrieves the values of Spring properties from the Spring configuration as well as values of the active and default profiles. Specifying a key of "profiles.active" will return the active profiles while a key of "profiles.default" will return the default profiles. The default and active profiles can be an array. If more than one profile is present they will be returned as a comma separated list. To retrieve a single item from the array append "[\{index}]" to the key [...] This Lookup will return null values until Spring Boot initializes application logging. The Spring Boot Lookup requires the log4j-spring-boot jar be included as a dependency. -[source, xml] +[source,xml] ---- <File name="Application" fileName="application-${spring:profiles.active[0]}.log"> <PatternLayout> @@ -641,61 +646,61 @@ result of a nested lookup. [#WebLookup] == Web Lookup -The WebLookup allows applications to retrieve variables that are -associated with the ServletContext. In addition to being able to -retrieve various fields in the ServletContext, WebLookup supports -looking up values stored as attributes or configured as initialization -parameters. The following table lists various keys that can be -retrieved: +The web lookup allows applications that run in a Jakarta EE environment to retrieve variables associated with a +https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/servletcontext[`ServletContext`]. +See xref:manual/webapp.adoc[] for more information. -[cols="1m,4"] +.Web lookup supported keys +[cols="1m,5",options="header"] |=== -|Key |Description -|attr._name_ -|Returns the ServletContext attribute with the specified name +|Key +|Description -|contextPath -|The context path of the web application +|attr.<key> +|Value of the `<key`> servlet context attribute. |contextPathName -|The first token in the context path of the web application splitting on "/" characters. +|The **first** fragment of the servlet context path. + +|contextPath +|The **entire** servlet context path. |effectiveMajorVersion -|Gets the major version of the Servlet specification that the application -represented by this ServletContext is based on. +|The major version of the Servlet specification supported by the application. |effectiveMinorVersion -|Gets the minor version of the Servlet specification that the application -represented by this ServletContext is based on. +|The minor version of the Servlet specification supported by the application. -|initParam._name_ -|Returns the ServletContext initialization parameter with the specified name +|initParam.<key> +|Value of the `<key>` servlet context initialization parameter. |majorVersion -|Returns the major version of the Servlet API that this servlet container supports. +|The major version of the Servlet specification supported by the server. |minorVersion -|Returns the minor version of the Servlet API that this servlet container supports. +|The minor version of the Servlet specification supported by the server. |rootDir -|Returns the result of calling getRealPath with a value of "/". +|The root directory of the servlet context. |serverInfo -|Returns the name and version of the servlet container on which the servlet is running. +|The server info. |servletContextName -|Returns the name of the web application as defined in the display-name element of the deployment descriptor +|The servlet context name. + +|<key> +|The value of `<key>` is searched as context attribute or context initialization parameter. |=== -Any other key names specified will first be checked to see if a -ServletContext attribute exists with that name and then will be checked -to see if an initialization parameter of that name exists. If the key is -located then the corresponding value will be returned. +The web lookup can be used, for example, to provide a different log file for each application: [source,xml] ---- -<Appenders> - <File name="ApplicationLog" fileName="${web:rootDir}/app.log"/> -</Appenders> +<File name="ApplicationLog" fileName="logs${web:contextPath}.log"/> ---- + +Additional runtime dependencies are required for using web lookup: + +include::partial$manual/dependencies-log4j-jakarta-web.adoc[] diff --git a/src/site/antora/modules/ROOT/pages/manual/webapp.adoc b/src/site/antora/modules/ROOT/pages/manual/webapp.adoc index cdb0f78040..70851def82 100644 --- a/src/site/antora/modules/ROOT/pages/manual/webapp.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/webapp.adoc @@ -15,311 +15,231 @@ limitations under the License. //// -= Log4j Web Applications += Using Log4j in a Jakarta EE environment -== Using Log4j in Web Applications +[#web-applications] +== Integrating with Web Applications -You must take particular care when using Log4j or any other logging framework within a Java EE web application. It's important for logging resources to be properly cleaned up (database connections closed, files closed, etc.) when the container shuts down or the web application is undeployed. Because of the nature of class loaders within web applications, Log4j resources cannot be cleaned up through normal means. Log4j must be "started" when the web application deploys and "shut down" whe [...] - -Due to the namespace change from `javax` to `jakarta`, you need to use `log4j-jakarta-web` instead of `log4j-web` for Servlet 5.0 or newer. +[NOTE] +==== +To avoid problems, some Log4j API and Log4j Core features are automatically disabled, when running in a Jakarta EE environment. Most notably: -In either case, you'll need to add the `log4j-web` module to your deployment. +- the usage of `ThreadLocal` for object pooling is disabled, +- a web-safe implementation of +link:../javadoc/log4j-api/org/apache/logging/log4j/spi/ThreadContextMap.html[`ThreadContextMap`] is used, +- JMX notifications are sent synchronously, +- the JVM shutdown hook is disabled. -[.note] -==== -To avoid problems, the Log4j shutdown hook will automatically be disabled when the log4j-web jar is included. +See xref:manual/systemproperties.adoc#log4j2.isWebapp[`log4j2.isWebapp`] for more details. ==== -[id=configuration] -=== Configuration +Using a logging implementation like **Log4j Core** in a Jakarta EE application requires particular care. +Since the lifecycle of a container or web application is independent of the lifecycle of the JVM, it's important for logging resources to be properly cleaned up (database connections closed, files closed, etc.) when the container or web application shuts down. -Log4j allows the configuration file to be specified in web.xml using the `log4jConfiguration` context parameter. Log4j will search for configuration files by: +To properly synchronize the lifecycles of Log4j Core and Jakarta EE applications an additional **Log4j Web** artifact is provided. -1. If a location is provided it will be searched for as a servlet context resource. For example, if `log4jConfiguration` contains "logging.xml" then Log4j will look for a file with that name in the root directory of the web application. -2. If no location is defined Log4j will search for a file that starts with "log4j2" in the WEB-INF directory. If more than one file is found, and if a file that starts with "log4j2-\{name}" is present, where \{name} is the name of the web application, then it will be used. Otherwise the first file will be used. -3. The "normal" search sequence using the classpath and file URLs will be used to locate the configuration file. +[#log4j-jakarta-web-installation] +=== Installation -[#Servlet-3-0] -=== Servlet 3.0 and Newer Web Applications +In order to install Log4j Web in your Web application, you need to add it as runtime dependency: -A Servlet 3.0 or newer web application is any `<web-app>` whose `version` attribute has a value of "3.0" or higher. Of course, the application must also be running in a compatible web container. +include::partial$manual/dependencies-log4j-jakarta-web.adoc[] -Some examples are: +If you are writing a Servlet 3.0 or later application, Apache Log4j Web will register a +https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/servletcontainerinitializer[`ServletContainerInitializer`] +that takes care of configuring the Log4j lifecycle for you. Under the hood this will: -* Tomcat 7.0 and higher -* GlassFish 3.0 and higher -* JBoss 7.0 and higher -* Oracle WebLogic 12c and higher -* IBM WebSphere 8.0 and higher +* initialize Log4j Core with the correct configuration file, +* register a `Log4jServletContextListener` to automatically shut down Log4j Core, when the application shuts down, +* register a `Log4jServletFilter` to enable the xref:manual/lookups.adoc#WebLookup[web lookup]. -==== The Short Story +[WARNING] +==== +While the Servlet Specification allows web fragments to automatically add context listeners, it does not give any guarantees regarding the order in which those listeners are executed +(cf. https://jakarta.ee/specifications/servlet/5.0/jakarta-servlet-spec-5.0#Assembling_the_descriptor[section 8.2.3]). -Log4j 2 "just works" in Servlet 3.0 and newer web applications. It is capable of automatically starting when the application deploys and shutting down when the application undeploys. Thanks to the https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html[ServletContainerInitializer] API added to Servlet 3.0, the relevant `Filter` and `ServletContextListener` classes can be registered dynamically on web application startup. +If other context listeners in your application use logging, you need to make sure that `Log4jServletContextListener` is the last listener to be executed at shutdown. +In order to do it you must create a `web.xml` descriptor and add the `Log4jServletContextListener` explicitly as **first** context listener: -[warning] -==== -Important Note! -For performance reasons, containers often ignore certain JARs known not to contain TLDs or `ServletContainerInitializer`s and do not scan them for web-fragments and initializers. Importantly, Tomcat 7 <7.0.43 ignores all JAR files named log4j*.jar, which prevents this feature from working. This has been fixed in Tomcat 7.0.43, Tomcat 8, and later. In Tomcat 7 <7.0.43 you will need to change `catalina.properties` and remove "log4j*.jar" from the `jarsToSkip` property. You may need to do s [...] +[source,xml,indent=0] +---- +include::example$manual/webapp/web.xml[tag=context-listener] +---- ==== -==== The Long Story - -The Log4j 2 Web JAR file is a web-fragment configured to order before any other web fragments in your application. It contains a `ServletContainerInitializer` (`Log4jServletContainerInitializer`) that the container automatically discovers and initializes. This adds the `Log4jServletContextListener` and `Log4jServletFilter` to the `ServletContext`. These classes properly initialize and deinitialize the Log4j configuration. +==== Manual installation -For some users, automatically starting Log4j is problematic or undesirable. You can easily disable this feature using the `isLog4jAutoInitializationDisabled` context parameter. Simply add it to your deployment descriptor with the value "true" to disable auto-initialization. You _must_ define the context parameter in `web.xml`. If you set in programmatically, it will be too late for Log4j to detect the setting. +If you are maintaining an older Servlet 2.5 (or earlier) application or if you disabled -[source,xml] +[source,xml,indent=0] ---- -<context-param> - <param-name>isLog4jAutoInitializationDisabled</param-name> - <param-value>true</param-value> -</context-param> +include::example$manual/webapp/web.xml[tags=context-listener;filter] ---- -Once you disable auto-initialization, you must initialize Log4j as you would a <<Servlet-2-5,Servlet 2.5 web application>>. You must do so in a way that this initialization happens before any other application code (such as Spring Framework startup code) executes. +[#configuration] +=== Configuration -You can customize the behavior of the listener and filter using the `log4jContextName`, `log4jConfiguration`, and/or `isLog4jContextSelectorNamed` context parameters. Read more about this in the <<ContextParams,Context Parameters>> section below. You _must not_ manually configure the `Log4jServletContextListener` or `Log4jServletFilter` in your deployment descriptor (`web.xml`) or in another initializer or listener in a Servlet 3.0 or newer application _unless you disable auto-initializa [...] +Log4j Web provides many configuration options to finely tune its installation. +These configuration options should be specified as +https://jakarta.ee/specifications/servlet/5.0/jakarta-servlet-spec-5.0#initialization-parameters[servlet context initialization parameters]. -[#Servlet-2-5] -=== Servlet 2.5 Web Applications +[id=isLog4jAutoInitializationDisabled] +==== `isLog4jAutoInitializationDisabled` -A Servlet 2.5 web application is any `<web-app>` whose `version` attribute has a value of "2.5." The `version` attribute is the only thing that matters; even if the web application is running in a Servlet 3.0 or newer container, it is a Servlet 2.5 web application if the `version` attribute is "2.5." Note that Log4j 2 does not support Servlet 2.4 and older web applications. +[cols="1h,5"] +|=== +| Type | `boolean` +| Default value | `false` +|=== -If you are using Log4j in a Servlet 2.5 web application, or if you have disabled auto-initialization with the isLog4jAutoInitializationDisabled context parameter, you must configure the Log4jServletContextListener and Log4jServletFilter in the deployment descriptor or programmatically. The filter should match all requests of any type. The listener should be the very first listener defined in your application, and the filter should be the very first filter defined and mapped in your appli [...] +If set to `true`, the `Log4jServletContainerInitializer` will be disabled, which prevents the automatic registration of both the `Log4jServletContextListener` and `Log4jServletFilter`. -[source,xml] ----- -<listener> - <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class> -</listener> - -<filter> - <filter-name>log4jServletFilter</filter-name> - <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class> -</filter> -<filter-mapping> - <filter-name>log4jServletFilter</filter-name> - <url-pattern>/*</url-pattern> - <dispatcher>REQUEST</dispatcher> - <dispatcher>FORWARD</dispatcher> - <dispatcher>INCLUDE</dispatcher> - <dispatcher>ERROR</dispatcher> - <dispatcher>ASYNC</dispatcher><!-- Servlet 3.0 w/ disabled auto-initialization only; not supported in 2.5 --> -</filter-mapping> ----- +[id=isLog4jAutoShutdownDisabled] +==== `isLog4jAutoShutdownDisabled` -You can customize the behavior of the listener and filter using the log4jContextName, log4jConfiguration, and/or isLog4jContextSelectorNamed context parameters. Read more about this in the Context Parameters section below. +[cols="1h,5"] +|=== +| Type | `boolean` +| Default value | `false` +|=== -[#ContextParams] -=== Context Parameters +If set to `true`, the `Log4jServletContextListener` will not register a `Log4jServletContextListener` to handle the web application shut down. -By default, Log4j 2 uses the ServletContext's context name as the LoggerContext name and uses the standard pattern for locating the Log4j configuration file. There are three context parameters that you can use to control this behavior. The first, isLog4jContextSelectorNamed, specifies whether the context should be selected using the JndiContextSelector. If isLog4jContextSelectorNamed is not specified or is anything other than true, it is assumed to be false. +[id=log4j.stop.timeout.timeunit] +==== `log4j.stop.timeout.timeunit` -If isLog4jContextSelectorNamed is true, log4jContextName must be specified or display-name must be specified in web.xml; otherwise, the application will fail to start with an exception. log4jConfiguration should also be specified in this case, and must be a valid URI for the configuration file; however, this parameter is not required. +[cols="1h,5"] +|=== +| Type +| https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/concurrent/TimeUnit.html[`TimeUnit`] -If isLog4jContextSelectorNamed is not true, log4jConfiguration may optionally be specified and must be a valid URI or path to a configuration file or start with "classpath:" to denote a configuration file that can be found on the classpath. Without this parameter, Log4j will use the standard mechanisms for locating the configuration file. +| Default value +| https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/concurrent/TimeUnit.html#SECONDS[`SECONDS`] +|=== -When specifying these context parameters, you must specify them in the deployment descriptor (web.xml) even in a Servlet 3.0 or never application. If you add them to the ServletContext within a listener, Log4j will initialize before the context parameters are available and they will have no effect. Here are some sample uses of these context parameters. +The `TimeUnit` to use for the shut-down delay. -==== Set the Logging Context Name to "myApplication" +[id=log4j.stop.timeout] +==== `log4j.stop.timeout` -[source,xml] ----- -<context-param> - <param-name>log4jContextName</param-name> - <param-value>myApplication</param-value> -</context-param> ----- +[cols="1h,5"] +|=== +| Type +| `long` -==== Set the Configuration Path/File/URI to "/etc/myApp/myLogging.xml" +| Default value +| `30` +|=== -[source,xml] ----- -<context-param> - <param-name>log4jConfiguration</param-name> - <param-value>file:///etc/myApp/myLogging.xml</param-value> -</context-param> ----- +[id=log4jContextName] +==== `log4jContextName` -[#use-jndi-context-selector] -==== Use the JndiContextSelector +[cols="1h,5"] +|=== +| Type +| `String` -[source,xml] ----- -<context-param> - <param-name>isLog4jContextSelectorNamed</param-name> - <param-value>true</param-value> -</context-param> -<context-param> - <param-name>log4jContextName</param-name> - <param-value>appWithJndiSelector</param-value> -</context-param> -<context-param> - <param-name>log4jConfiguration</param-name> - <param-value>file:///D:/conf/myLogging.xml</param-value> -</context-param> ----- +| Default value +| _automatically computed_ +|=== -Note that in this case you must also set the "Log4jContextSelector" system property to "org.apache.logging.log4j.core.selector.JndiContextSelector". +Specifies the name of the logger context to use. -For security reasons, from Log4j 2.17.0, JNDI must be enabled by setting system property log4j2.enableJndiContextSelector=true +If <<log4j-jakarta-web-jndi-configuration,`JndiContextSelector`>> is used, this parameter **must** be explicitly provided. Otherwise, the default value is: -== Using Web Application Information During the Configuration +. the servlet context name, if present, +. the servlet context path, including the leading `/`, otherwise. -You may want to use information about the web application during configuration. For example, you could embed the web application's context path in the name of a Rolling File Appender. See WebLookup in Lookups for more information. +[id=isLog4jContextSelectorNamed] +==== `isLog4jContextSelectorNamed` -=== JavaServer Pages Logging +[cols="1h,5"] +|=== +| Type +| `boolean` -You may use Log4j 2 within JSPs just as you would within any other Java code. Simply obtain a Logger and call its methods to log events. However, this requires you to use Java code within your JSPs, and some development teams rightly are not comfortable doing this. If you have a dedicated user interface development team that is not familiar with using Java, you may even have Java code disabled in your JSPs. +| Default value +| `false` +|=== -For this reason, Log4j 2 provides a JSP Tag Library that enables you to log events without using any Java code. To read more about using this tag library, xref:log4j-taglib.adoc[read the Log4j Tag Library documentation]. +Must be set to `true` to use the <<log4j-jakarta-web-jndi-configuration,JNDI configuration>>. -Important Note! As noted above, containers often ignore certain JARs known not to contain TLDs and do not scan them for TLD files. Importantly, Tomcat 7 <7.0.43 ignores all JAR files named log4j*.jar, which prevents the JSP tag library from being automatically discovered. This does not affect Tomcat 6.x and has been fixed in Tomcat 7.0.43, Tomcat 8, and later. In Tomcat 7 <7.0.43 you will need to change catalina.properties and remove "log4j*.jar" from the jarsToSkip property. You may nee [...] +[id=log4jConfiguration] +==== `log4jConfiguration` -=== Asynchronous Requests and Threads +[cols="1h,5"] +|=== +| Type +| https://docs.oracle.com/javase/8/docs/api/java/net/URI.html[`URI`] -The handling of asynchronous requests is tricky, and regardless of Servlet container version or configuration Log4j cannot handle everything automatically. When standard requests, forwards, includes, and error resources are processed, the Log4jServletFilter binds the LoggerContext to the thread handling the request. After request processing completes, the filter unbinds the LoggerContext from the thread. +| Default value +| `false` +|=== -Similarly, when an internal request is dispatched using a javax.servlet.AsyncContext, the Log4jServletFilter also binds the LoggerContext to the thread handling the request and unbinds it when request processing completes. However, this only happens for requests dispatched through the AsyncContext. There are other asynchronous activities that can take place other than internal dispatched requests. +The location of a Log4j Core configuration file. +If the provided value is not an **absolute** URI, Log4j interprets it as: -For example, after starting an AsyncContext you could start up a separate thread to process the request in the background, possibly writing the response with the ServletOutputStream. Filters cannot intercept the execution of this thread. Filters also cannot intercept threads that you start in the background during non-asynchronous requests. This is true whether you use a brand-new thread or a thread borrowed from a thread pool. So what can you do for these special threads? +. path to a +https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/servletcontext#getResource(java.lang.String)[servlet context resource], if it exists, +. path to a file, if it exists, +. path to a +https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html#getResource-java.lang.String-[classpath resource], otherwise. -You may not need to do anything. If you didn't use the isLog4jContextSelectorNamed context parameter, there is no need to bind the LoggerContext to the thread. Log4j can safely locate the LoggerContext on its own. In these cases, the filter provides only very modest performance gains, and only when creating new Loggers. However, if you did specify the isLog4jContextSelectorNamed context parameter with the value "true", you will need to manually bind the LoggerContext to asynchronous thre [...] +If no value is provided: -Thankfully, Log4j provides a simple mechanism for binding the LoggerContext to asynchronous threads in these special circumstances. The simplest way to do this is to wrap the Runnable instance that is passed to the AsyncContext.start() method. +. Log4j Web looks for a servlet context resource named `/WEB-INF/log4j2-<contextName>.<extension>`, where `<contextName>` is the name of the logger context, +. if no such file exists it looks for a servlet context resource named `/WEB-INF/log4j2.<extension>`, +. otherwise it searches for a configuration file on the classpath using the usual https://logging.apache.org/log4j/2.x/manual/configuration.html#automatic-configuration[automatic configuration procedure]. -[source,java] ----- -import java.io.IOException; -import javax.servlet.AsyncContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.web.WebLoggerContextUtils; - -public class TestAsyncServlet extends HttpServlet { - - @Override - protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { - final AsyncContext asyncContext = req.startAsync(); - asyncContext.start(WebLoggerContextUtils.wrapExecutionContext(this.getServletContext(), new Runnable() { - @Override - public void run() { - final Logger logger = LogManager.getLogger(TestAsyncServlet.class); - logger.info("Hello, servlet!"); - } - })); - } - - @Override - protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { - final AsyncContext asyncContext = req.startAsync(); - asyncContext.start(new Runnable() { - @Override - public void run() { - final Log4jWebSupport webSupport = - WebLoggerContextUtils.getWebLifeCycle(TestAsyncServlet.this.getServletContext()); - webSupport.setLoggerContext(); - // do stuff - webSupport.clearLoggerContext(); - } - }); - } -} ----- +[#async] +=== Asynchronous Requests and Threads + +In order for the +xref:manual/lookups.adoc#WebLookup[web lookup] +to work correctly, Log4j must be able to always identify the `ServletContext` used by the current thread. +When standard requests, forwards, includes, and error resources are processed, the `Log4jServletFilter` binds the `LoggerContext` to the thread handling the request, and you don't have to do anything. -This can be slightly more convenient when using Java 1.8 and lambda functions as demonstrated below. +The handling of asynchronous requests is however more tricky, since it allows you to execute code on threads that were not prepared by `Log4jServletFilter`. +Such a situation occurs for example, if your code was started using the +https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/asynccontext#start(java.lang.Runnable)[`AsyncContext.start(Runnable)`] +method. -[source,java] +To successfully propagate the logger context along asynchronous calls, the +link:../javadoc/log4j-jakarta-web/org/apache/logging/log4j/web/WebLoggerContextUtils.html[`WebLoggerContextUtils`] +helper class is made available. +Using this class you can either decorate a `Runnable` with method calls that bind the appropriate logger context to the thread: + +[source,java,indent=0] ---- -import java.io.IOException; -import javax.servlet.AsyncContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.web.WebLoggerContextUtils; - -public class TestAsyncServlet extends HttpServlet { - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - final AsyncContext asyncContext = req.startAsync(); - asyncContext.start(WebLoggerContextUtils.wrapExecutionContext(this.getServletContext(), () -> { - final Logger logger = LogManager.getLogger(TestAsyncServlet.class); - logger.info("Hello, servlet!"); - })); - } -} +include::example$manual/webapp/AsyncServlet.java[tag=automatic] ---- -Alternatively, you can obtain the `Log4jWebLifeCycle` instance from the ServletContext attributes, call its setLoggerContext method as the very first line of code in your asynchronous thread, and call its clearLoggerContext method as the very last line of code in your asynchronous thread. The following code demonstrates this. It uses the container thread pool to execute asynchronous request processing, passing an anonymous inner Runnable to the start method. +or, if more flexibility is required, you can apply the same logic by using +link:../javadoc/log4j-jakarta-web/org/apache/logging/log4j/web/Log4jWebSupport.html[`Log4jWebSupport`]: -[source,java] +[source,java,indent=0] ---- -import java.io.IOException; -import javax.servlet.AsyncContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.web.Log4jWebLifeCycle; -import org.apache.logging.log4j.web.WebLoggerContextUtils; - -public class TestAsyncServlet extends HttpServlet { - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - final AsyncContext asyncContext = req.startAsync(); - asyncContext.start(new Runnable() { - @Override - public void run() { - final Log4jWebLifeCycle webLifeCycle = - WebLoggerContextUtils.getWebLifeCycle(TestAsyncServlet.this.getServletContext()); - webLifeCycle.setLoggerContext(); - try { - final Logger logger = LogManager.getLogger(TestAsyncServlet.class); - logger.info("Hello, servlet!"); - } finally { - webLifeCycle.clearLoggerContext(); - } - } - }); - } -} +include::example$manual/webapp/AsyncServlet.java[tag=manual] ---- -Note that you must call clearLoggerContext once your thread is finished processing. Failing to do so will result in memory leaks. If using a thread pool, it can even disrupt the logging of other web applications in your container. For that reason, the example here shows clearing the context in a finally block, which will always execute. +[#application-server] +== Configuring an application server -== Using the Servlet Appender +[#jndi-configuration] +=== Using JNDI selectors -Log4j provides a Servlet Appender that uses the servlet context as the log target. For example: +Log4j Core allows the usage of JNDI to coordinate the usage of logger contexts in a Jakarta EE application server. +In order to use this feature, you need to: -[source,xml] +. Set the +xref:manual/systemproperties.adoc#log4j2.contextSelector[`log4j2.contextSelector`] +Log4j configuration property to ``org.apache.logging.log4j.core.selector.JndiContextSelector``, +. For security reasons you need to enable the selector, by setting the +xref:manual/systemproperties.adoc#log4j2.enableJndiContextSelector[`log4j2.enableJndiContextSelector`] +Log4j configuration property to `true`, +. Each web application needs to configure the servlet context parameter `isLog4jContextSelectorNamed` to `true` and provide a value for the `log4jContextName` servlet context parameter and `java:comp/env/log4j/context-name` JNDI environment entry: ++ +[source,xml,indent=0] ---- -<Configuration status="WARN" name="ServletTest"> - - <Appenders> - <Servlet name="Servlet"> - <PatternLayout pattern="%m%n%ex{none}"/> - </Servlet> - </Appenders> - - <Loggers> - <Root level="debug"> - <AppenderRef ref="Servlet"/> - </Root> - </Loggers> - -</Configuration> +include::example$manual/webapp/jndi.xml[tag=jndi] ---- - -To avoid double logging of exceptions to the servlet context, you must use %ex\{none} in your PatternLayout as shown in the example. The exception will be omitted from the message text but it is passed to the servlet context as the actual Throwable object. diff --git a/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-1.2-api.adoc b/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-1.2-api.adoc index 349feafc4c..71d36a4405 100644 --- a/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-1.2-api.adoc +++ b/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-1.2-api.adoc @@ -21,6 +21,7 @@ Maven:: + [source,xml,subs="+attributes"] ---- +<!-- We assume you use `log4j-bom` for dependency management --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> @@ -33,6 +34,7 @@ Gradle:: + [source,groovy,subs="+attributes"] ---- +// We assume you use `log4j-bom` for dependency management runtimeOnly 'org.apache.logging.log4j:log4j-1.2-api:{log4j-core-version}' ---- ==== \ No newline at end of file diff --git a/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-1.2-api.adoc b/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-jakarta-web.adoc similarity index 51% copy from src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-1.2-api.adoc copy to src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-jakarta-web.adoc index 349feafc4c..39e10d936d 100644 --- a/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-1.2-api.adoc +++ b/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-jakarta-web.adoc @@ -21,10 +21,10 @@ Maven:: + [source,xml,subs="+attributes"] ---- +<!-- We assume you use `log4j-bom` for dependency management --> <dependency> <groupId>org.apache.logging.log4j</groupId> - <artifactId>log4j-1.2-api</artifactId> - <version>{log4j-core-version}</version> + <artifactId>log4j-jakarta-web</artifactId> <scope>runtime</scope> </dependency> ---- @@ -33,6 +33,37 @@ Gradle:: + [source,groovy,subs="+attributes"] ---- -runtimeOnly 'org.apache.logging.log4j:log4j-1.2-api:{log4j-core-version}' +// We assume you use `log4j-bom` for dependency management +runtimeOnly 'org.apache.logging.log4j:log4j-jakarta-web' ---- -==== \ No newline at end of file +==== + +.Click here if you are you using Jakarta EE 8 or any version of Java EE? +[%collapsible] +===== +Jakarta EE 8 and all Java EE applications servers use the legacy `javax` package prefix instead of `jakarta`. +If you are using those application servers, you should replace the dependencies above with: + +[tabs] +==== +Maven:: ++ +[source,xml,subs="+attributes"] +---- +<!-- We assume you use `log4j-bom` for dependency management --> +<dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-web</artifactId> + <scope>runtime</scope> +</dependency> +---- + +Gradle:: ++ +[source,groovy,subs="+attributes"] +---- +// We assume you use `log4j-bom` for dependency management +runtimeOnly 'org.apache.logging.log4j:log4j-web' +---- +==== +===== \ No newline at end of file diff --git a/src/site/resources/.htaccess b/src/site/resources/.htaccess index 308ff31b1c..d54394a584 100644 --- a/src/site/resources/.htaccess +++ b/src/site/resources/.htaccess @@ -37,6 +37,7 @@ RewriteRule "^log4j-1\.2-api(/index)?\.html$" "manual/migration.html" [R=permane RewriteRule "^log4j-api/apidocs(.*)$" "javadoc/log4j-api$1" [R=permanent] RewriteRule "^log4j-api(/index)?\.html$" "manual/api.html" [R=permanent] RewriteRule "^log4j-core/apidocs(.*)$" "javadoc/log4j-core$1" [R=permanent] +RewriteRule "^log4j(-jakarta)?-web(/index)?\.html$" "manual/webapp.html" [R=permanent] RewriteRule "^log4j-jcl(/index)?\.html$" "manual/installation.html#impl-core-bridge-jcl" [R=permanent,NE] RewriteRule "^log4j-jmx-gui(/index)?\.html$" "/log4j/jmx-gui/latest/index.html" [R=permanent] RewriteRule "^log4j-jpl(/index)?\.html$" "manual/installation.html#impl-core-bridge-jpl" [R=permanent,NE] @@ -102,12 +103,10 @@ RewriteRule "^log4j-couchdb\.html/index\.html$" "log4j-couchdb.html" [R=permanen RewriteRule "^log4j-docker\.html/index\.html$" "log4j-docker.html" [R=permanent] RewriteRule "^log4j-flume-ng\.html/index\.html$" "log4j-flume-ng.html" [R=permanent] RewriteRule "^log4j-iostreams\.html/index\.html$" "log4j-iostreams.html" [R=permanent] -RewriteRule "^log4j-jakarta-web\.html/index\.html$" "log4j-jakarta-web.html" [R=permanent] RewriteRule "^log4j-jul\.html/index\.html$" "log4j-jul.html" [R=permanent,NE] RewriteRule "^log4j-spring-boot\.html/index\.html$" "log4j-spring-boot.html" [R=permanent] RewriteRule "^log4j-spring-cloud-config\.html/index\.html$" "log4j-spring-cloud-config.html" [R=permanent] RewriteRule "^log4j-spring-cloud-config-client\.html/index\.html$" "log4j-spring-cloud-config-client.html" [R=permanent] RewriteRule "^log4j-taglib\.html/index\.html$" "log4j-taglib.html" [R=permanent] RewriteRule "^log4j-to-jul\.html/index\.html$" "log4j-to-jul.html" [R=permanent] -RewriteRule "^log4j-web\.html/index\.html$" "log4j-web.html" [R=permanent] RewriteRule "^release-notes\.html/index\.html$" "release-notes.html" [R=permanent]
