blob: 39f17cd24305d192065106115c1e26bf99457d0a [file] [log] [blame]
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 1.11.1 from target/generated-sources/site/asciidoc/manual/json-template-layout.adoc at 2024-03-06
| Rendered using Apache Maven Fluido Skin 1.11.2
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="Apache Maven Doxia Site Renderer 1.11.1" />
<title>Log4j &#x2013; </title>
<link rel="stylesheet" href="../css/apache-maven-fluido-1.11.2.min.css" />
<link rel="stylesheet" href="../css/site.css" />
<link rel="stylesheet" href="../css/print.css" media="print" />
<script src="../js/apache-maven-fluido-1.11.2.min.js"></script>
</head>
<body class="topBarDisabled">
<div class="container-fluid">
<header>
<div id="banner">
<div class="pull-left"><a href="../../.." id="bannerLeft"><img src="../images/ls-logo.jpg" alt="" style="" /></a></div>
<div class="pull-right"><a href=".././" id="bannerRight"><img src="../images/logo.png" alt="" style="" /></a></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Last Published: 2024-03-06<span class="divider">|</span>
</li>
<li id="projectVersion">Version: 2.23.1</li>
<li class="pull-right"><span class="divider">|</span>
<a href="https://github.com/apache/logging-log4j2" class="externalLink" title="GitHub">GitHub</a></li>
<li class="pull-right"><span class="divider">|</span>
<a href="../../../" title="Logging Services">Logging Services</a></li>
<li class="pull-right"><span class="divider">|</span>
<a href="https://www.apache.org/" class="externalLink" title="Apache">Apache</a></li>
<li class="pull-right"><a href="https://cwiki.apache.org/confluence/display/LOGGING/Log4j" class="externalLink" title="Logging Wiki">Logging Wiki</a></li>
</ul>
</div>
</header>
<div class="row-fluid">
<header id="leftColumn" class="span2">
<nav class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/home.png" alt="Apache Log4j™ 2" style="border: 0;" /> Apache Log4j™ 2</li>
<li><a href="../index.html" title="About"><span class="none"></span>About</a></li>
<li><a href="../download.html" title="Download"><span class="none"></span>Download</a></li>
<li><a href="../support.html" title="Support"><span class="none"></span>Support</a></li>
<li><a href="../maven-artifacts.html" title="Maven, Ivy, Gradle Artifacts"><span class="icon-chevron-right"></span>Maven, Ivy, Gradle Artifacts</a></li>
<li><a href="../release-notes.html" title="Release Notes"><span class="none"></span>Release Notes</a></li>
<li><a href="../faq.html" title="FAQ"><span class="none"></span>FAQ</a></li>
<li><a href="../performance.html" title="Performance"><span class="icon-chevron-right"></span>Performance</a></li>
<li><a href="../articles.html" title="Articles and Tutorials"><span class="none"></span>Articles and Tutorials</a></li>
<li><a href="../security.html" title="Security"><span class="icon-chevron-right"></span>Security</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/book.png" alt="Manual" style="border: 0;" /> Manual</li>
<li><a href="../manual/index.html" title="Introduction"><span class="none"></span>Introduction</a></li>
<li><a href="../manual/architecture.html" title="Architecture"><span class="none"></span>Architecture</a></li>
<li><a href="../manual/api-separation.html" title="API Separation"><span class="none"></span>API Separation</a></li>
<li><a href="../manual/migration.html" title="Log4j 1.x Migration"><span class="icon-chevron-right"></span>Log4j 1.x Migration</a></li>
<li><a href="../manual/api.html" title="Java API"><span class="icon-chevron-right"></span>Java API</a></li>
<li><a href="../../kotlin" title="Kotlin API"><span class="none"></span>Kotlin API</a></li>
<li><a href="../../scala" title="Scala API"><span class="none"></span>Scala API</a></li>
<li><a href="../manual/configuration.html" title="Configuration"><span class="icon-chevron-right"></span>Configuration</a></li>
<li><a href="../manual/usage.html" title="Usage"><span class="icon-chevron-right"></span>Usage</a></li>
<li><a href="../manual/webapp.html" title="Web Applications and JSPs"><span class="icon-chevron-right"></span>Web Applications and JSPs</a></li>
<li><a href="../manual/lookups.html" title="Lookups"><span class="icon-chevron-right"></span>Lookups</a></li>
<li><a href="../manual/appenders.html" title="Appenders"><span class="icon-chevron-right"></span>Appenders</a></li>
<li><a href="../manual/layouts.html" title="Layouts"><span class="icon-chevron-down"></span>Layouts</a>
<ul class="nav nav-list">
<li><a href="../manual/layouts.html#CSVLayouts" title="CSV"><span class="none"></span>CSV</a></li>
<li><a href="../manual/layouts.html#GELFLayout" title="GELF"><span class="none"></span>GELF</a></li>
<li><a href="../manual/layouts.html#HTMLLayout" title="HTML"><span class="none"></span>HTML</a></li>
<li><a href="../manual/layouts.html#JSONLayout" title="JSON"><span class="none"></span>JSON</a></li>
<li class="active"><a><span class="none"></span>JSON Template</a></li>
<li><a href="../manual/layouts.html#PatternLayout" title="Pattern"><span class="none"></span>Pattern</a></li>
<li><a href="../manual/layouts.html#RFC5424Layout" title="RFC-5424"><span class="none"></span>RFC-5424</a></li>
<li><a href="../manual/layouts.html#SerializedLayout" title="Serialized"><span class="none"></span>Serialized</a></li>
<li><a href="../manual/layouts.html#SyslogLayout" title="Syslog"><span class="none"></span>Syslog</a></li>
<li><a href="../manual/layouts.html#XMLLayout" title="XML"><span class="none"></span>XML</a></li>
<li><a href="../manual/layouts.html#YamlLayout" title="YAML"><span class="none"></span>YAML</a></li>
<li><a href="../manual/layouts.html#LocationInformation" title="Location Information"><span class="none"></span>Location Information</a></li>
</ul></li>
<li><a href="../manual/filters.html" title="Filters"><span class="icon-chevron-right"></span>Filters</a></li>
<li><a href="../manual/async.html" title="Async Loggers"><span class="icon-chevron-right"></span>Async Loggers</a></li>
<li><a href="../manual/garbagefree.html" title="Garbage-free Logging"><span class="icon-chevron-right"></span>Garbage-free Logging</a></li>
<li><a href="../manual/jmx.html" title="JMX"><span class="none"></span>JMX</a></li>
<li><a href="../manual/logsep.html" title="Logging Separation"><span class="none"></span>Logging Separation</a></li>
<li><a href="../manual/extending.html" title="Extending Log4j"><span class="icon-chevron-right"></span>Extending Log4j</a></li>
<li><a href="../manual/plugins.html" title="Plugins"><span class="icon-chevron-right"></span>Plugins</a></li>
<li><a href="../manual/customconfig.html" title="Programmatic Log4j Configuration"><span class="icon-chevron-right"></span>Programmatic Log4j Configuration</a></li>
<li><a href="../manual/customloglevels.html" title="Custom Log Levels"><span class="icon-chevron-right"></span>Custom Log Levels</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/pencil.png" alt="For Contributors" style="border: 0;" /> For Contributors</li>
<li><a href="../guidelines.html" title="Guidelines"><span class="none"></span>Guidelines</a></li>
<li><a href="../javastyle.html" title="Style Guide"><span class="none"></span>Style Guide</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/cog.png" alt="Components" style="border: 0;" /> Components</li>
<li><a href="../log4j-api.html" title="API"><span class="none"></span>API</a></li>
<li><a href="../log4j-jcl.html" title="Commons Logging Bridge"><span class="none"></span>Commons Logging Bridge</a></li>
<li><a href="../log4j-1.2-api.html" title="Log4j 1.2 API"><span class="none"></span>Log4j 1.2 API</a></li>
<li><a href="../log4j-slf4j-impl.html" title="SLF4J Binding"><span class="none"></span>SLF4J Binding</a></li>
<li><a href="../log4j-jul.html" title="JUL Adapter"><span class="none"></span>JUL Adapter</a></li>
<li><a href="../log4j-jpl.html" title="JDK Platform Logger"><span class="none"></span>JDK Platform Logger</a></li>
<li><a href="../log4j-to-slf4j.html" title="Log4j 2 to SLF4J Adapter"><span class="none"></span>Log4j 2 to SLF4J Adapter</a></li>
<li><a href="../log4j-flume-ng.html" title="Apache Flume Appender"><span class="none"></span>Apache Flume Appender</a></li>
<li><a href="../log4j-taglib.html" title="Log4j Tag Library"><span class="none"></span>Log4j Tag Library</a></li>
<li><a href="../log4j-jmx-gui.html" title="Log4j JMX GUI"><span class="none"></span>Log4j JMX GUI</a></li>
<li><a href="../log4j-web.html" title="Log4j Web Application Support"><span class="none"></span>Log4j Web Application Support</a></li>
<li><a href="../log4j-jakarta-web.html" title="Log4j Jakarta Web Application Support"><span class="none"></span>Log4j Jakarta Web Application Support</a></li>
<li><a href="../log4j-appserver.html" title="Log4j Application Server Integration"><span class="none"></span>Log4j Application Server Integration</a></li>
<li><a href="../log4j-couchdb.html" title="Log4j CouchDB appender"><span class="none"></span>Log4j CouchDB appender</a></li>
<li><a href="../log4j-mongodb3.html" title="Log4j MongoDB3 appender"><span class="none"></span>Log4j MongoDB3 appender</a></li>
<li><a href="../log4j-mongodb4.html" title="Log4j MongoDB4 appender"><span class="none"></span>Log4j MongoDB4 appender</a></li>
<li><a href="../log4j-cassandra.html" title="Log4j Cassandra appender"><span class="none"></span>Log4j Cassandra appender</a></li>
<li><a href="../log4j-iostreams.html" title="Log4j IO Streams"><span class="none"></span>Log4j IO Streams</a></li>
<li><a href="../log4j-docker.html" title="Log4j Docker Support"><span class="none"></span>Log4j Docker Support</a></li>
<li><a href="../log4j-kubernetes.html" title="Log4j Kubernetes Support"><span class="none"></span>Log4j Kubernetes Support</a></li>
<li><a href="../log4j-spring-boot.html" title="Log4j Spring Boot"><span class="none"></span>Log4j Spring Boot</a></li>
<li><a href="../log4j-spring-cloud-config-client.html" title="Log4j Spring Cloud Config Client"><span class="none"></span>Log4j Spring Cloud Config Client</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/tag.png" alt="Related Projects" style="border: 0;" /> Related Projects</li>
<li><a href="../../../chainsaw/2.x/index.html" title="Chainsaw"><span class="none"></span>Chainsaw</a></li>
<li><a href="../../../log4cxx/latest_stable/index.html" title="Log4Cxx"><span class="none"></span>Log4Cxx</a></li>
<li><a href="../../../log4j-audit/latest/index.html" title="Log4j Audit"><span class="none"></span>Log4j Audit</a></li>
<li><a href="../../kotlin" title="Log4j Kotlin"><span class="none"></span>Log4j Kotlin</a></li>
<li><a href="../../scala" title="Log4j Scala"><span class="none"></span>Log4j Scala</a></li>
<li><a href="../../transform" title="Log4j Transform"><span class="none"></span>Log4j Transform</a></li>
<li><a href="../../../log4net/index.html" title="Log4Net"><span class="none"></span>Log4Net</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/link.png" alt="Legacy Sites" style="border: 0;" /> Legacy Sites</li>
<li><a href="../../log4j-2.12.4/" title="Log4j 2.12.4 - Java 7"><span class="none"></span>Log4j 2.12.4 - Java 7</a></li>
<li><a href="../../log4j-2.3.2/" title="Log4j 2.3.2 - Java 6"><span class="none"></span>Log4j 2.3.2 - Java 6</a></li>
<li><a href="../../1.2/" title="Log4j 1.2 - End of Life"><span class="none"></span>Log4j 1.2 - End of Life</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/info.png" alt="Project Information" style="border: 0;" /> Project Information</li>
<li><a href="../team.html" title="Project Team"><span class="none"></span>Project Team</a></li>
<li><a href="https://www.apache.org/licenses/LICENSE-2.0" class="externalLink" title="Project License"><span class="none"></span>Project License</a></li>
<li><a href="https://github.com/apache/logging-log4j2" class="externalLink" title="Source Repository"><span class="none"></span>Source Repository</a></li>
<li><a href="../runtime-dependencies.html" title="Runtime Dependencies"><span class="none"></span>Runtime Dependencies</a></li>
<li><a href="../javadoc.html" title="Javadoc"><span class="none"></span>Javadoc</a></li>
<li><a href="../thanks.html" title="Thanks"><span class="none"></span>Thanks</a></li>
</ul>
</nav>
<div class="well sidebar-nav">
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a>
</div>
</div>
</header>
<main id="bodyColumn" class="span10" >
<h1>JSON Template Layout</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p><code>JsonTemplateLayout</code> is a customizable, efficient, and garbage-free JSON
generating layout. It encodes <code>LogEvent</code>s according to the structure described
by the JSON template provided. In a nutshell, it shines with its</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Customizable JSON structure (see <code>eventTemplate[Uri]</code> and
<code>stackTraceElementTemplate[Uri]</code> <a href="#layout-config">layout configuration</a> parameters)</p>
</li>
<li>
<p>Customizable timestamp formatting (see <a href="#event-template-resolver-timestamp"><code>timestamp</code></a>
event template resolver)</p>
</li>
<li>
<p>Feature rich exception formatting (see <a href="#event-template-resolver-exception"><code>exception</code></a>
and <a href="#event-template-resolver-exceptionRootCause"><code>exceptionRootCause</code></a> event template resolvers)</p>
</li>
<li>
<p><a href="#extending">Extensible plugin support</a></p>
</li>
<li>
<p>Customizable object <a href="#recycling-strategy">recycling strategy</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="usage">Usage</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Adding <code>log4j-layout-template-json</code> artifact to your list of dependencies is
enough to enable access to <code>JsonTemplateLayout</code> in your Log4j configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;dependency&gt;
&lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
&lt;artifactId&gt;log4j-layout-template-json&lt;/artifactId&gt;
&lt;version&gt;2.23.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>For instance, given the following JSON template modelling
<a href="https://www.elastic.co/guide/en/ecs/current/ecs-reference.html">the Elastic Common Schema (ECS) specification</a>
(accessible via <code>classpath:EcsLayout.json</code>)</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"@timestamp": {
"$resolver": "timestamp",
"pattern": {
"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
"timeZone": "UTC"
}
},
"ecs.version": "1.2.0",
"log.level": {
"$resolver": "level",
"field": "name"
},
"message": {
"$resolver": "message",
"stringified": true
},
"process.thread.name": {
"$resolver": "thread",
"field": "name"
},
"log.logger": {
"$resolver": "logger",
"field": "name"
},
"labels": {
"$resolver": "mdc",
"flatten": true,
"stringified": true
},
"tags": {
"$resolver": "ndc"
},
"error.type": {
"$resolver": "exception",
"field": "className"
},
"error.message": {
"$resolver": "exception",
"field": "message"
},
"error.stack_trace": {
"$resolver": "exception",
"field": "stackTrace",
"stackTrace": {
"stringified": true
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>in combination with the below <code>log4j2.xml</code> configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;JsonTemplateLayout eventTemplateUri="classpath:EcsLayout.json"/&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>or with the below <code>log4j2.properties</code> configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ini" data-lang="ini">appender.console.layout.type = JsonTemplateLayout
appender.console.layout.eventTemplateUri = classpath:EcsLayout.json</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>JsonTemplateLayout</code> generates JSON as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"@timestamp": "2017-05-25T19:56:23.370Z",
"ecs.version": "1.2.0",
"log.level": "ERROR",
"message": "Hello, error!",
"process.thread.name": "main",
"log.logger": "org.apache.logging.log4j.JsonTemplateLayoutDemo",
"error.type": "java.lang.RuntimeException",
"error.message": "test",
"error.stack_trace": "java.lang.RuntimeException: test\n\tat org.apache.logging.log4j.JsonTemplateLayoutDemo.main(JsonTemplateLayoutDemo.java:11)\n"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="layout-config">Layout Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>JsonTemplateLayout</code> is configured with the following parameters:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 1. <code>JsonTemplateLayout</code> parameters</caption>
<colgroup>
<col style="width: 16.6666%;"/>
<col style="width: 16.6666%;"/>
<col style="width: 66.6668%;"/>
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Parameter Name</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Type</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Description</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>charset</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Charset</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Charset</code> used for <code>String</code> encoding</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>locationInfoEnabled</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>boolean</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">toggles access to the <code>LogEvent</code> source; file name, line number, etc.
(defaults to <code>false</code> set by <code>log4j.layout.jsonTemplate.locationInfoEnabled</code>
property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>stackTraceEnabled</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>boolean</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">toggles access to the stack traces (defaults to <code>true</code> set by
<code>log4j.layout.jsonTemplate.stackTraceEnabled</code> property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>eventTemplate</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">inline JSON template for rendering <code>LogEvent</code>s (has priority over
<code>eventTemplateUri</code>, defaults to <code>null</code> set by
<code>log4j.layout.jsonTemplate.eventTemplate</code> property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>eventTemplateUri</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">URI pointing to the JSON template for rendering <code>LogEvent</code>s (defaults to
<code>classpath:EcsLayout.json</code> set by <code>log4j.layout.jsonTemplate.eventTemplateUri</code>
property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>eventTemplateRootObjectKey</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">if present, the event template is put into a JSON object composed of a single
member with the provided key (defaults to <code>null</code> set by
<code>log4j.layout.jsonTemplate.eventTemplateRootObjectKey</code>
property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>eventTemplateAdditionalField</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>EventTemplateAdditionalField[]</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">additional key-value pairs appended to the root of the event template</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>stackTraceElementTemplate</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">inline JSON template for rendering <code>StackTraceElement</code>s (has priority over
<code>stackTraceElementTemplateUri</code>, defaults to <code>null</code> set by
<code>log4j.layout.jsonTemplate.stackTraceElementTemplate</code> property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>stackTraceElementTemplateUri</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">URI pointing to the JSON template for rendering <code>StackTraceElement</code>s
(defaults to <code>classpath:StackTraceElementLayout.json</code> set by
<code>log4j.layout.jsonTemplate.stackTraceElementTemplateUri</code> property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>eventDelimiter</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">delimiter used for separating rendered <code>LogEvent</code>s (defaults to
<code>System.lineSeparator()</code> set by <code>log4j.layout.jsonTemplate.eventDelimiter</code>
property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nullEventDelimiterEnabled</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>boolean</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">append <code>\0</code> (<code>null</code>) character to the end of every <code>eventDelimiter</code>
separating rendered <code>LogEvent</code>s (defaults to <code>false</code> set by
<code>log4j.layout.jsonTemplate.nullEventDelimiterEnabled</code> property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>maxStringLength</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>int</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">truncate string values longer than the specified limit (defaults to 16384 set
by <code>log4j.layout.jsonTemplate.maxStringLength</code> property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>truncatedStringSuffix</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">suffix to append to strings truncated due to exceeding <code>maxStringLength</code>
(defaults to <code></code> set by <code>log4j.layout.jsonTemplate.truncatedStringSuffix</code>
property)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>recyclerFactory</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>RecyclerFactory</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">recycling strategy that can either be <code>dummy</code>, <code>threadLocal</code>, or <code>queue</code>
(set by <code>log4j.layout.jsonTemplate.recyclerFactory</code> property)</p></td>
</tr>
</tbody>
</table>
<div class="sect2">
<h3 id="additional-event-template-fields">Additional event template fields</h3>
<div class="paragraph">
<p>Additional event template fields are a convenient short-cut to add custom fields
to a template or override the existing ones. Following configuration overrides
the <code>host</code> field of the <code>GelfLayout.json</code> template and adds two new custom
fields:</p>
</div>
<div class="listingblock">
<div class="title">XML configuration with additional fields</div>
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;JsonTemplateLayout eventTemplateUri="classpath:GelfLayout.json"&gt;
&lt;EventTemplateAdditionalField key="host" value="www.apache.org"/&gt;
&lt;EventTemplateAdditionalField key="_serviceName" value="auth-service"/&gt;
&lt;EventTemplateAdditionalField key="_containerId" value="6ede3f0ca7d9"/&gt;
&lt;/JsonTemplateLayout&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The default <code>format</code> for the added new fields are <code>String</code>.
One can also provide JSON-formatted additional fields:</p>
</div>
<div class="listingblock">
<div class="title">XML-formatted configuration with JSON-formatted additional fields</div>
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;JsonTemplateLayout eventTemplateUri="classpath:GelfLayout.json"&gt;
&lt;EventTemplateAdditionalField
key="marker"
format="JSON"
value='{"$resolver": "marker", "field": "name"}'/&gt;
&lt;EventTemplateAdditionalField
key="aNumber"
format="JSON"
value="1"/&gt;
&lt;EventTemplateAdditionalField
key="aList"
format="JSON"
value='[1, 2, "three"]'/&gt;
&lt;/JsonTemplateLayout&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Additional event template fields can very well be introduced using properties-,
YAML-, and JSON-formatted configurations:</p>
</div>
<div class="listingblock">
<div class="title">Properties-formatted configuration with JSON-formatted additional fields</div>
<div class="content">
<pre class="highlight"><code class="language-properties" data-lang="properties">appender.console.layout.type = JsonTemplateLayout
appender.console.layout.eventTemplateUri = classpath:GelfLayout.json
appender.console.layout.eventTemplateAdditionalField[0].type = EventTemplateAdditionalField
appender.console.layout.eventTemplateAdditionalField[0].key = marker
appender.console.layout.eventTemplateAdditionalField[0].value = {"$resolver": "marker", "field": "name"}
appender.console.layout.eventTemplateAdditionalField[0].format = JSON
appender.console.layout.eventTemplateAdditionalField[1].type = EventTemplateAdditionalField
appender.console.layout.eventTemplateAdditionalField[1].key = aNumber
appender.console.layout.eventTemplateAdditionalField[1].value = 1
appender.console.layout.eventTemplateAdditionalField[1].format = JSON
appender.console.layout.eventTemplateAdditionalField[2].type = EventTemplateAdditionalField
appender.console.layout.eventTemplateAdditionalField[2].key = aList
appender.console.layout.eventTemplateAdditionalField[2].value = [1, 2, "three"]
appender.console.layout.eventTemplateAdditionalField[2].format = JSON</code></pre>
</div>
</div>
<div class="listingblock">
<div class="title">YAML-formatted configuration with JSON-formatted additional fields</div>
<div class="content">
<pre class="highlight"><code class="language-yaml" data-lang="yaml">JsonTemplateLayout:
eventTemplateAdditionalField:
- key: "marker"
value: '{"$resolver": "marker", "field": "name"}'
format: "JSON"
- key: "aNumber"
value: "1"
format: "JSON"
- key: "aList"
value: '[1, 2, "three"]'
format: "JSON"</code></pre>
</div>
</div>
<div class="listingblock">
<div class="title">JSON-formatted configuration with JSON-formatted additional fields</div>
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"JsonTemplateLayout": {
"eventTemplateAdditionalField": [
{
"key": "marker",
"value": "{\"$resolver\": \"marker\", \"field\": \"name\"}",
"format": "JSON"
},
{
"key": "aNumber",
"value": "1",
"format": "JSON"
},
{
"key": "aList",
"value": "[1, 2, \"three\"]",
"format": "JSON"
}
]
}
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="recycling-strategy">Recycling strategy</h3>
<div class="paragraph">
<p><code>RecyclerFactory</code> plays a crucial role for determining the memory footprint of
the layout. Template resolvers employ it to create recyclers for objects that
they can reuse. The behavior of each <code>RecyclerFactory</code> and when one should
prefer one over another is explained below:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>dummy</code> performs no recycling, hence each recycling attempt will result in a
new instance. This will obviously create a load on the garbage-collector. It
is a good choice for applications with low and medium log rate.</p>
</li>
<li>
<p><code>threadLocal</code> performs the best, since every instance is stored in
<code>ThreadLocal</code>s and accessed without any synchronization cost. Though this
might not be a desirable option for applications running with hundreds of
threads or more, e.g., a web servlet.</p>
</li>
<li>
<p><code>queue</code> is the best of both worlds. It allows recycling of objects up to a
certain number (<code>capacity</code>). When this limit is exceeded due to excessive
concurrent load (e.g., <code>capacity</code> is 50 but there are 51 threads concurrently
trying to log), it starts allocating. <code>queue</code> is a good strategy where
<code>threadLocal</code> is not desirable.</p>
<div class="paragraph">
<p><code>queue</code> also accepts optional <code>supplier</code> (of type <code>java.util.Queue</code>, defaults to
<code>org.jctools.queues.MpmcArrayQueue.new</code> if JCTools is in the classpath;
otherwise <code>java.util.concurrent.ArrayBlockingQueue.new</code>) and <code>capacity</code> (of
type <code>int</code>, defaults to <code>max(8,2*cpuCount+1)</code>) parameters:</p>
</div>
<div class="listingblock">
<div class="title">Example configurations of <code>queue</code> recycling strategy</div>
<div class="content">
<pre class="highlight"><code>queue:supplier=org.jctools.queues.MpmcArrayQueue.new
queue:capacity=10
queue:supplier=java.util.concurrent.ArrayBlockingQueue.new,capacity=50</code></pre>
</div>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>The default <code>RecyclerFactory</code> is <code>threadLocal</code>, if
<code>log4j2.enable.threadlocals=true</code>; otherwise, <code>queue</code>.</p>
</div>
<div class="paragraph">
<p>See <a href="#extending-recycler">Extending Recycler Factories</a> for details on how to introduce custom
<code>RecyclerFactory</code> implementations.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="template-config">Template Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Templates are configured by means of the following <code>JsonTemplateLayout</code>
parameters:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>eventTemplate[Uri]</code> (for serializing <code>LogEvent</code>s)</p>
</li>
<li>
<p><code>stackTraceElementTemplate[Uri]</code> (for serializing <code>StackStraceElement</code>s)</p>
</li>
<li>
<p><code>eventTemplateAdditionalField</code> (for extending the used event template)</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="event-templates">Event Templates</h3>
<div class="paragraph">
<p><code>eventTemplate[Uri]</code> describes the JSON structure <code>JsonTemplateLayout</code> uses to
serialize <code>LogEvent</code>s. The default configuration (accessible by
<code>log4j.layout.jsonTemplate.eventTemplate[Uri]</code> property) is set to
<code>classpath:EcsLayout.json</code> provided by the <code>log4j-layout-template-json</code>
artifact, which contains the following predefined event templates:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/apache/logging-log4j2/tree/main/log4j-layout-template-json/src/main/resources/EcsLayout.json"><code>EcsLayout.json</code></a>
described by <a href="https://www.elastic.co/guide/en/ecs/current/ecs-reference.html">the Elastic Common Schema (ECS) specification</a></p>
</li>
<li>
<p><a href="https://github.com/apache/logging-log4j2/tree/main/log4j-layout-template-json/src/main/resources/LogstashJsonEventLayoutV1.json"><code>LogstashJsonEventLayoutV1.json</code></a>
described in <a href="https://github.com/logstash/log4j-jsonevent-layout">Logstash
<code>json_event</code> pattern for log4j</a></p>
</li>
<li>
<p><a href="https://github.com/apache/logging-log4j2/tree/main/log4j-layout-template-json/src/main/resources/GelfLayout.json"><code>GelfLayout.json</code></a>
described by <a href="https://docs.graylog.org/en/3.1/pages/gelf.html#gelf-payload-specification">the
Graylog Extended Log Format (GELF) payload specification</a> with additional
<code>_thread</code> and <code>_logger</code> fields. (Here it is advised to override the obligatory
<code>host</code> field with a user provided constant via
<a href="#additional-event-template-fields">additional event template fields</a>
to avoid <code>hostName</code> property lookup at runtime, which incurs an extra cost.)</p>
</li>
<li>
<p><a href="https://github.com/apache/logging-log4j2/tree/main/log4j-layout-template-json/src/main/resources/GcpLayout.json"><code>GcpLayout.json</code></a>
described by <a href="https://cloud.google.com/logging/docs/structured-logging">Google
Cloud Platform structured logging</a> with additional
<code>_thread</code>, <code>_logger</code> and <code>_exception</code> fields. The exception trace, if any,
is written to the <code>_exception</code> field as well as the <code>message</code> field –
the former is useful for explicitly searching/analyzing structured exception
information, while the latter is Google&#8217;s expected place for the exception,
and integrates with <a href="https://cloud.google.com/error-reporting">Google Error Reporting</a>.</p>
</li>
<li>
<p><a href="https://github.com/apache/logging-log4j2/tree/main/log4j-layout-template-json/src/main/resources/JsonLayout.json"><code>JsonLayout.json</code></a>
providing the exact JSON structure generated by <a href="layouts.html#JSONLayout"><code>JsonLayout</code></a>
with the exception of <code>thrown</code> field. (<code>JsonLayout</code> serializes the <code>Throwable</code>
as is via Jackson <code>ObjectMapper</code>, whereas <code>JsonLayout.json</code> template of
<code>JsonTemplateLayout</code> employs the <code>StackTraceElementLayout.json</code> template
for stack traces to generate a document-store-friendly flat structure.)</p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="event-template-resolvers">Event Template Resolvers</h4>
<div class="paragraph">
<p>Event template resolvers consume a <code>LogEvent</code> and render a certain property of
it at the point of the JSON where they are declared. For instance, <code>marker</code>
resolver renders the marker of the event, <code>level</code> resolver renders the level,
and so on. An event template resolver is denoted with a special object
containing a`$resolver` key:</p>
</div>
<div class="listingblock">
<div class="title">Example event template demonstrating the usage of <code>level</code> resolver</div>
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"version": "1.0",
"level": {
"$resolver": "level",
"field": "name"
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Here <code>version</code> field will be rendered as is, while <code>level</code> field will be
populated by the <code>level</code> resolver. That is, this template will generate JSON
similar to the following:</p>
</div>
<div class="listingblock">
<div class="title">Example JSON generated from the demonstrated event template</div>
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"version": "1.0",
"level": "INFO"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The complete list of available event template resolvers are provided below in
detail.</p>
</div>
<div class="sect4">
<h5 id="event-template-resolver-counter"><code>counter</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = [ start ] , [ overflowing ] , [ stringified ]
start = "start" -&gt; number
overflowing = "overflowing" -&gt; boolean
stringified = "stringified" -&gt; boolean</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves a number from an internal counter.</p>
</div>
<div class="paragraph">
<p>Unless provided, <code>start</code> and <code>overflowing</code> are respectively set to zero and
<code>true</code> by default.</p>
</div>
<div class="paragraph">
<p>When <code>stringified</code> is enabled, which is set to `false by default, the resolved
number will be converted to a string.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<div class="title">Warning</div>
</td>
<td class="content">
<div class="paragraph">
<p>When <code>overflowing</code> is set to <code>true</code>, the internal counter is created using a
<code>long</code>, which is subject to overflow while incrementing, though garbage-free.
Otherwise, a <code>BigInteger</code> is used, which does not overflow, but incurs
allocation costs.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect5">
<h6 id="examples">Examples</h6>
<div class="paragraph">
<p>Resolves a sequence of numbers starting from 0. Once <code>Long.MAX_VALUE</code> is
reached, counter overflows to <code>Long.MIN_VALUE</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "counter"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves a sequence of numbers starting from 1000. Once <code>Long.MAX_VALUE</code> is
reached, counter overflows to <code>Long.MIN_VALUE</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "counter",
"start": 1000
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves a sequence of numbers starting from 0 and keeps on doing as long as
JVM heap allows.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "counter",
"overflowing": false
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-caseConverter"><code>caseConverter</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = case , input , [ locale ] , [ errorHandlingStrategy ]
input = JSON
case = "case" -&gt; ( "upper" | "lower" )
locale = "locale" -&gt; (
language |
( language , "_" , country ) |
( language , "_" , country , "_" , variant )
)
errorHandlingStrategy = "errorHandlingStrategy" -&gt; (
"fail" |
"pass" |
"replace"
)
replacement = "replacement" -&gt; JSON</code></pre>
</div>
</div>
<div class="paragraph">
<p>Converts the case of string values.</p>
</div>
<div class="paragraph">
<p><code>input</code> can be any available template value; e.g., a JSON literal, a lookup
string, an object pointing to another resolver.</p>
</div>
<div class="paragraph">
<p>Unless provided, <code>locale</code> points to the one returned by
<code>JsonTemplateLayoutDefaults.getLocale()</code>, which is configured by
<code>log4j.layout.jsonTemplate.locale</code> system property and by default set to the
default system locale.</p>
</div>
<div class="paragraph">
<p><code>errorHandlingStrategy</code> determines the behavior when either the input doesn&#8217;t
resolve to a string value or case conversion throws an exception:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>fail</code> propagates the failure</p>
</li>
<li>
<p><code>pass</code> causes the resolved value to be passed as is</p>
</li>
<li>
<p><code>replace</code> suppresses the failure and replaces it with the <code>replacement</code>,
which is set to <code>null</code> by default</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>errorHandlingStrategy</code> is set to <code>replace</code> by default.</p>
</div>
<div class="paragraph">
<p>Most of the time JSON logs are persisted to a storage solution (e.g.,
Elasticsearch) that keeps a statically-typed index on fields. Hence, if a field
is always expected to be of type string, using non-string <code>replacement</code>s or
<code>pass</code> in <code>errorHandlingStrategy</code> might result in type incompatibility issues at
the storage level.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<div class="title">Warning</div>
</td>
<td class="content">
<div class="paragraph">
<p>Unless the input value is <code>pass</code>ed intact or <code>replace</code>d, case conversion is
not garbage-free.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect5">
<h6 id="examples_2">Examples</h6>
<div class="paragraph">
<p>Convert the resolved log level strings to upper-case:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "caseConverter",
"case": "upper",
"input": {
"$resolver": "level",
"field": "name"
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Convert the resolved <code>USER</code> environment variable to lower-case using <code>nl_NL</code>
locale:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "caseConverter",
"case": "lower",
"locale": "nl_NL",
"input": "${env:USER}"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Convert the resolved <code>sessionId</code> thread context data (MDC) to lower-case:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "caseConverter",
"case": "lower",
"input": {
"$resolver": "mdc",
"key": "sessionId"
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Above, if <code>sessionId</code> MDC resolves to a, say, number, case conversion will fail.
Since <code>errorHandlingStrategy</code> is set to <code>replace</code> and replacement is set to
<code>null</code> by default, the resolved value will be <code>null</code>. One can suppress this
behavior and let the resolved <code>sessionId</code> number be left as is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "caseConverter",
"case": "lower",
"input": {
"$resolver": "mdc",
"key": "sessionId"
},
"errorHandlingStrategy": "pass"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>or replace it with a custom string:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "caseConverter",
"case": "lower",
"input": {
"$resolver": "mdc",
"key": "sessionId"
},
"errorHandlingStrategy": "replace",
"replacement": "unknown"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-endOfBatch"><code>endOfBatch</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "endOfBatch"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves <code>logEvent.isEndOfBatch()</code> boolean flag.</p>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-exception"><code>exception</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = field , [ stringified ] , [ stackTrace ]
field = "field" -&gt; ( "className" | "message" | "stackTrace" )
stackTrace = "stackTrace" -&gt; (
[ stringified ]
, [ elementTemplate ]
)
stringified = "stringified" -&gt; ( boolean | truncation )
truncation = "truncation" -&gt; (
[ suffix ]
, [ pointMatcherStrings ]
, [ pointMatcherRegexes ]
)
suffix = "suffix" -&gt; string
pointMatcherStrings = "pointMatcherStrings" -&gt; string[]
pointMatcherRegexes = "pointMatcherRegexes" -&gt; string[]
elementTemplate = "elementTemplate" -&gt; object</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves fields of the <code>Throwable</code> returned by <code>logEvent.getThrown()</code>.</p>
</div>
<div class="paragraph">
<p><code>stringified</code> is set to <code>false</code> by default. <code>stringified</code> at the root level is
<strong>deprecated</strong> in favor of <code>stackTrace.stringified</code>, which has precedence if both
are provided.</p>
</div>
<div class="paragraph">
<p><code>pointMatcherStrings</code> and <code>pointMatcherRegexes</code> enable the truncation of
stringified stack traces after the given matching point. If both parameters are
provided, <code>pointMatcherStrings</code> will be checked first.</p>
</div>
<div class="paragraph">
<p>If a stringified stack trace truncation takes place, it will be indicated with a
<code>suffix</code>, which by default is set to the configured <code>truncatedStringSuffix</code> in
the layout, unless explicitly provided. Every truncation suffix is prefixed with
a newline.</p>
</div>
<div class="paragraph">
<p>Stringified stack trace truncation operates in <code>Caused by:</code> and <code>Suppressed:</code>
label blocks. That is, matchers are executed against each label in isolation.</p>
</div>
<div class="paragraph">
<p><code>elementTemplate</code> is an object describing the template to be used while
resolving the <code>StackTraceElement</code> array. If <code>stringified</code> is set to <code>true</code>,
<code>elementTemplate</code> will be discarded. By default, <code>elementTemplate</code> is set to
<code>null</code> and rather populated from the layout configuration. That is, the stack
trace element template can also be provided using
<code>stackTraceElementTemplate[Uri]</code> layout configuration parameters. The template
to be employed is determined in the following order:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>elementTemplate</code> provided in the resolver configuration</p>
</li>
<li>
<p><code>stackTraceElementTemplate</code> parameter from layout configuration
(the default is populated from <code>log4j.layout.jsonTemplate.stackTraceElementTemplate</code>
system property)</p>
</li>
<li>
<p><code>stackTraceElementTemplateUri</code> parameter from layout configuration
(the default is populated from <code>log4j.layout.jsonTemplate.stackTraceElementTemplateUri</code>
system property)</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>See <a href="#stack-trace-element-templates">Stack Trace Element Templates</a>
for the list of available resolvers in a stack trace element template.</p>
</div>
<div class="paragraph">
<p>Note that this resolver is toggled by
<code>log4j.layout.jsonTemplate.stackTraceEnabled</code> property.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<div class="title">Warning</div>
</td>
<td class="content">
<div class="paragraph">
<p>Since <code>Throwable#getStackTrace()</code> clones the original <code>StackTraceElement[]</code>,
access to (and hence rendering of) stack traces are not garbage-free.</p>
</div>
<div class="paragraph">
<p>Each <code>pointMatcherRegexes</code> item triggers a <code>Pattern#matcher()</code> call, which is
not garbage-free either.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect5">
<h6 id="examples_3">Examples</h6>
<div class="paragraph">
<p>Resolve <code>logEvent.getThrown().getClass().getCanonicalName()</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "exception",
"field": "className"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the stack trace into a list of <code>StackTraceElement</code> objects:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "exception",
"field": "stackTrace"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the stack trace into a string field:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "exception",
"field": "stackTrace",
"stackTrace": {
"stringified": true
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the stack trace into a string field such that the content will be
truncated after the given point matcher:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "exception",
"field": "stackTrace",
"stackTrace": {
"stringified": {
"truncation": {
"suffix": "... [truncated]",
"pointMatcherStrings": ["at javax.servlet.http.HttpServlet.service"]
}
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the stack trace into an object described by the provided stack trace
element template:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "exception",
"field": "stackTrace",
"stackTrace": {
"elementTemplate": {
"class": {
"$resolver": "stackTraceElement",
"field": "className"
},
"method": {
"$resolver": "stackTraceElement",
"field": "methodName"
},
"file": {
"$resolver": "stackTraceElement",
"field": "fileName"
},
"line": {
"$resolver": "stackTraceElement",
"field": "lineNumber"
}
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>See <a href="#stack-trace-element-templates">Stack Trace Element Templates</a> for further details on resolvers available
for <code>StackTraceElement</code> templates.</p>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-exceptionRootCause"><code>exceptionRootCause</code></h5>
<div class="paragraph">
<p>Resolves the fields of the innermost <code>Throwable</code> returned by
<code>logEvent.getThrown()</code>. Its syntax and garbage-footprint are identical to the
<a href="#event-template-resolver-exception"><code>exception</code></a> resolver.</p>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-level"><code>level</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = field , [ severity ]
field = "field" -&gt; ( "name" | "severity" )
severity = severity-field
severity-field = "field" -&gt; ( "keyword" | "code" )</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves the fields of the <code>logEvent.getLevel()</code>.</p>
</div>
<div class="sect5">
<h6 id="examples_4">Examples</h6>
<div class="paragraph">
<p>Resolve the level name:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "level",
"field": "name"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the <a href="https://en.wikipedia.org/wiki/Syslog#Severity_levels">Syslog severity</a>
keyword:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "level",
"field": "severity",
"severity": {
"field": "keyword"
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the <a href="https://en.wikipedia.org/wiki/Syslog#Severity_levels">Syslog severity</a>
code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "level",
"field": "severity",
"severity": {
"field": "code"
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-logger"><code>logger</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = "field" -&gt; ( "name" | "fqcn" )</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves <code>logEvent.getLoggerFqcn()</code> and <code>logEvent.getLoggerName()</code>.</p>
</div>
<div class="sect5">
<h6 id="examples_5">Examples</h6>
<div class="paragraph">
<p>Resolve the logger name:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "logger",
"field": "name"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the logger&#8217;s fully qualified class name:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "logger",
"field": "fqcn"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-main"><code>main</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = ( index | key )
index = "index" -&gt; number
key = "key" -&gt; string</code></pre>
</div>
</div>
<div class="paragraph">
<p>Performs <a href="lookups.html#AppMainArgsLookup">Main Argument Lookup</a> for the
given <code>index</code> or <code>key</code>.</p>
</div>
<div class="sect5">
<h6 id="examples_6">Examples</h6>
<div class="paragraph">
<p>Resolve the 1st <code>main()</code> method argument:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "main",
"index": 0
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the argument coming right after <code>--userId</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "main",
"key": "--userId"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-map"><code>map</code></h5>
<div class="paragraph">
<p>Resolves <code>MapMessage</code>s. See <a href="#map-resolver-template">Map Resolver Template</a>
for details.</p>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-marker"><code>marker</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = "field" -&gt; ( "name" | "parents" )</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves <code>logEvent.getMarker()</code>.</p>
</div>
<div class="sect5">
<h6 id="examples_7">Examples</h6>
<div class="paragraph">
<p>Resolve the marker name:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "marker",
"field": "name"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the names of the marker&#8217;s parents:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "marker",
"field": "parents"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-mdc"><code>mdc</code></h5>
<div class="paragraph">
<p>Resolves Mapped Diagnostic Context (MDC), aka. Thread Context Data. See
<a href="#map-resolver-template">Map Resolver Template</a> for details.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<div class="title">Warning</div>
</td>
<td class="content">
<div class="paragraph">
<p><code>log4j2.garbagefreeThreadContextMap</code> flag needs to be turned on to iterate
the map without allocations.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-message"><code>message</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = [ stringified ] , [ fallbackKey ]
stringified = "stringified" -&gt; boolean
fallbackKey = "fallbackKey" -&gt; string</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves <code>logEvent.getMessage()</code>.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<div class="title">Warning</div>
</td>
<td class="content">
<div class="paragraph">
<p>For simple string messages, the resolution is performed without allocations.
For <code>ObjectMessage</code>s and <code>MultiformatMessage</code>s, it depends.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect5">
<h6 id="examples_8">Examples</h6>
<div class="paragraph">
<p>Resolve the message into a string:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "message",
"stringified": true
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the message such that if it is an <code>ObjectMessage</code> or a
<code>MultiformatMessage</code> with JSON support, its type (string, list, object, etc.)
will be retained:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "message"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Given the above configuration, a <code>SimpleMessage</code> will generate a <code>"sample log
message"</code>, whereas a <code>MapMessage</code> will generate a <code>{"action": "login",
"sessionId": "87asd97a"}</code>. Certain indexed log storage systems (e.g.,
<a href="https://www.elastic.co/elasticsearch/">Elasticsearch</a>) will not allow both values
to coexist due to type mismatch: one is a <code>string</code> while the other is an <code>object</code>.
Here one can use a <code>fallbackKey</code> to work around the problem:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "message",
"fallbackKey": "formattedMessage"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Using this configuration, a <code>SimpleMessage</code> will generate a
<code>{"formattedMessage": "sample log message"}</code> and a <code>MapMessage</code> will generate a
<code>{"action": "login", "sessionId": "87asd97a"}</code>. Note that both emitted JSONs are
of type <code>object</code> and have no type-conflicting fields.</p>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-messageParameter"><code>messageParameter</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = [ stringified ] , [ index ]
stringified = "stringified" -&gt; boolean
index = "index" -&gt; number</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves <code>logEvent.getMessage().getParameters()</code>.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<div class="title">Warning</div>
</td>
<td class="content">
<div class="paragraph">
<p>Regarding garbage footprint, <code>stringified</code> flag translates to
<code>String.valueOf(value)</code>, hence mind not-<code>String</code>-typed values. Further,
<code>logEvent.getMessage()</code> is expected to implement <code>ParameterVisitable</code> interface,
which is the case if <code>log4j2.enableThreadLocals</code> property set to true.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect5">
<h6 id="examples_9">Examples</h6>
<div class="paragraph">
<p>Resolve the message parameters into an array:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "messageParameter"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the string representation of all message parameters into an array:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "messageParameter",
"stringified": true
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the first message parameter:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "messageParameter",
"index": 0
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the string representation of the first message parameter:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "messageParameter",
"index": 0,
"stringified": true
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-ndc"><code>ndc</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = [ pattern ]
pattern = "pattern" -&gt; string</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves the Nested Diagnostic Context (NDC), aka. Thread Context Stack,
<code>String[]</code> returned by <code>logEvent.getContextStack()</code>.</p>
</div>
<div class="sect5">
<h6 id="examples_10">Examples</h6>
<div class="paragraph">
<p>Resolve all NDC values into a list:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "ndc"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve all NDC values matching with the <code>pattern</code> regex:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "ndc",
"pattern": "user(Role|Rank):\\w+"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-pattern"><code>pattern</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = pattern , [ stackTraceEnabled ]
pattern = "pattern" -&gt; string
stackTraceEnabled = "stackTraceEnabled" -&gt; boolean</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolver delegating to <a href="layouts.html#PatternLayout"><code>PatternLayout</code></a>.</p>
</div>
<div class="paragraph">
<p>The default value of <code>stackTraceEnabled</code> is inherited from the parent
<code>JsonTemplateLayout</code>.</p>
</div>
<div class="sect5">
<h6 id="examples_11">Examples</h6>
<div class="paragraph">
<p>Resolve the string produced by <code>%p %c{1.} [%t] %X{userId} %X %m%ex</code> pattern:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "pattern",
"pattern": "%p %c{1.} [%t] %X{userId} %X %m%ex"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-source"><code>source</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = "field" -&gt; (
"className" |
"fileName" |
"methodName" |
"lineNumber" )</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves the fields of the <code>StackTraceElement</code> returned by
<code>logEvent.getSource()</code>.</p>
</div>
<div class="paragraph">
<p>Note that this resolver is toggled by
<code>log4j.layout.jsonTemplate.locationInfoEnabled</code> property.</p>
</div>
<div class="sect5">
<h6 id="examples_12">Examples</h6>
<div class="paragraph">
<p>Resolve the line number:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "source",
"field": "lineNumber"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-thread"><code>thread</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = "field" -&gt; ( "name" | "id" | "priority" )</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves <code>logEvent.getThreadId()</code>, <code>logEvent.getThreadName()</code>,
<code>logEvent.getThreadPriority()</code>.</p>
</div>
<div class="sect5">
<h6 id="examples_13">Examples</h6>
<div class="paragraph">
<p>Resolve the thread name:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "thread",
"field": "name"
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="event-template-resolver-timestamp"><code>timestamp</code></h5>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = [ patternConfig | epochConfig ]
patternConfig = "pattern" -&gt; ( [ format ] , [ timeZone ] , [ locale ] )
format = "format" -&gt; string
timeZone = "timeZone" -&gt; string
locale = "locale" -&gt; (
language |
( language , "_" , country ) |
( language , "_" , country , "_" , variant )
)
epochConfig = "epoch" -&gt; ( unit , [ rounded ] )
unit = "unit" -&gt; (
"nanos" |
"millis" |
"secs" |
"millis.nanos" |
"secs.nanos" |
)
rounded = "rounded" -&gt; boolean</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolves <code>logEvent.getInstant()</code> in various forms.</p>
</div>
<div class="sect5">
<h6 id="examples_14">Examples</h6>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 2. <code>timestamp</code> template resolver examples</caption>
<colgroup>
<col style="width: 71.4285%;"/>
<col style="width: 28.5715%;"/>
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Configuration</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Output</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp"
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2020-02-07T13:38:47.098+02:00</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"pattern": {
"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
"timeZone": "UTC",
"locale": "en_US"
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2020-02-07T13:38:47.098Z</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"epoch": {
"unit": "secs"
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>1581082727.982123456</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"epoch": {
"unit": "secs",
"rounded": true
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>1581082727</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"epoch": {
"unit": "secs.nanos"
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>982123456</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"epoch": {
"unit": "millis"
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>1581082727982.123456</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"epoch": {
"unit": "millis",
"rounded": true
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>1581082727982</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"epoch": {
"unit": "millis.nanos"
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>123456</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "timestamp",
"epoch": {
"unit": "nanos"
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>1581082727982123456</code></p></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="map-resolver-template">Map Resolver Template</h4>
<div class="paragraph">
<p><code>ReadOnlyStringMap</code> is Log4j&#8217;s <code>Map&lt;String, Object&gt;</code> equivalent with
garbage-free accessors and heavily employed throughout the code base. It is the
data structure backing both Mapped Diagnostic Context (MDC), aka. Thread Context
Data and <code>MapMessage</code> implementations. Hence template resolvers for both of
these are provided by a single backend: <code>ReadOnlyStringMapResolver</code>. Put another
way, both <code>mdc</code> and <code>map</code> resolvers support identical configuration, behaviour,
and garbage footprint, which are detailed below.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = singleAccess | multiAccess
singleAccess = key , [ stringified ]
key = "key" -&gt; string
stringified = "stringified" -&gt; boolean
multiAccess = [ pattern ] , [ replacement ] , [ flatten ] , [ stringified ]
pattern = "pattern" -&gt; string
replacement = "replacement" -&gt; string
flatten = "flatten" -&gt; ( boolean | flattenConfig )
flattenConfig = [ flattenPrefix ]
flattenPrefix = "prefix" -&gt; string</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>singleAccess</code> resolves a single field, whilst <code>multiAccess</code> resolves a
multitude of fields. If <code>flatten</code> is provided, <code>multiAccess</code> merges the fields
with the parent, otherwise creates a new JSON object containing the values.</p>
</div>
<div class="paragraph">
<p>Enabling <code>stringified</code> flag converts each value to its string representation.</p>
</div>
<div class="paragraph">
<p>Regex provided in the <code>pattern</code> is used to match against the keys. If provided,
<code>replacement</code> will be used to replace the matched keys. These two are
effectively equivalent to <code>Pattern.compile(pattern).matcher(key).matches()</code> and
<code>Pattern.compile(pattern).matcher(key).replaceAll(replacement)</code> calls.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<div class="title">Warning</div>
</td>
<td class="content">
<div class="paragraph">
<p>Regarding garbage footprint, <code>stringified</code> flag translates to
<code>String.valueOf(value)</code>, hence mind not-<code>String</code>-typed values.</p>
</div>
<div class="paragraph">
<p><code>pattern</code> and <code>replacement</code> incur pattern matcher allocation costs.</p>
</div>
<div class="paragraph">
<p>Writing certain non-primitive values (e.g., <code>BigDecimal</code>, <code>Set</code>, etc.) to JSON
generates garbage, though most (e.g., <code>int</code>, <code>long</code>, <code>String</code>, <code>List</code>,
<code>boolean[]</code>, etc.) don&#8217;t.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>"$resolver"</code> is left out in the following examples, since it is to be
defined by the actual resolver, e.g., <code>map</code>, <code>mdc</code>.</p>
</div>
<div class="paragraph">
<p>Resolve the value of the field keyed with <code>user:role</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…",
"key": "user:role"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve the string representation of the <code>user:rank</code> field value:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…",
"key": "user:rank",
"stringified": true
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve all fields into an object:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve all fields into an object such that values are converted to string:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…",
"stringified": true
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve all fields whose keys match with the <code>user:(role|rank)</code> regex into an
object:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…",
"pattern": "user:(role|rank)"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Resolve all fields whose keys match with the <code>user:(role|rank)</code> regex into an
object after removing the <code>user:</code> prefix in the key:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…",
"pattern": "user:(role|rank)",
"replacement": "$1"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Merge all fields whose keys are matching with the <code>user:(role|rank)</code> regex into
the parent:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…",
"flatten": true,
"pattern": "user:(role|rank)"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>After converting the corresponding field values to string, merge all fields to
parent such that keys are prefixed with <code>_</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"$resolver": "…",
"stringified": true,
"flatten": {
"prefix": "_"
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="stack-trace-element-templates">Stack Trace Element Templates</h3>
<div class="paragraph">
<p><a href="#event-template-resolver-exception"><code>exception</code></a> and
<a href="#event-template-resolver-exceptionRootCause"><code>exceptionRootCause</code></a> event template resolvers can
serialize an exception stack trace (i.e., <code>StackTraceElement[]</code> returned by
<code>Throwable#getStackTrace()</code>) into a JSON array. While doing so, JSON templating
infrastructure is used again.</p>
</div>
<div class="paragraph">
<p><code>stackTraceElement[Uri]</code> describes the JSON structure <code>JsonTemplateLayout</code> uses
to format <code>StackTraceElement</code>s. The default configuration (accessible by
<code>log4j.layout.jsonTemplate.stackTraceElementTemplate[Uri]</code> property) is set to
<code>classpath:StackTraceElementLayout.json</code> provided by the
<code>log4j-layout-template-json</code> artifact:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"class": {
"$resolver": "stackTraceElement",
"field": "className"
},
"method": {
"$resolver": "stackTraceElement",
"field": "methodName"
},
"file": {
"$resolver": "stackTraceElement",
"field": "fileName"
},
"line": {
"$resolver": "stackTraceElement",
"field": "lineNumber"
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The allowed template configuration syntax is as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>config = "field" -&gt; (
"className" |
"fileName" |
"methodName" |
"lineNumber" )</code></pre>
</div>
</div>
<div class="paragraph">
<p>All above accesses to <code>StackTraceElement</code> is garbage-free.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="extending">Extending</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>JsonTemplateLayout</code> relies on Log4j <a href="plugins.html">plugin system</a> to build
up the features it provides. This enables feature customization a breeze for
users. As of this moment, following features are implemented by means of
plugins:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Event template resolvers (e.g., <code>exception</code>, <code>message</code>, <code>level</code> event template resolvers)</p>
</li>
<li>
<p>Event template interceptors (e.g., injection of <code>eventTemplateAdditionalField</code>)</p>
</li>
<li>
<p>Recycler factories</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Following sections cover these in detail.</p>
</div>
<div class="sect2">
<h3 id="extending-plugins">Plugin Preliminaries</h3>
<div class="paragraph">
<p>Log4j plugin system is the de facto extension mechanism embraced by various
Log4j components, including <code>JsonTemplateLayout</code>. Plugins make it possible
for extensible components <em>receive</em> feature implementations without any explicit
links in between. It is analogous to a
<a href="https://en.wikipedia.org/wiki/Dependency_injection">dependency injection</a>
framework, but curated for Log4j-specific needs.</p>
</div>
<div class="paragraph">
<p>In a nutshell, you annotate your classes with <code>@Plugin</code> and their (<code>static</code>)
creator methods with <code>@PluginFactory</code>. Last, you inform the Log4j plugin system
to discover these custom classes. This can be done either using <code>packages</code>
declared in your Log4j configuration or by various other ways described in
<a href="plugins.html">plugin system documentation</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="extending-event-resolvers">Extending Event Resolvers</h3>
<div class="paragraph">
<p>All available <a href="#event-template-resolvers">event template resolvers</a> are simple
plugins employed by <code>JsonTemplateLayout</code>. To add new ones, one just needs to
create their own <code>EventResolver</code> and instruct its injection via a
<code>@Plugin</code>-annotated <code>EventResolverFactory</code> class.</p>
</div>
<div class="paragraph">
<p>For demonstration purposes, below we will create a <code>randomNumber</code> event resolver.
Let&#8217;s start with the actual resolver:</p>
</div>
<div class="listingblock">
<div class="title">Custom random number event resolver</div>
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">package com.acme.logging.log4j.layout.template.json;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.layout.template.json.resolver.EventResolver;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
/**
* Resolves a random floating point number.
*
* &lt;h3&gt;Configuration&lt;/h3&gt;
*
* &lt;pre&gt;
* config = ( [ range ] )
* range = number[]
* &lt;/pre&gt;
*
* {@code range} is a number array with two elements, where the first number
* denotes the start (inclusive) and the second denotes the end (exclusive).
* {@code range} is optional and by default set to {@code [0, 1]}.
*
* &lt;h3&gt;Examples&lt;/h3&gt;
*
* Resolve a random number between 0 and 1:
*
* &lt;pre&gt;
* {
* "$resolver": "randomNumber"
* }
* &lt;/pre&gt;
*
* Resolve a random number between -0.123 and 0.123:
*
* &lt;pre&gt;
* {
* "$resolver": "randomNumber",
* "range": [-0.123, 0.123]
* }
* &lt;/pre&gt;
*/
public final class RandomNumberResolver implements EventResolver {
private final double loIncLimit;
private final double hiExcLimit;
RandomNumberResolver(final TemplateResolverConfig config) {
final List&lt;Number&gt; rangeArray = config.getList("range", Number.class);
if (rangeArray == null) {
this.loIncLimit = 0D;
this.hiExcLimit = 1D;
} else if (rangeArray.size() != 2) {
throw new IllegalArgumentException(
"range array must be of size two: " + config);
} else {
this.loIncLimit = rangeArray.get(0).doubleValue();
this.hiExcLimit = rangeArray.get(1).doubleValue();
if (loIncLimit &gt; hiExcLimit) {
throw new IllegalArgumentException("invalid range: " + config);
}
}
}
static String getName() {
return "randomNumber";
}
@Override
public void resolve(
final LogEvent value,
final JsonWriter jsonWriter) {
final double randomNumber =
loIncLimit + (hiExcLimit - loIncLimit) * Math.random();
jsonWriter.writeNumber(randomNumber);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Next create a <code>EventResolverFactory</code> class to register <code>RandomNumberResolver</code>
into the Log4j plugin system.</p>
</div>
<div class="listingblock">
<div class="title">Resolver factory class to register <code>RandomNumberResolver</code> into the Log4j plugin system</div>
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">package com.acme.logging.log4j.layout.template.json;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext;
import org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory;
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver;
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverConfig;
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverFactory;
/**
* {@link RandomNumberResolver} factory.
*/
@Plugin(name = "RandomNumberResolverFactory", category = TemplateResolverFactory.CATEGORY)
public final class RandomNumberResolverFactory implements EventResolverFactory {
private static final RandomNumberResolverFactory INSTANCE =
new RandomNumberResolverFactory();
private RandomNumberResolverFactory() {}
@PluginFactory
public static RandomNumberResolverFactory getInstance() {
return INSTANCE;
}
@Override
public String getName() {
return RandomNumberResolver.getName();
}
@Override
public RandomNumberResolver create(
final EventResolverContext context,
final TemplateResolverConfig config) {
return new RandomNumberResolver(config);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Almost complete. Last, we need to inform the Log4j plugin system to discover
these custom classes:</p>
</div>
<div class="listingblock">
<div class="title">Log4j configuration employing custom <code>randomNumber</code> resolver</div>
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Configuration&gt;
&lt;!-- ... --&gt;
&lt;JsonTemplateLayout&gt;
&lt;EventTemplateAdditionalField
key="id"
format="JSON"
value='{"$resolver": "randomNumber", "range": [0, 1000000]}'/&gt;
&lt;/JsonTemplateLayout&gt;
&lt;!-- ... --&gt;
&lt;/Configuration&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>All available event template resolvers are located in
<code>org.apache.logging.log4j.layout.template.json.resolver</code> package. It is a fairly
rich resource for inspiration while implementing new resolvers.</p>
</div>
</div>
<div class="sect2">
<h3 id="extending-template-resolver">Intercepting the Template Resolver Compiler</h3>
<div class="paragraph">
<p><code>JsonTemplateLayout</code> allows interception of the template resolver compilation,
which is the process converting a template into a Java function performing the
JSON serialization. This interception mechanism is internally used to implement
<code>eventTemplateRootObjectKey</code> and <code>eventTemplateAdditionalField</code> features. In a
nutshell, one needs to create a <code>@Plugin</code>-annotated class extending from
<code>EventResolverInterceptor</code> interface.</p>
</div>
<div class="paragraph">
<p>To see the interception in action, check out the <code>EventRootObjectKeyInterceptor</code>
class which is responsible for implementing the <code>eventTemplateRootObjectKey</code>
feature:</p>
</div>
<div class="listingblock">
<div class="title">Event interceptor to add <code>eventTemplateRootObjectKey</code>, if present</div>
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">import org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext;
import org.apache.logging.log4j.layout.template.json.resolver.EventResolverInterceptor;
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverInterceptor;
/**
* Interceptor to add a root object key to the event template.
*/
@Plugin(name = "EventRootObjectKeyInterceptor", category = TemplateResolverInterceptor.CATEGORY)
public class EventRootObjectKeyInterceptor implements EventResolverInterceptor {
private static final EventRootObjectKeyInterceptor INSTANCE =
new EventRootObjectKeyInterceptor();
private EventRootObjectKeyInterceptor() {}
@PluginFactory
public static EventRootObjectKeyInterceptor getInstance() {
return INSTANCE;
}
@Override
public Object processTemplateBeforeResolverInjection(
final EventResolverContext context,
final Object node) {
String eventTemplateRootObjectKey = context.getEventTemplateRootObjectKey();
return eventTemplateRootObjectKey != null
? Collections.singletonMap(eventTemplateRootObjectKey, node)
: node;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Here, <code>processTemplateBeforeResolverInjection()</code> method checks if the user has
provided an <code>eventTemplateRootObjectKey</code>. If so, it wraps the root <code>node</code> with a
new object; otherwise, returns the <code>node</code> as is. Note that <code>node</code> refers to the
root Java object of the event template read by <code>JsonReader</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="extending-recycler">Extending Recycler Factories</h3>
<div class="paragraph">
<p><code>recyclerFactory</code> input <code>String</code> read from the layout configuration is converted
to a <code>RecyclerFactory</code> using the default <code>RecyclerFactoryConverter</code> extending
from <code>TypeConverter&lt;RecyclerFactory&gt;</code>. If one wants to change this behavior,
they simply need to add their own <code>TypeConverter&lt;RecyclerFactory&gt;</code> implementing
<code>Comparable&lt;TypeConverter&lt;?&gt;&gt;</code> to prioritize their custom converter.</p>
</div>
<div class="listingblock">
<div class="title">Custom <code>TypeConverter</code> for <code>RecyclerFactory</code></div>
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">package com.acme.logging.log4j.layout.template.json;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.convert.TypeConverter;
import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
@Plugin(name = "AcmeRecyclerFactoryConverter", category = TypeConverters.CATEGORY)
public final class AcmeRecyclerFactoryConverter
implements TypeConverter&lt;RecyclerFactory&gt;, Comparable&lt;TypeConverter&lt;?&gt;&gt; {
@Override
public RecyclerFactory convert(final String recyclerFactorySpec) {
return AcmeRecyclerFactory.ofSpec(recyclerFactorySpec);
}
@Override
public int compareTo(final TypeConverter&lt;?&gt; ignored) {
return -1;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Here note that <code>compareTo()</code> always returns -1 to rank it higher compared to
other matching converters.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="features">Features</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Below is a feature comparison matrix between <code>JsonTemplateLayout</code> and
alternatives.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 3. Feature comparison matrix</caption>
<colgroup>
<col style="width: 42.8571%;"/>
<col style="width: 14.2857%;"/>
<col style="width: 14.2857%;"/>
<col style="width: 14.2857%;"/>
<col style="width: 14.2858%;"/>
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Feature</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>JsonTemplateLayout</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="layouts.html#JSONLayout"><code>JsonLayout</code></a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="layouts.html#GELFLayout"><code>GelfLayout</code></a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/elastic/java-ecs-logging/tree/master/log4j2-ecs-layout"><code>EcsLayout</code></a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Java version</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Dependencies</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">None</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Jackson</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">None</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">None</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Schema customization?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Timestamp customization?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">(Almost) garbage-free?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Custom typed <code>Message</code> serialization?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">?<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnotedef_1" title="View footnote.">1</a>]</sup></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Custom typed <code>MDC</code> value serialization?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Rendering stack traces as array?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Stack trace truncation?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">JSON pretty print?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Additional string fields?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Additional JSON fields?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Custom resolvers?</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"></p></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect1">
<h2 id="faq">F.A.Q.</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="faq-lookups">Are lookups supported in templates?</h3>
<div class="paragraph">
<p>Yes, <a href="lookups.html">lookups</a> (e.g., <code>${java:version}</code>,
<code>${env:USER}</code>, <code>${date:MM-dd-yyyy}</code>) are supported in string
literals of templates. Though note that they are not garbage-free.</p>
</div>
</div>
<div class="sect2">
<h3 id="are_recursive_collections_supported">Are recursive collections supported?</h3>
<div class="paragraph">
<p>No. Consider a <code>Message</code> containing a recursive value as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">Object[] recursiveCollection = new Object[1];
recursiveCollection[0] = recursiveCollection;</code></pre>
</div>
</div>
<div class="paragraph">
<p>While the exact exception might vary, you will most like get a
<code>StackOverflowError</code> for trying to render <code>recursiveCollection</code> into a
<code>String</code>. Note that this is also the default behaviour for other Java standard
library methods, e.g., <code>Arrays.toString()</code>. Hence mind self references while
logging.</p>
</div>
</div>
<div class="sect2">
<h3 id="faq-garbage-free">Is <code>JsonTemplateLayout</code> garbage-free?</h3>
<div class="paragraph">
<p>Yes, if the garbage-free layout behaviour toggling properties
<code>log4j2.enableDirectEncoders</code> and <code>log4j2.garbagefreeThreadContextMap</code> are
enabled. Take into account the following caveats:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The configured <a href="#recycling-strategy">recycling strategy</a> might not be
garbage-free.</p>
</li>
<li>
<p>Since <code>Throwable#getStackTrace()</code> clones the original <code>StackTraceElement[]</code>,
access to (and hence rendering of) stack traces are not garbage-free.</p>
</li>
<li>
<p>Serialization of <code>MapMessage</code>s and <code>ObjectMessage</code>s are mostly
garbage-free except for certain types (e.g., <code>BigDecimal</code>, <code>BigInteger</code>,
<code>Collection</code>s, except <code>List</code>).</p>
</li>
<li>
<p><a href="lookups.html">Lookups</a> (that is, <code>${&#8230;&#8203;}</code> variables) are not garbage-free.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Don&#8217;t forget to check out <a href="#event-template-resolvers">the notes on garbage footprint of resolvers</a>
you employ in templates.</p>
</div>
</div>
</div>
</div>
<div id="footnotes">
<hr/>
<div class="footnote" id="_footnotedef_1">
<a href="#_footnoteref_1">1</a>. Only for <code>ObjectMessage</code>s and if Jackson is in the classpath.
</div>
</div>
</main>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p align="center">Copyright &copy; 1999-2024 <a class="external" href="https://www.apache.org">The Apache Software Foundation</a>. All Rights Reserved.<br>
Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the Apache Logging project logo are trademarks of The Apache Software Foundation.</p>
</div>
</div>
</footer>
<script>
if(anchors) {
anchors.add();
}
</script>
</body>
</html>