Update documentation based on changes to JsonTemplateLayout
diff --git a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/ContainerUtil.java b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/ContainerUtil.java
index e414045..7944e86 100644
--- a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/ContainerUtil.java
+++ b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/ContainerUtil.java
@@ -41,8 +41,9 @@
* been much nicer if Kubernetes would just put the container id in a standard environment variable.
*
* @see <a href="http://stackoverflow.com/a/25729598/12916">Stackoverflow</a> for a discussion on retrieving the containerId.
- * @see <a href="https://github.com/jenkinsci/docker-workflow-plugin/blob/master/src/main/java/org/jenkinsci/plugins/docker/workflow/client/ControlGroup.java>ControlGroup</a>
+ * @see <a href="https://github.com/jenkinsci/docker-workflow-plugin/blob/master/src/main/java/org/jenkinsci/plugins/docker/workflow/client/ControlGroup.java">ControlGroup</a>
* for the original version of this. Not much is actually left but it provided good inspiration.
+ * @return The container id.
*/
public static String getContainerId() {
try {
diff --git a/src/site/asciidoc/manual/json-template-layout.adoc b/src/site/asciidoc/manual/json-template-layout.adoc
index 97a8898..dfef200 100644
--- a/src/site/asciidoc/manual/json-template-layout.adoc
+++ b/src/site/asciidoc/manual/json-template-layout.adoc
@@ -737,6 +737,8 @@
[source]
----
config = [ stringified ] , [ fallbackKey ]
+pattern = "pattern" -> string
+includeStackTrace = "includeStacktrae" -> boolean
stringified = "stringified" -> boolean
fallbackKey = "fallbackKey" -> string
----
@@ -754,6 +756,17 @@
}
----
+Resolve the message into a string using a pattern:
+
+[source,json]
+----
+{
+ "$resolver": "message",
+ "pattern": ""[%t] %-5p %X{requestId, sessionId, loginId, userId, ipAddress, corpAcctNumber} %C{1.}.%M:%L - %m"",
+ "stringified": true
+}
+----
+
Resolve the message such that if it is an `ObjectMessage` or a
`MultiformatMessage` with JSON support, its type (string, list, object, etc.)
will be retained:
diff --git a/src/site/markdown/manual/cloud.md b/src/site/markdown/manual/cloud.md
index 3df1d33..3eef8f8 100644
--- a/src/site/markdown/manual/cloud.md
+++ b/src/site/markdown/manual/cloud.md
@@ -129,7 +129,10 @@
Log4j provides a multitude of JSON generating layouts. In particular, [JSON
Template Layout](layouts.html#JSONTemplateLayout) allows full schema
customization and bundles ELK-specific layouts by default, which makes it a
-great fit for the bill.
+great fit for the bill. Using the EcsLayout template as shown below will generate data in Kibana where
+the message displayed exactly matches the message passed to Log4j and most of the event attributes, including
+any exceptions, are present as individual attributes that can be displayed. Note, however that stack traces
+will be formatted without newlines.
<Socket name="Logstash"
host="${sys:logstash.host}"
@@ -139,7 +142,7 @@
<JsonTemplateLayout eventTemplateUri="classpath:EcsLayout.json">
<EventTemplateAdditionalFields>
<EventTemplateAdditionalField key="containerId" value="${docker:containerId:-}"/>
- <EventTemplateAdditionalField key="application" value="$${lower:${spring:spring.application.name:-spring}}"/>
+ <EventTemplateAdditionalField key="application" value="${lower:${spring:spring.application.name:-spring}}"/>
<EventTemplateAdditionalField key="kubernetes.serviceAccountName" value="${k8s:accountName:-}"/>
<EventTemplateAdditionalField key="kubernetes.containerId" value="${k8s:containerId:-}"/>
<EventTemplateAdditionalField key="kubernetes.containerName" value="${k8s:containerName:-}"/>
@@ -157,6 +160,119 @@
</EventTemplateAdditionalFields>
</JsonTemplateLayout>
</Socket>
+
+The JsonTemplateLayout can also be used to generate JSON that matches the GELF specification which can
+format the message attribute using a pattern in accordance with the PatternLayout. For example, the following
+template, named EnhancedGelf.json, can be used to generate GELF-compliant data that can be passed to Logstash.
+With this template the message attribute will include the thread id, level, specific ThreadContext attributes,
+the class name, method name, and line number as well as the message. If an exception is included it will also
+be included with newlines. This format follows very closely what you would see in a typical log file on disk
+using the PatternLayout but has the additional advantage of including the attributes as separate fields that
+can be queried.
+
+ {
+ "version": "1.1",
+ "host": "${hostName}",
+ "short_message": {
+ "$resolver": "message",
+ "stringified": true
+ },
+ "full_message": {
+ "$resolver": "message",
+ "pattern": "[%t] %-5p %X{requestId, sessionId, loginId, userId, ipAddress, corpAcctNumber} %C{1.}.%M:%L - %m",
+ "stringified": true
+ },
+ "timestamp": {
+ "$resolver": "timestamp",
+ "epoch": {
+ "unit": "secs"
+ }
+ },
+ "level": {
+ "$resolver": "level",
+ "field": "severity",
+ "severity": {
+ "field": "code"
+ }
+ },
+ "_logger": {
+ "$resolver": "logger",
+ "field": "name"
+ },
+ "_thread": {
+ "$resolver": "thread",
+ "field": "name"
+ },
+ "_mdc": {
+ "$resolver": "mdc",
+ "flatten": {
+ "prefix": "_"
+ },
+ "stringified": true
+ }
+ }
+
+The logging configuration to use this template would be
+
+ <Socket name="Elastic"
+ host="\${sys:logstash.search.host}"
+ port="12222"
+ protocol="tcp"
+ bufferedIo="true">
+ <JsonTemplateLayout eventTemplateUri="classpath:EnhancedGelf.json" eventDelimiter="null">
+ <EventTemplateAdditionalFields>
+ <EventTemplateAdditionalField key="containerId" value="${docker:containerId:-}"/>
+ <EventTemplateAdditionalField key="application" value="${lower:${spring:spring.application.name:-spring}}"/>
+ <EventTemplateAdditionalField key="kubernetes.serviceAccountName" value="${k8s:accountName:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.containerId" value="${k8s:containerId:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.containerName" value="${k8s:containerName:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.host" value="${k8s:host:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.labels.app" value="${k8s:labels.app:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.labels.pod-template-hash" value="${k8s:labels.podTemplateHash:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.master_url" value="${k8s:masterUrl:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.namespaceId" value="${k8s:namespaceId:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.namespaceName" value="${k8s:namespaceName:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.podID" value="${k8s:podId:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.podIP" value="${k8s:podIp:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.podName" value="${k8s:podName:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.imageId" value="${k8s:imageId:-}"/>
+ <EventTemplateAdditionalField key="kubernetes.imageName" value="${k8s:imageName:-}"/>
+ </EventTemplateAdditionalFields>
+ </JsonTemplateLayout>
+ </Socket>
+The significant difference with this configuration from the first example is that it references the
+custom template and it specifies an event delimiter of a null character ('\0');
+
+Note: The level being passed with the above template does not strictly conform to the GELF spec as the
+Level being passed is the Log4j Level NOT the Level defined in the GELF spec. However, testing has shown
+that Logstash, Elk, and Kibana are pretty tolerant of whatever data is passed to it.
+
+Finally, the GelfLayout can be used to generate GELF compliant output. Unlike the JsonTemplateLayout it
+adheres closely to the GELF spec.
+
+ <Socket name="Elastic" host="${sys:elastic.search.host}" port="12222" protocol="tcp" bufferedIo="true">
+ <GelfLayout includeStackTrace="true" host="${hostName}" includeThreadContext="true" includeNullDelimiter="true"
+ compressionType="OFF">
+ <ThreadContextIncludes>requestId,sessionId,loginId,userId,ipAddress,callingHost</ThreadContextIncludes>
+ <MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, ipAddress} %C{1.}.%M:%L - %m%n</MessagePattern>
+ <KeyValuePair key="containerId" value="${docker:containerId:-}"/>
+ <KeyValuePair key="application" value="${lower:${spring:spring.application.name:-spring}}"/>
+ <KeyValuePair key="kubernetes.serviceAccountName" value="${k8s:accountName:-}"/>
+ <KeyValuePair key="kubernetes.containerId" value="${k8s:containerId:-}"/>
+ <KeyValuePair key="kubernetes.containerName" value="${k8s:containerName:-}"/>
+ <KeyValuePair key="kubernetes.host" value="${k8s:host:-}"/>
+ <KeyValuePair key="kubernetes.labels.app" value="${k8s:labels.app:-}"/>
+ <KeyValuePair key="kubernetes.labels.pod-template-hash" value="${k8s:labels.podTemplateHash:-}"/>
+ <KeyValuePair key="kubernetes.master_url" value="${k8s:masterUrl:-}"/>
+ <KeyValuePair key="kubernetes.namespaceId" value="${k8s:namespaceId:-}"/>
+ <KeyValuePair key="kubernetes.namespaceName" value="${k8s:namespaceName:-}"/>
+ <KeyValuePair key="kubernetes.podID" value="${k8s:podId:-}"/>
+ <KeyValuePair key="kubernetes.podIP" value="${k8s:podIp:-}"/>
+ <KeyValuePair key="kubernetes.podName" value="${k8s:podName:-}"/>
+ <KeyValuePair key="kubernetes.imageId" value="${k8s:imageId:-}"/>
+ <KeyValuePair key="kubernetes.imageName" value="${k8s:imageName:-}"/>
+ </GelfLayout>
+ </Socket>
### Logstash Configuration
@@ -182,11 +298,52 @@
}
}
+
+When one of the GELF compliant formats is used Logstash should be configured as
+
+ gelf {
+ host => "localhost"
+ use_tcp => true
+ use_udp => false
+ port => 12222
+ type => "gelf"
+ }
+ }
+
+ filter {
+ # These are GELF/Syslog logging levels as defined in RFC 3164. Map the integer level to its human readable format.
+ translate {
+ field => "[level]"
+ destination => "[levelName]"
+ dictionary => {
+ "0" => "EMERG"
+ "1" => "ALERT"
+ "2" => "CRITICAL"
+ "3" => "ERROR"
+ "4" => "WARN"
+ "5" => "NOTICE"
+ "6" => "INFO"
+ "7" => "DEBUG"
+ }
+ }
+ }
+
+ output {
+ # (Un)comment for debugging purposes
+ # stdout { codec => rubydebug }
+ # Modify the hosts value to reflect where elasticsearch is installed.
+ elasticsearch {
+ hosts => ["http://localhost:9200/"]
+ index => "app-%{application}-%{+YYYY.MM.dd}"
+ }
+ }
### Kibana
-With the above configurations the message field will contain a fully formatted log event just as it would appear in
-a file Appender. The ThreadContext attributes, custome fields, thread name, etc. will all be available as attributes
-on each log event that can be used for filtering.
+Using the EnhancedGelf template or the GelfLayout the above configurations the message field will contain a fully
+formatted log event just as it would appear in a file Appender. The ThreadContext attributes, custome fields,
+thread name, etc. will all be available as attributes on each log event that can be used for filtering.
+The result will resemble
+![](../images/kibana.png)
## Managing Logging Configuration
diff --git a/src/site/resources/images/kibana.png b/src/site/resources/images/kibana.png
new file mode 100644
index 0000000..3b15693
--- /dev/null
+++ b/src/site/resources/images/kibana.png
Binary files differ