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.io.IOException;
20  import java.io.Writer;
21  import java.nio.charset.Charset;
22  
23  import org.apache.logging.log4j.core.LogEvent;
24  import org.apache.logging.log4j.core.config.Configuration;
25  import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
26  import org.apache.logging.log4j.core.impl.MutableLogEvent;
27  import org.apache.logging.log4j.core.util.StringBuilderWriter;
28  import org.apache.logging.log4j.util.Strings;
29  
30  import com.fasterxml.jackson.core.JsonGenerationException;
31  import com.fasterxml.jackson.databind.JsonMappingException;
32  import com.fasterxml.jackson.databind.ObjectWriter;
33  
34  abstract class AbstractJacksonLayout extends AbstractStringLayout {
35  
36      protected static final String DEFAULT_EOL = "\r\n";
37      protected static final String COMPACT_EOL = Strings.EMPTY;
38  
39      public static abstract class Builder<B extends Builder<B>> extends AbstractStringLayout.Builder<B> {
40  
41          @PluginBuilderAttribute
42          private boolean eventEol;
43          
44          @PluginBuilderAttribute
45          private boolean compact;
46          
47          @PluginBuilderAttribute
48          private boolean complete;
49  
50          @PluginBuilderAttribute
51          private boolean locationInfo;
52  
53          @PluginBuilderAttribute
54          private boolean properties;
55  
56          @PluginBuilderAttribute
57          private boolean includeStacktrace = true;
58  
59          @PluginBuilderAttribute
60          private boolean stacktraceAsString = false;
61  
62          @PluginBuilderAttribute
63          private boolean includeNullDelimiter = false;
64  
65          protected String toStringOrNull(final byte[] header) {
66              return header == null ? null : new String(header, Charset.defaultCharset());
67          }
68  
69          public boolean getEventEol() {
70              return eventEol;
71          }
72  
73          public boolean isCompact() {
74              return compact;
75          }
76  
77          public boolean isComplete() {
78              return complete;
79          }
80  
81          public boolean isLocationInfo() {
82              return locationInfo;
83          }
84  
85          public boolean isProperties() {
86              return properties;
87          }
88  
89          /**
90           * If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true".
91           * @return If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true".
92           */
93          public boolean isIncludeStacktrace() {
94              return includeStacktrace;
95          }
96  
97          public boolean isStacktraceAsString() {
98              return stacktraceAsString;
99          }
100 
101         public boolean isIncludeNullDelimiter() { return includeNullDelimiter; }
102 
103         public B setEventEol(final boolean eventEol) {
104             this.eventEol = eventEol;
105             return asBuilder();
106         }
107 
108         public B setCompact(final boolean compact) {
109             this.compact = compact;
110             return asBuilder();
111         }
112 
113         public B setComplete(final boolean complete) {
114             this.complete = complete;
115             return asBuilder();
116         }
117 
118         public B setLocationInfo(final boolean locationInfo) {
119             this.locationInfo = locationInfo;
120             return asBuilder();
121         }
122 
123         public B setProperties(final boolean properties) {
124             this.properties = properties;
125             return asBuilder();
126         }
127 
128         /**
129          * If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true".
130          * @param includeStacktrace If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true".
131          * @return this builder
132          */
133         public B setIncludeStacktrace(final boolean includeStacktrace) {
134             this.includeStacktrace = includeStacktrace;
135             return asBuilder();
136         }
137 
138         /**
139          * Whether to format the stacktrace as a string, and not a nested object (optional, defaults to false).
140          *
141          * @return this builder
142          */
143         public B setStacktraceAsString(final boolean stacktraceAsString) {
144             this.stacktraceAsString = stacktraceAsString;
145             return asBuilder();
146         }
147 
148         /**
149          * Whether to include NULL byte as delimiter after each event (optional, default to false).
150          *
151          * @return this builder
152          */
153         public B setIncludeNullDelimiter(final boolean includeNullDelimiter) {
154             this.includeNullDelimiter = includeNullDelimiter;
155             return asBuilder();
156         }
157     }
158 
159     protected final String eol;
160     protected final ObjectWriter objectWriter;
161     protected final boolean compact;
162     protected final boolean complete;
163     protected final boolean includeNullDelimiter;
164 
165     @Deprecated
166     protected AbstractJacksonLayout(final Configuration config, final ObjectWriter objectWriter, final Charset charset,
167             final boolean compact, final boolean complete, final boolean eventEol, final Serializer headerSerializer,
168             final Serializer footerSerializer) {
169         this(config, objectWriter, charset, compact, complete, eventEol, headerSerializer, footerSerializer, false);
170     }
171 
172     protected AbstractJacksonLayout(final Configuration config, final ObjectWriter objectWriter, final Charset charset,
173             final boolean compact, final boolean complete, final boolean eventEol, final Serializer headerSerializer,
174             final Serializer footerSerializer, final boolean includeNullDelimiter) {
175         super(config, charset, headerSerializer, footerSerializer);
176         this.objectWriter = objectWriter;
177         this.compact = compact;
178         this.complete = complete;
179         this.eol = compact && !eventEol ? COMPACT_EOL : DEFAULT_EOL;
180         this.includeNullDelimiter = includeNullDelimiter;
181     }
182 
183     /**
184      * Formats a {@link org.apache.logging.log4j.core.LogEvent}.
185      *
186      * @param event The LogEvent.
187      * @return The XML representation of the LogEvent.
188      */
189     @Override
190     public String toSerializable(final LogEvent event) {
191         final StringBuilderWriter writer = new StringBuilderWriter();
192         try {
193             toSerializable(event, writer);
194             return writer.toString();
195         } catch (final IOException e) {
196             // Should this be an ISE or IAE?
197             LOGGER.error(e);
198             return Strings.EMPTY;
199         }
200     }
201 
202     private static LogEvent convertMutableToLog4jEvent(final LogEvent event) {
203         // TODO Jackson-based layouts have certain filters set up for Log4jLogEvent.
204         // TODO Need to set up the same filters for MutableLogEvent but don't know how...
205         // This is a workaround.
206         return event instanceof MutableLogEvent
207                 ? ((MutableLogEvent) event).createMemento()
208                 : event;
209     }
210 
211     public void toSerializable(final LogEvent event, final Writer writer)
212             throws JsonGenerationException, JsonMappingException, IOException {
213         objectWriter.writeValue(writer, convertMutableToLog4jEvent(event));
214         writer.write(eol);
215         if (includeNullDelimiter) {
216             writer.write('\0');
217         }
218         markEvent();
219     }
220 
221 }