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.Serializable;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.Layout;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.config.Configuration;
27 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
28 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
29 import org.apache.logging.log4j.status.StatusLogger;
30
31 /**
32 * Abstract base class for Layouts.
33 *
34 * @param <T>
35 * The Class that the Layout will format the LogEvent into.
36 */
37 public abstract class AbstractLayout<T extends Serializable> implements Layout<T> {
38
39 /**
40 * Subclasses can extend this abstract Builder.
41 *
42 * @param <B> The type to build.
43 */
44 public abstract static class Builder<B extends Builder<B>> {
45
46 @PluginConfiguration
47 private Configuration configuration;
48
49 @PluginBuilderAttribute
50 private byte[] footer;
51
52 @PluginBuilderAttribute
53 private byte[] header;
54
55 @SuppressWarnings("unchecked")
56 public B asBuilder() {
57 return (B) this;
58 }
59
60 public Configuration getConfiguration() {
61 return configuration;
62 }
63
64 public byte[] getFooter() {
65 return footer;
66 }
67
68 public byte[] getHeader() {
69 return header;
70 }
71
72 public B setConfiguration(final Configuration configuration) {
73 this.configuration = configuration;
74 return asBuilder();
75 }
76
77 public B setFooter(final byte[] footer) {
78 this.footer = footer;
79 return asBuilder();
80 }
81
82 public B setHeader(final byte[] header) {
83 this.header = header;
84 return asBuilder();
85 }
86
87 }
88
89 /**
90 * Allow subclasses access to the status logger without creating another instance.
91 */
92 protected static final Logger LOGGER = StatusLogger.getLogger();
93
94 /**
95 * The current Configuration.
96 */
97 protected final Configuration configuration;
98
99 /**
100 * The number of events successfully processed by this layout.
101 */
102 protected long eventCount;
103
104 /**
105 * The footer to add when the stream is closed. May be null.
106 */
107 protected final byte[] footer;
108
109 /**
110 * The header to include when the stream is opened. May be null.
111 */
112 protected final byte[] header;
113
114 /**
115 * Constructs a layout with an optional header and footer.
116 *
117 * @param header
118 * The header to include when the stream is opened. May be null.
119 * @param footer
120 * The footer to add when the stream is closed. May be null.
121 * @deprecated Use {@link #AbstractLayout(Configuration, byte[], byte[])}
122 */
123 @Deprecated
124 public AbstractLayout(final byte[] header, final byte[] footer) {
125 this(null, header, footer);
126 }
127
128 /**
129 * Constructs a layout with an optional header and footer.
130 *
131 * @param configuration
132 * The configuration
133 * @param header
134 * The header to include when the stream is opened. May be null.
135 * @param footer
136 * The footer to add when the stream is closed. May be null.
137 */
138 public AbstractLayout(final Configuration configuration, final byte[] header, final byte[] footer) {
139 super();
140 this.configuration = configuration;
141 this.header = header;
142 this.footer = footer;
143 }
144
145 public Configuration getConfiguration() {
146 return configuration;
147 }
148
149 @Override
150 public Map<String, String> getContentFormat() {
151 return new HashMap<>();
152 }
153
154 /**
155 * Returns the footer, if one is available.
156 *
157 * @return A byte array containing the footer.
158 */
159 @Override
160 public byte[] getFooter() {
161 return footer;
162 }
163
164 /**
165 * Returns the header, if one is available.
166 *
167 * @return A byte array containing the header.
168 */
169 @Override
170 public byte[] getHeader() {
171 return header;
172 }
173
174 protected void markEvent() {
175 eventCount++;
176 }
177
178 /**
179 * Encodes the specified source LogEvent to some binary representation and writes the result to the specified
180 * destination.
181 * <p>
182 * The default implementation of this method delegates to the {@link #toByteArray(LogEvent)} method which allocates
183 * temporary objects.
184 * </p><p>
185 * Subclasses can override this method to provide a garbage-free implementation. For text-based layouts,
186 * {@code AbstractStringLayout} provides various convenience methods to help with this:
187 * </p>
188 * <pre>@Plugin(name = "MyLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
189 * public final class MyLayout extends AbstractStringLayout {
190 * @Override
191 * public void encode(LogEvent event, ByteBufferDestination destination) {
192 * StringBuilder text = getStringBuilder();
193 * convertLogEventToText(event, text);
194 * getStringBuilderEncoder().encode(text, destination);
195 * }
196 *
197 * private void convertLogEventToText(LogEvent event, StringBuilder destination) {
198 * ... // append a text representation of the log event to the StringBuilder
199 * }
200 * }
201 * </pre>
202 *
203 * @param event the LogEvent to encode.
204 * @param destination holds the ByteBuffer to write into.
205 * @see AbstractStringLayout#getStringBuilder()
206 * @see AbstractStringLayout#getStringBuilderEncoder()
207 */
208 @Override
209 public void encode(final LogEvent event, final ByteBufferDestination destination) {
210 final byte[] data = toByteArray(event);
211 destination.writeBytes(data, 0, data.length);
212 }
213 }