{"id":15337293,"url":"https://github.com/vy/log4j2-logstash-layout","last_synced_at":"2025-08-20T10:31:32.688Z","repository":{"id":21002139,"uuid":"91546562","full_name":"vy/log4j2-logstash-layout","owner":"vy","description":"Log4j 2.x plugin for customizable and Logstash-friendly JSON layout.","archived":false,"fork":false,"pushed_at":"2022-04-20T07:15:27.000Z","size":691,"stargazers_count":89,"open_issues_count":7,"forks_count":26,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-11-26T01:34:09.552Z","etag":null,"topics":["java","json","log4j","log4j2","logging","logstash"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"COPYING.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"vy"}},"created_at":"2017-05-17T07:28:37.000Z","updated_at":"2024-06-04T19:42:22.000Z","dependencies_parsed_at":"2022-08-07T09:16:29.605Z","dependency_job_id":null,"html_url":"https://github.com/vy/log4j2-logstash-layout","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Flog4j2-logstash-layout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Flog4j2-logstash-layout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Flog4j2-logstash-layout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Flog4j2-logstash-layout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vy","download_url":"https://codeload.github.com/vy/log4j2-logstash-layout/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230415317,"owners_count":18222158,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","json","log4j","log4j2","logging","logstash"],"created_at":"2024-10-01T10:20:29.640Z","updated_at":"2024-12-19T10:08:57.005Z","avatar_url":"https://github.com/vy.png","language":"Java","funding_links":["https://github.com/sponsors/vy"],"categories":[],"sub_categories":[],"readme":"**`log4j2-logstash-layout` is not maintained anymore! Since Log4j 2.14.0, it is\nsuperseded by `log4j-layout-template-json` shipping\n[`JsonTemplateLayout`](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html),\nwhich is a successor of `LogstashLayout`. We strongly advise all `LogstashLayout`\nusers to migrate to `JsonTemplateLayout`. We will do our best to bring bug fixes\nto `LogstashLayout`, but all the new development efforts will be focused on\n`JsonTemplateLayout`.**\n\n[![Actions Status](https://github.com/vy/log4j2-logstash-layout/workflows/CI/badge.svg)](https://github.com/vy/log4j2-logstash-layout/actions)\n[![Maven Central](https://img.shields.io/maven-central/v/com.vlkan.log4j2/log4j2-logstash-layout-parent.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.vlkan.log4j2%22)\n[![License](https://img.shields.io/github/license/vy/log4j2-logstash-layout.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt)\n\n`LogstashLayout` is **the fastest** [Log4j 2](https://logging.apache.org/log4j/2.x/)\nJSON layout allowing schema customization and [Logstash](https://www.elastic.co/products/logstash)-friendly\noutput.\n\nBy default, `LogstashLayout` ships the official `JSONEventLayoutV1` stated by\n[log4j-jsonevent-layout](https://github.com/logstash/log4j-jsonevent-layout)\nLog4j 1.x plugin. Compared to\n[JSONLayout](https://logging.apache.org/log4j/2.x/manual/layouts.html#JSONLayout)\nincluded in Log4j 2 and `log4j-jsonevent-layout`, `LogstashLayout` provides\nthe following additional features:\n\n- Superior [performance](#performance)\n- Customizable JSON schema (see `eventTemplate[Uri]` and `stackTraceElementTemplate[Uri]` parameters)\n- Customizable timestamp formatting (see `dateTimeFormatPattern` and `timeZoneId` parameters)\n\n# Table of Contents\n\n- [Usage](#usage)\n- [Predefined Templates](#templates)\n- [Features](#features)\n- [Appender Support](#appender-support)\n- [Performance](#performance)\n- [F.A.Q.](#faq)\n- [Contributors](#contributors)\n- [License](#license)\n\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n\n# Usage\n\nAdd the `log4j2-logstash-layout` dependency to your POM file\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.vlkan.log4j2\u003c/groupId\u003e\n    \u003cartifactId\u003elog4j2-logstash-layout\u003c/artifactId\u003e\n    \u003cversion\u003e${log4j2-logstash-layout.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nin combination with a valid `log4j-core` dependency:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.apache.logging.log4j\u003c/groupId\u003e\n    \u003cartifactId\u003elog4j-core\u003c/artifactId\u003e\n    \u003cversion\u003e${log4j2.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n(Note that the Java 9 module name is `com.vlkan.log4j2.logstash.layout`.)\n\nBelow you can find a sample `log4j2.xml` snippet employing `LogstashLayout`.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cConfiguration status=\"warn\"\u003e\n    \u003cAppenders\u003e\n        \u003cConsole name=\"CONSOLE\" target=\"SYSTEM_OUT\"\u003e\n            \u003cLogstashLayout dateTimeFormatPattern=\"yyyy-MM-dd'T'HH:mm:ss.SSSZZZ\"\n                            eventTemplateUri=\"classpath:LogstashJsonEventLayoutV1.json\"\n                            prettyPrintEnabled=\"true\"\n                            stackTraceEnabled=\"true\"/\u003e\n        \u003c/Console\u003e\n    \u003c/Appenders\u003e\n    \u003cLoggers\u003e\n        \u003cRoot level=\"info\"\u003e\n            \u003cAppenderRef ref=\"CONSOLE\"/\u003e\n        \u003c/Root\u003e\n    \u003c/Loggers\u003e\n\u003c/Configuration\u003e\n```\n\nOr using the `log4j2.properties` file instead:\n\n```ini\nstatus = warn\n\nappender.console.name = CONSOLE\nappender.console.type = CONSOLE\nappender.console.target = SYSTEM_OUT\n\nappender.console.logstash.type = LogstashLayout\nappender.console.logstash.dateTimeFormatPattern = yyyy-MM-dd'T'HH:mm:ss.SSSZZZ\nappender.console.logstash.eventTemplateUri = classpath:LogstashJsonEventLayoutV1.json\nappender.console.logstash.prettyPrintEnabled = true\nappender.console.logstash.stackTraceEnabled = true\n\nrootLogger.level = info\nrootLogger.appenderRef.stdout.ref = CONSOLE\n```\n\nThis generates an output as follows:\n\n```json\n{\n  \"exception\": {\n    \"exception_class\": \"java.lang.RuntimeException\",\n    \"exception_message\": \"test\",\n    \"stacktrace\": \"java.lang.RuntimeException: test\\n\\tat com.vlkan.log4j2.logstash.layout.demo.LogstashLayoutDemo.main(LogstashLayoutDemo.java:11)\\n\"\n  },\n  \"line_number\": 12,\n  \"class\": \"com.vlkan.log4j2.logstash.layout.demo.LogstashLayoutDemo\",\n  \"@version\": 1,\n  \"source_host\": \"varlik\",\n  \"message\": \"Hello, error!\",\n  \"thread_name\": \"main\",\n  \"@timestamp\": \"2017-05-25T19:56:23.370+02:00\",\n  \"level\": \"ERROR\",\n  \"file\": \"LogstashLayoutDemo.java\",\n  \"method\": \"main\",\n  \"logger_name\": \"com.vlkan.log4j2.logstash.layout.demo.LogstashLayoutDemo\"\n}\n```\n\n`LogstashLayout` is configured with the following parameters:\n\n| Parameter Name | Type | Description |\n|----------------|------|-------------|\n| `prettyPrintEnabled` | boolean | enables pretty-printer (defaults to `false`) |\n| `locationInfoEnabled` | boolean | includes the filename and line number in the output (defaults to `false`) |\n| `stackTraceEnabled` | boolean | includes stack traces (defaults to `false`) |\n| `emptyPropertyExclusionEnabled` | boolean | exclude empty and null properties (defaults to `false`) |\n| `dateTimeFormatPattern` | String | timestamp formatter pattern (defaults to `yyyy-MM-dd'T'HH:mm:ss.SSSZZZ`) |\n| `timeZoneId` | String | time zone id (defaults to `TimeZone.getDefault().getID()`) |\n| `locale` | String | locale in one of the following forms: `\u003clanguage\u003e`, `\u003clanguage\u003e_\u003ccountry\u003e`, or `\u003clanguage\u003e_\u003ccountry\u003e_\u003cvariant\u003e` (defaults to `Locale.getDefault()`) |\n| `mdcKeyPattern` | String | regex to filter MDC keys (does not apply to direct `mdc:key` access) |\n| `ndcPattern` | String | regex to filter NDC items |\n| `eventTemplate` | String | inline JSON template for rendering `LogEvent`s (has priority over `eventTemplateUri`) |\n| `eventTemplateUri` | String | JSON template for rendering `LogEvent`s (defaults to [`classpath:LogstashJsonEventLayoutV1.json`](layout/src/main/resources/LogstashJsonEventLayoutV1.json)) |\n| `eventTemplateAdditionalFields`\u003csup\u003e1\u003c/sup\u003e | KeyValuePair | additional key-value pairs appended to the root of the event template |\n| `stackTraceElementTemplate` | String | inline JSON template for rendering `StackTraceElement`s (has priority over `stackTraceElementTemplateUri`) |\n| `stackTraceElementTemplateUri` | String | JSON template for rendering `StackTraceElement`s (defaults to [`classpath:Log4j2StackTraceElementLayout.json`](layout/src/main/resources/Log4j2StackTraceElementLayout.json)) |\n| `lineSeparator` | String | used to separate log outputs (defaults to `System.lineSeparator()`) |\n| `maxByteCount` | int | used to cap the internal `byte[]` buffer used for serialization (defaults to 16 KiB) |\n| `maxStringLength`\u003csup\u003e2\u003c/sup\u003e | int | truncate string values longer than the specified limit (defaults to 0) |\n| `objectMapperFactoryMethod` | String | custom object mapper factory method (defaults to `com.fasterxml.jackson.databind.ObjectMapper.new`) |\n| `mapMessageFormatterIgnored` | boolean | as a temporary work around for [LOG4J2-2703](https://issues.apache.org/jira/browse/LOG4J2-2703), serialize `MapMessage`s using Jackson rather than `MapMessage#getFormattedMessage()` (defaults to `true`) |\n\n\u003csup\u003e1\u003c/sup\u003e One can configure additional event template fields as follows:\n\n```xml\n\u003cLogstashLayout ...\u003e\n    \u003cEventTemplateAdditionalFields\u003e\n        \u003cKeyValuePair key=\"serviceName\" value=\"auth-service\"/\u003e\n        \u003cKeyValuePair key=\"containerId\" value=\"6ede3f0ca7d9\"/\u003e\n    \u003c/EventTemplateAdditionalFields\u003e\n\u003c/LogstashLayout\u003e\n```\n\n\u003csup\u003e2\u003c/sup\u003e Note that string value truncation via `maxStringLength` can take\nplace both in object keys and values, and this operation does not leave any\ntrace behind. `maxStringLength` is intended as a soft protection against bogus\ninput and one should always rely on `maxByteCount` for a hard limit.\n\n`eventTemplateUri` denotes the URI pointing to the JSON template that will be used\nwhile formatting the `LogEvent`s. By default, `LogstashLayout` ships\n[`LogstashJsonEventLayoutV1.json`](layout/src/main/resources/LogstashJsonEventLayoutV1.json)\nproviding [the official Logstash `JSONEventLayoutV1`](https://github.com/logstash/log4j-jsonevent-layout).\n\n```json\n{\n  \"mdc\": \"${json:mdc}\",\n  \"ndc\": \"${json:ndc}\",\n  \"exception\": {\n    \"exception_class\": \"${json:exception:className}\",\n    \"exception_message\": \"${json:exception:message}\",\n    \"stacktrace\": \"${json:exception:stackTrace:text}\"\n  },\n  \"line_number\": \"${json:source:lineNumber}\",\n  \"class\": \"${json:source:className}\",\n  \"@version\": 1,\n  \"source_host\": \"${hostName}\",\n  \"message\": \"${json:message}\",\n  \"thread_name\": \"${json:thread:name}\",\n  \"@timestamp\": \"${json:timestamp}\",\n  \"level\": \"${json:level}\",\n  \"file\": \"${json:source:fileName}\",\n  \"method\": \"${json:source:methodName}\",\n  \"logger_name\": \"${json:logger:name}\"\n}\n```\n\nSimilarly, `stackTraceElementUri` denotes the URI pointing to the JSON template\nthat will be used while formatting the `StackTraceElement`s. By default,\n`LogstashLayout` ships [`classpath:Log4j2StackTraceElementLayout.json`](layout/src/main/resources/Log4j2StackTraceElementLayout.json)\nproviding an identical stack trace structure produced by Log4j 2 `JSONLayout`.\n\n```json\n{\n  \"class\": \"${json:stackTraceElement:className}\",\n  \"method\": \"${json:stackTraceElement:methodName}\",\n  \"file\": \"${json:stackTraceElement:fileName}\",\n  \"line\": \"${json:stackTraceElement:lineNumber}\"\n}\n```\n\nIn case of need, you can create your own templates with a structure tailored\nto your needs. That is, you can add new fields, remove or rename existing\nones, change the structure, etc. Please note that `eventTemplateUri` parameter\nonly supports `file` and `classpath` URI schemes. \n\nBelow is the list of allowed `LogEvent` template variables that will be replaced\nwhile rendering the JSON output.\n\n| Variable Name | Description |\n|---------------|-------------|\n| `endOfBatch` | `logEvent.isEndOfBatch()` |\n| `exception:className` | `logEvent.getThrown().getClass().getCanonicalName()` |\n| `exception:message` | `logEvent.getThrown().getMessage()` |\n| `exception:stackTrace` | `logEvent.getThrown().getStackTrace()` (inactive when `stackTraceEnabled=false`) |\n| `exception:stackTrace:text` | `logEvent.getThrown().printStackTrace()` (inactive when `stackTraceEnabled=false`) |\n| `exceptionRootCause:className` | the innermost `exception:className` in causal chain |\n| `exceptionRootCause:message` | the innermost `exception:message` in causal chain |\n| `exceptionRootCause:stackTrace[:text]` | the innermost `exception:stackTrace[:text]` in causal chain |\n| `level` | `logEvent.getLevel()` |\n| `level:severity` | [Syslog severity](https://en.wikipedia.org/wiki/Syslog#Severity_levels) keyword of `logEvent.getLevel()` |\n| `level:severity:code` | [Syslog severity](https://en.wikipedia.org/wiki/Syslog#Severity_levels) code of `logEvent.getLevel()` |\n| `logger:fqcn` | `logEvent.getLoggerFqcn()` |\n| `logger:name` | `logEvent.getLoggerName()` |\n| `main:\u003ckey\u003e` | performs [Main Argument Lookup](https://logging.apache.org/log4j/2.0/manual/lookups.html#AppMainArgsLookup) for the given `key` |\n| `map:\u003ckey\u003e` | performs [Map Lookup](https://logging.apache.org/log4j/2.0/manual/lookups.html#MapLookup) for the given `key` |\n| `marker:name` | `logEvent.getMarker.getName()` |\n| `mdc` | Mapped Diagnostic Context `Map\u003cString, String\u003e` returned by `logEvent.getContextData()` |\n| `mdc:\u003ckey\u003e` | Mapped Diagnostic Context `String` associated with `key` (`mdcKeyPattern` is discarded) |\n| `message` | `logEvent.getFormattedMessage()` |\n| `message:json` | if `logEvent.getMessage()` is of type `MultiformatMessage` and supports JSON, its read value, otherwise, `{\"message\": \u003cformattedMessage\u003e}` object |\n| `ndc` | Nested Diagnostic Context `String[]` returned by `logEvent.getContextStack()` |\n| `source:className` | `logEvent.getSource().getClassName()` |\n| `source:fileName` | `logEvent.getSource().getFileName()` (inactive when `locationInfoEnabled=false`) |\n| `source:lineNumber` | `logEvent.getSource().getLineNumber()` (inactive when `locationInfoEnabled=false`) |\n| `source:methodName` | `logEvent.getSource().getMethodName()` |\n| `thread:id` | `logEvent.getThreadId()` |\n| `thread:name` | `logEvent.getThreadName()` |\n| `thread:priority` | `logEvent.getThreadPriority()` |\n| `timestamp` | `logEvent.getTimeMillis()` formatted using `dateTimeFormatPattern` and `timeZoneId` |\n| `timestamp:epoch` | epoch nanoseconds derived from `logEvent.getInstant()` |\n| `timestamp:epoch:divisor=\u003cdivisor\u003e` | epoch nanoseconds derived from `logEvent.getInstant()` divided by provided `divisor` (of type `double`) |\n| `timestamp:epoch:divisor=\u003cdivisor\u003e,integral` | epoch nanoseconds derived from `logEvent.getInstant()` divided by provided `divisor` (of type `double`) and casted to `long` |\n\nJSON field lookups are performed using the `${json:\u003cvariable-name\u003e}` scheme\nwhere `\u003cvariable-name\u003e` is defined as `\u003cresolver-name\u003e[:\u003cresolver-key\u003e]`.\nCharacters following colon (`:`) are treated as the `resolver-key`.\n\n[Log4j 2 Lookups](https://logging.apache.org/log4j/2.0/manual/lookups.html)\n(e.g., `${java:version}`, `${env:USER}`, `${date:MM-dd-yyyy}`) are supported\nin templates too. Though note that while `${json:...}` template variables are\nexpected to occupy an entire field, that is, `\"level\": \"${json:level}\"`, a\nlookup can be mixed within a regular text: `\"myCustomField\": \"Hello, ${env:USER}!\"`.\n\nSimilarly, below is the list of allowed `StackTraceElement` template variables:\n\n| Variable Name | Description |\n|---------------|-------------|\n| `stackTraceElement:className` | `stackTraceElement.getClassName()` |\n| `stackTraceElement:methodName` | `stackTraceElement.getMethodName()` |\n| `stackTraceElement:fileName` | `stackTraceElement.getFileName()` |\n| `stackTraceElement:lineNumber` | `stackTraceElement.getLineNumber()` |\n\nAs in `LogEvent` templates, `StackTraceElement` templates support Log4j 2\nlookups too.\n\nSee [`layout-demo`](layout-demo) directory for a sample application\ndemonstrating the usage of `LogstashLayout`.\n\n\u003ca name=\"templates\"\u003e\u003c/a\u003e\n\n# Predefined Templates\n\n`log4j2-logstash-layout` artifact contains the following predefined templates:\n\n- [`EcsLayout.json`](layout/src/main/resources/EcsLayout.json) described by\n  [the Elastic Common Schema (ECS) specification](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html)\n\n- [`LogstashJsonEventLayoutV1.json`](layout/src/main/resources/LogstashJsonEventLayoutV1.json)\n  described in [log4j-jsonevent-layout](https://github.com/logstash/log4j-jsonevent-layout)\n\n- [`GelfLayout.json`](layout/src/main/resources/GelfLayout.json) described by\n  [the Graylog Extended Log Format (GELF) payload specification](https://docs.graylog.org/en/3.1/pages/gelf.html#gelf-payload-specification)\n  with additional `_thread` and `_logger`fields similar to\n  [`GelfLayout` of Log4j 2](https://logging.apache.org/log4j/2.0/manual/layouts.html#GELFLayout)\n  (Here it is advised to override the obligatory `host` field with a user\n  provided constant via `eventTemplateAdditionalFields` to avoid `hostName`\n  property lookup at runtime, which incurs an extra cost.)\n\n\u003ca name=\"features\"\u003e\u003c/a\u003e\n\n# Features\n\nBelow is a feature comparison matrix between `LogstashLayout` and alternatives.\n\n| Feature | `LogstashLayout` | `JsonLayout` | `EcsLayout` |\n|---------|------------------|--------------|-------------|\n| Java version | 8 | 7\u003csup\u003e3\u003c/sup\u003e | 6 |\n| Dependencies | Jackson | Jackson | None |\n| Full schema customization? | ✓ | ✕ | ✕ |\n| Timestamp customization? | ✓ | ✕ | ✕ |\n| (Almost) garbage-free? | ✓ | ✕ | ✓ |\n| Custom typed `Message` serialization? | ✓ | ✕ | ✓\u003csup\u003e4\u003c/sup\u003e |\n| Custom typed `MDC` value serialization? | ✓ | ✕ | ✕ |\n| Rendering stack traces as array? | ✓ | ✓ | ✓ |\n| Enabling/Disabling JSON pretty print? | ✓ | ✓ | ✕ |\n| Additional fields? | ✓ | ✓ | ✓ |\n\n\u003csup\u003e3\u003c/sup\u003e Log4j 2.4 and greater requires Java 7, versions 2.0-alpha1 to 2.3\nrequired Java 6.\n\n\u003csup\u003e4\u003c/sup\u003e Only for `ObjectMessage`s and if Jackson is in the classpath.\n\n\u003ca name=\"fat-jar\"\u003e\u003c/a\u003e\n\n# Fat JAR\n\nProject also contains a `log4j2-logstash-layout-fatjar` artifact which\nincludes all its transitive dependencies in a separate shaded package (to\navoid the JAR Hell) with the exception of `log4j-core`, that you need to\ninclude separately.\n\nThis might come handy if you want to use this plugin along with already\ncompiled applications, e.g., Elasticsearch 5.x and 6.x versions, which\nrequires Log4j 2.\n\n\u003ca name=\"appender-support\"\u003e\u003c/a\u003e\n\n# Appender Support\n\n`log4j2-logstash-layout` is all about providing a highly customizable JSON\nschema for your logs. Though this does not necessarily mean that all of its\nfeatures are expected to be supported by every appender in the market. For\ninstance, while `prettyPrintEnabled=true` works fine with\n[log4j2-redis-appender](/vy/log4j2-redis-appender), it should be turned off\nfor Logstash's `log4j-json` file input type. (See\n[Pretty printing in Logstash](/vy/log4j2-logstash-layout/issues/8) issue.)\nMake sure you configure `log4j2-logstash-layout` properly in a way that\nis aligned with your appender of preference.\n\n\u003ca name=\"performance\"\u003e\u003c/a\u003e\n\n# Performance\n\nThe source code contains a benchmark comparing `LogstashLayout` performance with\n[`JsonLayout`](https://logging.apache.org/log4j/2.0/manual/layouts.html#JSONLayout)\n(shipped by default in Log4j 2) and\n[`EcsLayout`](https://github.com/elastic/java-ecs-logging/tree/master/log4j2-ecs-layout)\n(shipped by Elastic). There [JMH](https://openjdk.java.net/projects/code-tools/jmh/)\nis used to assess the rendering performance of these layouts. In the tests,\ndifferent `LogEvent` profiles are employed:\n\n- **full**: `LogEvent` contains MDC, NDC, and an exception.\n- **lite:** `LogEvent` has no MDC, NDC, or exception attachment.\n\nTo give an idea, we ran the benchmark with the following settings:\n\n- **CPU:** Intel i7 2.70GHz (x86-64, confined `java` process to a single core\n  using [`taskset -c 0`](http://www.man7.org/linux/man-pages/man1/taskset.1.html))\n- **JVM:** OpenJDK 64-Bit, AdoptOpenJDK, build 25.232-b09\n  - `-XX:+TieredCompilation`\n  - `-Dlog4j2.garbagefreeThreadContextMap=true`\n  - `-Dlog4j2.enableDirectEncoders=true`\n  - `-Dlog4j2.enable.threadlocals=true`\n  - `-Dlog4j2.is.webapp=false`\n- **OS:** Xubuntu 18.04.3 (4.15.0-70-generic, x86-64)\n- **`LogstashLayout4{Ecs,Json,Gelf}Layout`** used default settings with the\n  following exceptions:\n  - **`stackTraceEnabled`:** `true`\n  - **`maxByteCount`:** (4096) 4KiB\n- **`JsonLayout`** used in two different flavors:\n  - **`DefaultJsonLayout`:** default settings\n  - **`CustomJsonLayout`:** default settings with an additional `\"@version\": 1`\n    field (this forces instantiation of a wrapper class to obtain the necessary\n    Jackson view)\n- **`EcsLayout`** used with the following configurations:\n  - **`serviceName`:** `benchmark`\n  - **`additionalFields`:** `new KeyValuePair[0]`\n- **`GelfLayout`** used with the following configurations:\n  - **`compressionType`:** `off`\n\nThe figures for serializing 1,000 `LogEvent`s at each operation are as follows.\n(See [`layout-benchmark`](layout-benchmark) directory for the full report.)\n\n\u003cdiv id=\"results\"\u003e\n    \u003ctable\u003e\n        \u003cthead\u003e\n            \u003ctr\u003e\n                \u003cth\u003eBenchmark\u003c/th\u003e\n                \u003cth colspan=\"2\"\u003eops/sec\u003csup\u003e5\u003c/sup\u003e\u003c/th\u003e\n                \u003cth\u003eB/op\u003csup\u003e5\u003c/sup\u003e\u003c/th\u003e\n            \u003c/tr\u003e\n        \u003c/thead\u003e\n        \u003ctbody\u003e\n            \u003ctr data-benchmark=\"liteLogstashLayout4GelfLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003eliteLogstashLayout4GelfLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e1,517,062\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ (100%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e0.0\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"liteLogstashLayout4EcsLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003eliteLogstashLayout4EcsLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e1,196,255\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ (79%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e0.0\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"liteGelfLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003eliteGelfLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e1,184,922\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ (78%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e0.0\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"liteLogstashLayout4JsonLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003eliteLogstashLayout4JsonLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e870,012\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉▉▉▉▉▉▉▉▉▉ (57%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e0.0\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"liteEcsLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003eliteEcsLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e836,648\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉▉▉▉▉▉▉▉▉▉ (55%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e0.0\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"liteDefaultJsonLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003eliteDefaultJsonLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e506,985\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉▉▉▉▉▉ (33%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e5,331,680.0\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"liteCustomJsonLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003eliteCustomJsonLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e446,243\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉▉▉▉▉ (29%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e5,740,400.0\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"fullLogstashLayout4JsonLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003efullLogstashLayout4JsonLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e118,294\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉▉ (8%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e104,000.1\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"fullLogstashLayout4GelfLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003efullLogstashLayout4GelfLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e73,102\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉ (5%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e35,663,200.3\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"fullLogstashLayout4EcsLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003efullLogstashLayout4EcsLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e60,569\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉ (4%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e35,631,200.4\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"fullEcsLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003efullEcsLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e27,887\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉ (2%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e46,479,200.5\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"fullGelfLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003efullGelfLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e21,458\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉ (1%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e58,911,200.7\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"fullDefaultJsonLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003efullDefaultJsonLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e13,513\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉ (1%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e234,102,401.5\u003c/td\u003e\n            \u003c/tr\u003e\n            \u003ctr data-benchmark=\"fullCustomJsonLayout\"\u003e\n                \u003ctd class=\"benchmark\"\u003efullCustomJsonLayout\u003c/td\u003e\n                \u003ctd class=\"op_rate\"\u003e13,511\u003c/td\u003e\n                \u003ctd class=\"op_rate_bar\"\u003e▉ (1%)\u003c/td\u003e\n                \u003ctd class=\"gc_rate\"\u003e234,238,401.5\u003c/td\u003e\n            \u003c/tr\u003e\n        \u003c/tbody\u003e\n    \u003c/table\u003e\n    \u003cp id=\"footnotes\"\u003e\n        \u003csup\u003e5\u003c/sup\u003e 99\u003csup\u003eth\u003c/sup\u003e percentile\n    \u003c/p\u003e\n\u003c/div\u003e\n\nLet us try to answer some common questions:\n\n- **How come `log4j2-logstash-layout` can yield superior performance compared\n  to Log4j 2 `JsonLayout`?** Log4j 2 `JsonLayout` employs a single Jackson view\n  to generate JSON, XML, and YAML outputs. For this purpose, it uses Jackson\n  `ObjectMapper`, which needs to walk over the class fields via reflection and\n  perform heavy branching and intermediate object instantiation. On the\n  contrary, `log4j2-logstash-layout` parses the given template once and\n  compiles a (mostly) garbage- and (to a certain extent) branching-free\n  JSON generator employing Jackson `JsonGenerator`.\n\n- **Why is `log4j2-logstash-layout` is not totally garbage-free?**\n\n  - Since `Throwable#getStackTrace()` clones the original\n    `StackTraceElement[]`, accesses to (and hence rendering) stack traces can\n    never be garbage-free.\n\n  - Rendering of context data (that is, MDC) field values is garbage-free if\n    the value is either `null`, or of type `String`, `Short`, `Integer`,\n    `Long`, or `byte[]`.\n\n- **How can one run the benchmark on his/her machine?** After a fresh\n  `mvn clean verify` within the source directory, run\n  `layout-benchmark/benchmark.py`.\n\n- **What about thread-local allocations?** Even though Log4j 2 exposes a\n  `log4j2.enable.threadlocals` flag to toggle TLAs, neither `EcsLayout`, nor\n  Log4j 2 `JsonLayout` and `GelfLayout` honor it. Historically, `LogstashLayout`\n  used to have TLAs taking the `log4j2.enable.threadlocals` flag into account.\n  In version 0.18, we switched to simple memory-efficient object pools, though\n  that incurred extra synchronization costs. Since version 0.22,\n  `LogstashLayout` switched back to TLAs taking `log4j2.enable.threadlocals`\n  into account.\n\n\u003ca name=\"faq\"\u003e\u003c/a\u003e\n\n# F.A.Q.\n\n- **How can one enable thread-local allocations?** For performance reasons,\n  it is highly recommended to turn TLAs on. For this purpose, you need to make\n  sure `log4j2.enable.threadlocals=true` and `log4j2.is.webapp=false`.\n\n- **Is there a fat JAR of the plugin?** Project also contains a\n  `log4j2-logstash-layout-fatjar` artifact which includes all its transitive\n  dependencies in a separate shaded package (to avoid the JAR Hell) with the\n  exception of `log4j-core`, that you need to include separately. Fat JAR might\n  come handy if you want to use this plugin along with certain applications,\n  e.g., Elasticsearch 5.x and 6.x versions, which requires Log4j 2.\n\n- **Why do I get irrelevant stack traces from\n  `exception[RootCause]:stackTrace[:text]` directives?** `LogstashLayout`\n  uses `Throwable#printStackTrace(PrintWriter)` and `Throwable#getStackTrace()`\n  methods to resolve these directives. Under certain circumstances, these\n  methods may throw exception as well. Put another way, trying to access the\n  stack trace of an exception might cause another exception. In such a case,\n  `LogstashLayout` continues the directive resolution using the new exception\n  and keeps on repeating until it manages to resolve a stack trace to at least\n  provide some insight into the underlying cause.\n\n\u003ca name=\"contributors\"\u003e\u003c/a\u003e\n\n# Contributors\n\n- [bakomchik](https://github.com/bakomchik)\n- [chrissydee](https://github.com/chrissydee)\n- [Daniel Lundsgaard Skovenborg](https://github.com/waldeinburg)\n- [Eric Schwartz](https://github.com/emschwar)\n- [Felix Barnsteiner](https://github.com/felixbarny)\n- [Johann Schmitz](https://github.com/ercpe)\n- [John Ament](https://github.com/johnament)\n- [Jonathan Guéhenneux](https://github.com/Achaaab)\n- [justinsaliba](https://github.com/justinsaliba)\n- [Maurice Zeijen](https://github.com/mzeijen)\n- [Michael K. Edwards](https://github.com/mkedwards)\n- [Mikael Strand](https://github.com/MikaelStrand)\n- [Rafa Gómez](https://github.com/rgomezcasas)\n- [Yaroslav Skopets](https://github.com/yskopets)\n\n\u003ca name=\"license\"\u003e\u003c/a\u003e\n\n# License\n\nCopyright \u0026copy; 2017-2020 [Volkan Yazıcı](https://vlkan.com/)\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvy%2Flog4j2-logstash-layout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvy%2Flog4j2-logstash-layout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvy%2Flog4j2-logstash-layout/lists"}