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