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