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  
49          public JSON(final boolean encodeThreadContextAsList, final boolean includeStacktrace, final boolean stacktraceAsString) {
50              this.encodeThreadContextAsList = encodeThreadContextAsList;
51              this.includeStacktrace = includeStacktrace;
52              this.stacktraceAsString = stacktraceAsString;
53          }
54  
55          @Override
56          protected String getPropertNameForContextMap() {
57              return JsonConstants.ELT_CONTEXT_MAP;
58          }
59  
60          @Override
61          protected String getPropertNameForSource() {
62              return JsonConstants.ELT_SOURCE;
63          }
64  
65          @Override
66          protected String getPropertNameForNanoTime() {
67              return JsonConstants.ELT_NANO_TIME;
68          }
69  
70          @Override
71          protected PrettyPrinter newCompactPrinter() {
72              return new MinimalPrettyPrinter();
73          }
74  
75          @Override
76          protected ObjectMapper newObjectMapper() {
77              return new Log4jJsonObjectMapper(encodeThreadContextAsList, includeStacktrace, stacktraceAsString);
78          }
79  
80          @Override
81          protected PrettyPrinter newPrettyPrinter() {
82              return new DefaultPrettyPrinter();
83          }
84      }
85  
86      static class XML extends JacksonFactory {
87  
88          static final int DEFAULT_INDENT = 1;
89  
90          private final boolean includeStacktrace;
91          private final boolean stacktraceAsString;
92  
93  
94          public XML(final boolean includeStacktrace, final boolean stacktraceAsString) {
95              this.includeStacktrace = includeStacktrace;
96              this.stacktraceAsString = stacktraceAsString;
97          }
98  
99          @Override
100         protected String getPropertNameForContextMap() {
101             return XmlConstants.ELT_CONTEXT_MAP;
102         }
103 
104         @Override
105         protected String getPropertNameForSource() {
106             return XmlConstants.ELT_SOURCE;
107         }
108 
109         @Override
110         protected String getPropertNameForNanoTime() {
111             return JsonConstants.ELT_NANO_TIME;
112         }
113 
114         @Override
115         protected PrettyPrinter newCompactPrinter() {
116             // Yes, null is the proper answer.
117             return null;
118         }
119 
120         @Override
121         protected ObjectMapper newObjectMapper() {
122             return new Log4jXmlObjectMapper(includeStacktrace, stacktraceAsString);
123         }
124 
125         @Override
126         protected PrettyPrinter newPrettyPrinter() {
127             return new Log4jXmlPrettyPrinter(DEFAULT_INDENT);
128         }
129     }
130 
131     static class YAML extends JacksonFactory {
132 
133         private final boolean includeStacktrace;
134         private final boolean stacktraceAsString;
135 
136 
137         public YAML(final boolean includeStacktrace, final boolean stacktraceAsString) {
138             this.includeStacktrace = includeStacktrace;
139             this.stacktraceAsString = stacktraceAsString;
140         }
141 
142         @Override
143         protected String getPropertNameForContextMap() {
144             return JsonConstants.ELT_CONTEXT_MAP;
145         }
146 
147         @Override
148         protected String getPropertNameForSource() {
149             return JsonConstants.ELT_SOURCE;
150         }
151 
152         @Override
153         protected String getPropertNameForNanoTime() {
154             return JsonConstants.ELT_NANO_TIME;
155         }
156 
157         @Override
158         protected PrettyPrinter newCompactPrinter() {
159             return new MinimalPrettyPrinter();
160         }
161 
162         @Override
163         protected ObjectMapper newObjectMapper() {
164             return new Log4jYamlObjectMapper(false, includeStacktrace, stacktraceAsString);
165         }
166 
167         @Override
168         protected PrettyPrinter newPrettyPrinter() {
169             return new DefaultPrettyPrinter();
170         }
171     }
172 
173     /**
174      * When <Event>s are written into a XML file; the "Event" object is not the root element, but an element named
175      * <Events> created using {@link XmlLayout#getHeader()} and {@link XmlLayout#getFooter()} methods.
176      * <p>
177      * {@link com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter} is used to print the Event object into
178      * XML; hence it assumes &lt;Event&gt; tag as the root element, so it prints the &lt;Event&gt; tag without any
179      * indentation. To add an indentation to the &lt;Event&gt; tag; hence an additional indentation for any
180      * sub-elements, this class is written. As an additional task, to avoid the blank line printed after the ending
181      * &lt;/Event&gt; tag, {@link #writePrologLinefeed(XMLStreamWriter2)} method is also overridden.
182      * </p>
183      */
184     static class Log4jXmlPrettyPrinter extends DefaultXmlPrettyPrinter {
185 
186         private static final long serialVersionUID = 1L;
187 
188         Log4jXmlPrettyPrinter(final int nesting) {
189             _nesting = nesting;
190         }
191 
192         @Override
193         public void writePrologLinefeed(final XMLStreamWriter2 sw) throws XMLStreamException {
194             // nothing
195         }
196 
197         /**
198          * Sets the nesting level to 1 rather than 0, so the "Event" tag will get indentation of next level below root.
199          */
200         @Override
201         public DefaultXmlPrettyPrinter createInstance() {
202             return new Log4jXmlPrettyPrinter(XML.DEFAULT_INDENT);
203         }
204 
205     }
206 
207     abstract protected String getPropertNameForContextMap();
208 
209     abstract protected String getPropertNameForSource();
210 
211     abstract protected String getPropertNameForNanoTime();
212 
213     abstract protected PrettyPrinter newCompactPrinter();
214 
215     abstract protected ObjectMapper newObjectMapper();
216 
217     abstract protected PrettyPrinter newPrettyPrinter();
218 
219     ObjectWriter newWriter(final boolean locationInfo, final boolean properties, final boolean compact) {
220         final SimpleFilterProvider filters = new SimpleFilterProvider();
221         final Set<String> except = new HashSet<>(2);
222         if (!locationInfo) {
223             except.add(this.getPropertNameForSource());
224         }
225         if (!properties) {
226             except.add(this.getPropertNameForContextMap());
227         }
228         except.add(this.getPropertNameForNanoTime());
229         filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except));
230         final ObjectWriter writer = this.newObjectMapper().writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter());
231         return writer.with(filters);
232     }
233 
234 }