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 org.apache.logging.log4j.core.LogEvent;
20  import org.apache.logging.log4j.core.config.plugins.Plugin;
21  import org.apache.logging.log4j.core.config.plugins.PluginAttr;
22  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
23  import org.apache.logging.log4j.core.helpers.Charsets;
24  import org.apache.logging.log4j.core.net.Facility;
25  import org.apache.logging.log4j.core.net.Priority;
26  
27  import java.net.InetAddress;
28  import java.net.UnknownHostException;
29  import java.nio.charset.Charset;
30  import java.text.SimpleDateFormat;
31  import java.util.Date;
32  import java.util.Locale;
33  import java.util.regex.Matcher;
34  import java.util.regex.Pattern;
35  
36  
37  /**
38   * Formats a log event as a BSD Log record.
39   */
40  @Plugin(name = "SyslogLayout", type = "Core", elementType = "layout", printObject = true)
41  public class SyslogLayout extends AbstractStringLayout {
42      /**
43       * Match newlines in a platform-independent manner.
44       */
45      public static final Pattern NEWLINE_PATTERN = Pattern.compile("\\r?\\n");
46  
47      private final Facility facility;
48      private final boolean includeNewLine;
49      private final String escapeNewLine;
50  
51      /**
52       * Date format used if header = true.
53       */
54      private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss ", Locale.ENGLISH);
55      /**
56       * Host name used to identify messages from this appender.
57       */
58      private final String localHostname = getLocalHostname();
59  
60  
61  
62      protected SyslogLayout(final Facility facility, final boolean includeNL, final String escapeNL, final Charset c) {
63          super(c);
64          this.facility = facility;
65          this.includeNewLine = includeNL;
66          this.escapeNewLine = escapeNL == null ? null : Matcher.quoteReplacement(escapeNL);
67      }
68  
69      /**
70       * Formats a {@link org.apache.logging.log4j.core.LogEvent} in conformance with the log4j.dtd.
71       *
72       * @param event The LogEvent
73       * @return the event formatted as a String.
74       */
75      public String toSerializable(final LogEvent event) {
76          final StringBuilder buf = new StringBuilder();
77  
78          buf.append("<");
79          buf.append(Priority.getPriority(facility, event.getLevel()));
80          buf.append(">");
81          addDate(event.getMillis(), buf);
82          buf.append(" ");
83          buf.append(localHostname);
84          buf.append(" ");
85  
86          String message = event.getMessage().getFormattedMessage();
87          if (null != escapeNewLine) {
88              message = NEWLINE_PATTERN.matcher(message).replaceAll(escapeNewLine);
89          }
90          buf.append(message);
91  
92          if (includeNewLine) {
93              buf.append("\n");
94          }
95          return buf.toString();
96      }
97  
98      /**
99       * This method gets the network name of the machine we are running on.
100      * Returns "UNKNOWN_LOCALHOST" in the unlikely case where the host name
101      * cannot be found.
102      *
103      * @return String the name of the local host
104      */
105     private String getLocalHostname() {
106         try {
107             final InetAddress addr = InetAddress.getLocalHost();
108             return addr.getHostName();
109         } catch (final UnknownHostException uhe) {
110             LOGGER.error("Could not determine local host name", uhe);
111             return "UNKNOWN_LOCALHOST";
112         }
113     }
114 
115     private synchronized void addDate(final long timestamp, final StringBuilder buf) {
116         final int index = buf.length() + 4;
117         buf.append(dateFormat.format(new Date(timestamp)));
118         //  RFC 3164 says leading space, not leading zero on days 1-9
119         if (buf.charAt(index) == '0') {
120             buf.setCharAt(index, ' ');
121         }
122     }
123 
124     /**
125      * Create a SyslogLayout.
126      * @param facility The Facility is used to try to classify the message.
127      * @param includeNL If true a newline will be appended to the result.
128      * @param escapeNL Pattern to use for replacing newlines.
129      * @param charsetName The character set.
130      * @return A SyslogLayout.
131      */
132     @PluginFactory
133     public static SyslogLayout createLayout(@PluginAttr("facility") final String facility,
134                                             @PluginAttr("newLine") final String includeNL,
135                                             @PluginAttr("newLineEscape") final String escapeNL,
136                                             @PluginAttr("charset") final String charsetName) {
137         final Charset charset = Charsets.getSupportedCharset(charsetName);
138         final boolean includeNewLine = includeNL == null ? false : Boolean.valueOf(includeNL);
139         final Facility f = Facility.toFacility(facility, Facility.LOCAL0);
140         return new SyslogLayout(f, includeNewLine, escapeNL, charset);
141     }
142 }