|
1 | 1 | [[intro]]
|
2 | 2 | == Introduction
|
3 | 3 |
|
4 |
| -Centralized logging for Java applications with the Elastic stack made easy. |
| 4 | +ECS loggers are formatter/encoder plugins for your favorite logging libraries. |
| 5 | +They make it easy to format your logs into ECS-compatible JSON. |
5 | 6 |
|
| 7 | +TIP: Want to learn more about ECS, ECS logging, and other available language plugins? |
| 8 | +See the {ecs-logging-ref}/intro.html[ECS logging guide]. |
6 | 9 |
|
7 |
| -NOTE: This library is in **beta**. Backward-incompatible changes might be introduced in future releases while the major version is zero (0.x.x). |
8 |
| - |
9 |
| -[role="screenshot"] |
10 |
| -image:https://user-images.githubusercontent.com/2163464/62682932-9cac3600-b9bd-11e9-9cc3-39e907280f8e.png[] |
11 |
| - |
12 |
| -[float] |
13 |
| -=== What is ECS? |
14 |
| - |
15 |
| -Elastic Common Schema (ECS) defines a common set of fields for ingesting data into Elasticsearch. |
16 |
| -For more information about ECS, visit the {ecs-ref}/ecs-reference.html[ECS Reference Documentation]. |
17 |
| - |
18 |
| -[float] |
19 |
| -=== What is ECS logging? |
20 |
| - |
21 |
| -ECS loggers are formatter/encoder plugins for your favorite logging library. |
22 |
| -They make it easy to format your logs into ECS-compatible JSON. For example: |
23 |
| -[source,json] |
24 |
| ----- |
25 |
| -{"@timestamp":"2019-08-06T12:09:12.375Z", "log.level": "INFO", "message":"Tomcat started on port(s): 8080 (http) with context path ''", "service.name":"spring-petclinic","process.thread.name":"restartedMain","log.logger":"org.springframework.boot.web.embedded.tomcat.TomcatWebServer"} |
26 |
| -{"@timestamp":"2019-08-06T12:09:12.379Z", "log.level": "INFO", "message":"Started PetClinicApplication in 7.095 seconds (JVM running for 9.082)", "service.name":"spring-petclinic","process.thread.name":"restartedMain","log.logger":"org.springframework.samples.petclinic.PetClinicApplication"} |
27 |
| -{"@timestamp":"2019-08-06T14:08:40.199Z", "log.level":"DEBUG", "message":"init find form", "service.name":"spring-petclinic","process.thread.name":"http-nio-8080-exec-8","log.logger":"org.springframework.samples.petclinic.owner.OwnerController","transaction.id":"28b7fb8d5aba51f1","trace.id":"2869b25b5469590610fea49ac04af7da"} |
28 |
| -{"@timestamp":"2019-09-17T13:16:48.038Z", "log.level":"ERROR", "message":"Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: Expected: controller used to showcase what happens when an exception is thrown] with root cause", "process.thread.name":"http-nio-8080-exec-1","log.logger":"org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]","log.origin":{"file.name":"DirectJDKLog.java","function":"log","file.line":175},"error.type":"java.lang.RuntimeException","error.message":"Expected: controller used to showcase what happens when an exception is thrown","error.stack_trace":[ |
29 |
| - "java.lang.RuntimeException: Expected: controller used to showcase what happens when an exception is thrown", |
30 |
| - "\tat org.springframework.samples.petclinic.system.CrashController.triggerException(CrashController.java:33)", |
31 |
| - "\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)", |
32 |
| - "\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)", |
33 |
| - "\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)", |
34 |
| - "\tat java.lang.reflect.Method.invoke(Method.java:498)", |
35 |
| - "\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)", |
36 |
| - "\tat java.lang.Thread.run(Thread.java:748)"]} |
37 |
| ----- |
38 |
| - |
39 |
| -[float] |
40 |
| -=== Why ECS logging? |
41 |
| - |
42 |
| -*No parsing of the log file required*:: |
43 |
| -+ |
44 |
| --- |
45 |
| -ECS-compatible JSON doesn't require the use of Logstash or grok parsing via an ingest node pipeline. |
46 |
| --- |
47 |
| - |
48 |
| -*No external dependencies*:: |
49 |
| -+ |
50 |
| --- |
51 |
| -By not using any external dependencies such as JSON serializers, |
52 |
| -the library is incredibly lightweight. |
53 |
| --- |
54 |
| - |
55 |
| -*Highly efficient*:: |
56 |
| -+ |
57 |
| --- |
58 |
| -The log4j2 `EcsLayout` does not allocate any memory (unless the log event contains an `Exception`) which reduces GC pressure. |
59 |
| -This is achieved by manually serializing JSON so that no intermediate JSON or map representation of a log event is needed. |
60 |
| --- |
61 |
| - |
62 |
| -*Decently human-readable JSON structure*:: |
63 |
| -+ |
64 |
| --- |
65 |
| -The first three fields are always `@timestamp`, `log.level` and `message`. |
66 |
| -It's also possible to format stack traces so that each element is rendered in a new line. |
67 |
| --- |
68 |
| - |
69 |
| -*Enjoy the benefits of a common schema*:: |
70 |
| -+ |
71 |
| --- |
72 |
| -Use the Kibana {observability-guide}/monitor-logs.html[Logs app] without additional configuration. |
73 |
| - |
74 |
| -Using a common schema across different services and teams makes it possible create reusable dashboards and avoids {ref}/mapping.html#mapping-limit-settings[mapping explosions]. |
75 |
| --- |
76 |
| - |
77 |
| -*APM Log correlation*:: |
78 |
| -+ |
79 |
| --- |
80 |
| -If you are using the {apm-java-ref}/index.html[Elastic APM Java agent], |
81 |
| -you can leverage the {apm-java-ref}/config-logging.html#config-enable-log-correlation[log correlation feature] without any additional configuration. |
82 |
| -This lets you jump from the {kibana-ref}/spans.html[Span timeline in the APM UI] to the {observability-guide}/monitor-logs.html[Logs app], |
83 |
| -showing only the logs which belong to the corresponding request. |
84 |
| -Vice versa, you can also jump from a log line in the Logs UI to the Span Timeline of the APM UI. |
85 |
| --- |
86 |
| - |
87 |
| -[float] |
88 |
| -==== Additional advantages when using in combination with Filebeat |
89 |
| - |
90 |
| -We recommend using this library to log into a JSON log file and using Filebeat to send the logs to Elasticsearch. Here are a few benefits to this approach. |
91 |
| - |
92 |
| -*Resilient in case of outages*:: |
93 |
| -+ |
94 |
| --- |
95 |
| -{filebeat-ref}/how-filebeat-works.html#at-least-once-delivery[Guaranteed at-least-once delivery] |
96 |
| -without buffering within the application, thus no risk of `OutOfMemoryError` s or lost events. |
97 |
| -There's also the option to use either the JSON logs or plain-text logs as a fallback. |
98 |
| --- |
99 |
| - |
100 |
| -*Loose coupling*:: |
101 |
| -+ |
102 |
| --- |
103 |
| -The application does not need to know the details of the logging backend (URI, credentials, etc.). |
104 |
| -You can also leverage alternative {filebeat-ref}/configuring-output.html[Filebeat outputs], |
105 |
| -like Logstash, Kafka or Redis. |
106 |
| --- |
107 |
| - |
108 |
| -*Index Lifecycle management*:: |
109 |
| -+ |
110 |
| --- |
111 |
| -Leverage Filebeat's default {filebeat-ref}/ilm.html[index lifecycle management settings]. |
112 |
| -This is much more efficient than using daily indices. |
113 |
| --- |
114 |
| - |
115 |
| -*Efficient Elasticsearch mappings*:: |
116 |
| -+ |
117 |
| --- |
118 |
| -Leverage Filebeat's default ECS-compatible {filebeat-ref}/configuration-template.html[index template] |
119 |
| --- |
120 |
| - |
121 |
| -[float] |
122 |
| -=== Mapping |
123 |
| - |
124 |
| -|=== |
125 |
| -|ECS field | Log4j2 API |
126 |
| -|{ecs-ref}/ecs-base.html[`@timestamp`] |
127 |
| -|https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getTimeMillis()[`LogEvent#getTimeMillis()`] |
128 |
| - |
129 |
| -|{ecs-ref}/ecs-log.html[`log.level`] |
130 |
| -|https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getLevel()[`LogEvent#getLevel()`] |
131 |
| - |
132 |
| -|{ecs-ref}/ecs-log.html[`log.logger`] |
133 |
| -|https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getLoggerName()[`LogEvent#getLoggerName()`] |
134 |
| - |
135 |
| -|{ecs-ref}/ecs-log.html[`log.origin.file.name`] |
136 |
| -|https://docs.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html#getFileName()[`StackTraceElement#getFileName()`] |
137 |
| - |
138 |
| -|{ecs-ref}/ecs-log.html[`log.origin.file.line`] |
139 |
| -|https://docs.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html#getLineNumber()[`StackTraceElement#getLineNumber()`] |
140 |
| - |
141 |
| -|{ecs-ref}/ecs-log.html[`log.origin.function`] |
142 |
| -|https://docs.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html#getMethodName()[`StackTraceElement#getMethodName()`] |
143 |
| - |
144 |
| -|{ecs-ref}/ecs-base.html[`message`] |
145 |
| -|https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getMessage()[`LogEvent#getMessage()`] |
146 |
| - |
147 |
| -|{ecs-ref}/ecs-error.html[`error.type`] |
148 |
| -|https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass()[`Throwable#getClass()`] |
149 |
| - |
150 |
| -|{ecs-ref}/ecs-error.html[`error.message`] |
151 |
| -|https://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#getMessage()[`Throwable#getMessage()`] |
152 |
| - |
153 |
| -|{ecs-ref}/ecs-error.html[`error.stack_trace`] |
154 |
| -|https://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#getStackTrace()[`Throwable#getStackTrace()`] |
155 |
| - |
156 |
| -|{ecs-ref}/ecs-process.html[`process.thread.name`] |
157 |
| -|https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getThreadName()[`LogEvent#getThreadName()`] |
158 |
| - |
159 |
| -|Each MDC entry is a top-level field footnote:[ |
160 |
| -We recommend using existing {ecs-ref}/ecs-field-reference.html[ECS fields] for MDC values. |
161 |
| -If there is no appropriate ECS field, |
162 |
| -consider prefixing your fields with `labels.`, as in `labels.foo`, for simple key/value pairs. |
163 |
| -For nested structures, consider prefixing with `custom.`. This approach protects against conflicts in case ECS later adds the same fields but with a different mapping. |
164 |
| -] |
165 |
| -|https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getContextMap()[`LogEvent#getContextMap()`] |
166 |
| - |
167 |
| -|{ecs-ref}/ecs-base.html[`tags`] |
168 |
| -|https://logging.apache.org/log4j/log4j-2.3/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getContextStack()[`LogEvent#getContextStack()`] |
169 |
| -|=== |
| 10 | +Ready to jump into `ecs-logging-java`? <<setup,Get started>>. |
0 commit comments