View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.layout;
18  
19  import java.util.HashSet;
20  import java.util.Set;
21  
22  import javax.xml.stream.XMLStreamException;
23  
24  import org.apache.logging.log4j.core.impl.Log4jLogEvent;
25  import org.apache.logging.log4j.core.jackson.JsonConstants;
26  import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper;
27  import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper;
28  import org.apache.logging.log4j.core.jackson.Log4jYamlObjectMapper;
29  import org.apache.logging.log4j.core.jackson.XmlConstants;
30  import org.codehaus.stax2.XMLStreamWriter2;
31  
32  import com.fasterxml.jackson.core.PrettyPrinter;
33  import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
34  import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
35  import com.fasterxml.jackson.databind.ObjectMapper;
36  import com.fasterxml.jackson.databind.ObjectWriter;
37  import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
38  import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
39  import com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter;
40  
41  abstract class JacksonFactory {
42  
43      static class JSON extends JacksonFactory {
44  
45          private final boolean encodeThreadContextAsList;
46          private final boolean includeStacktrace;
47          private final boolean stacktraceAsString;
48          private final boolean objectMessageAsJsonObject;
49  
50          public JSON(final boolean encodeThreadContextAsList, final boolean includeStacktrace, final boolean stacktraceAsString, final boolean objectMessageAsJsonObject) {
51              this.encodeThreadContextAsList = encodeThreadContextAsList;
52              this.includeStacktrace = includeStacktrace;
53              this.stacktraceAsString = stacktraceAsString;
54              this.objectMessageAsJsonObject = objectMessageAsJsonObject;
55          }
56  
57          @Override
58          protected String getPropertNameForContextMap() {
59              return JsonConstants.ELT_CONTEXT_MAP;
60          }
61  
62          @Override
63          protected String getPropertNameForSource() {
64              return JsonConstants.ELT_SOURCE;
65          }
66  
67          @Override
68          protected String getPropertNameForNanoTime() {
69              return JsonConstants.ELT_NANO_TIME;
70          }
71  
72          @Override
73          protected PrettyPrinter newCompactPrinter() {
74              return new MinimalPrettyPrinter();
75          }
76  
77          @Override
78          protected ObjectMapper newObjectMapper() {
79              return new Log4jJsonObjectMapper(encodeThreadContextAsList, includeStacktrace, stacktraceAsString, objectMessageAsJsonObject);
80          }
81  
82          @Override
83          protected PrettyPrinter newPrettyPrinter() {
84              return new DefaultPrettyPrinter();
85          }
86  
87      }
88  
89      static class XML extends JacksonFactory {
90  
91          static final int DEFAULT_INDENT = 1;
92  
93          private final boolean includeStacktrace;
94          private final boolean stacktraceAsString;
95  
96  
97          public XML(final boolean includeStacktrace, final boolean stacktraceAsString) {
98              this.includeStacktrace = includeStacktrace;
99              this.stacktraceAsString = stacktraceAsString;
100         }
101 
102         @Override
103         protected String getPropertNameForContextMap() {
104             return XmlConstants.ELT_CONTEXT_MAP;
105         }
106 
107         @Override
108         protected String getPropertNameForSource() {
109             return XmlConstants.ELT_SOURCE;
110         }
111 
112         @Override
113         protected String getPropertNameForNanoTime() {
114             return JsonConstants.ELT_NANO_TIME;
115         }
116 
117         @Override
118         protected PrettyPrinter newCompactPrinter() {
119             // Yes, null is the proper answer.
120             return null;
121         }
122 
123         @Override
124         protected ObjectMapper newObjectMapper() {
125             return new Log4jXmlObjectMapper(includeStacktrace, stacktraceAsString);
126         }
127 
128         @Override
129         protected PrettyPrinter newPrettyPrinter() {
130             return new Log4jXmlPrettyPrinter(DEFAULT_INDENT);
131         }
132     }
133 
134     static class YAML extends JacksonFactory {
135 
136         private final boolean includeStacktrace;
137         private final boolean stacktraceAsString;
138 
139 
140         public YAML(final boolean includeStacktrace, final boolean stacktraceAsString) {
141             this.includeStacktrace = includeStacktrace;
142             this.stacktraceAsString = stacktraceAsString;
143         }
144 
145         @Override
146         protected String getPropertNameForContextMap() {
147             return JsonConstants.ELT_CONTEXT_MAP;
148         }
149 
150         @Override
151         protected String getPropertNameForSource() {
152             return JsonConstants.ELT_SOURCE;
153         }
154 
155         @Override
156         protected String getPropertNameForNanoTime() {
157             return JsonConstants.ELT_NANO_TIME;
158         }
159 
160         @Override
161         protected PrettyPrinter newCompactPrinter() {
162             return new MinimalPrettyPrinter();
163         }
164 
165         @Override
166         protected ObjectMapper newObjectMapper() {
167             return new Log4jYamlObjectMapper(false, includeStacktrace, stacktraceAsString);
168         }
169 
170         @Override
171         protected PrettyPrinter newPrettyPrinter() {
172             return new DefaultPrettyPrinter();
173         }
174     }
175 
176     /**
177      * When <Event>s are written into a XML file; the "Event" object is not the root element, but an element named
178      * <Events> created using {@link XmlLayout#getHeader()} and {@link XmlLayout#getFooter()} methods.
179      * <p>
180      * {@link com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter} is used to print the Event object into
181      * XML; hence it assumes &lt;Event&gt; tag as the root element, so it prints the &lt;Event&gt; tag without any
182      * indentation. To add an indentation to the &lt;Event&gt; tag; hence an additional indentation for any
183      * sub-elements, this class is written. As an additional task, to avoid the blank line printed after the ending
184      * &lt;/Event&gt; tag, {@link #writePrologLinefeed(XMLStreamWriter2)} method is also overridden.
185      * </p>
186      */
187     static class Log4jXmlPrettyPrinter extends DefaultXmlPrettyPrinter {
188 
189         private static final long serialVersionUID = 1L;
190 
191         Log4jXmlPrettyPrinter(final int nesting) {
192             _nesting = nesting;
193         }
194 
195         @Override
196         public void writePrologLinefeed(final XMLStreamWriter2 sw) throws XMLStreamException {
197             // nothing
198         }
199 
200         /**
201          * Sets the nesting level to 1 rather than 0, so the "Event" tag will get indentation of next level below root.
202          */
203         @Override
204         public DefaultXmlPrettyPrinter createInstance() {
205             return new Log4jXmlPrettyPrinter(XML.DEFAULT_INDENT);
206         }
207 
208     }
209 
210     abstract protected String getPropertNameForContextMap();
211 
212     abstract protected String getPropertNameForSource();
213 
214     abstract protected String getPropertNameForNanoTime();
215 
216     abstract protected PrettyPrinter newCompactPrinter();
217 
218     abstract protected ObjectMapper newObjectMapper();
219 
220     abstract protected PrettyPrinter newPrettyPrinter();
221 
222     ObjectWriter newWriter(final boolean locationInfo, final boolean properties, final boolean compact) {
223         final SimpleFilterProvider filters = new SimpleFilterProvider();
224         final Set<String> except = new HashSet<>(2);
225         if (!locationInfo) {
226             except.add(this.getPropertNameForSource());
227         }
228         if (!properties) {
229             except.add(this.getPropertNameForContextMap());
230         }
231         except.add(this.getPropertNameForNanoTime());
232         filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except));
233         final ObjectWriter writer = this.newObjectMapper().writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter());
234         return writer.with(filters);
235     }
236 
237 }