001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.layout; 018 019 import org.apache.logging.log4j.core.LogEvent; 020 import org.apache.logging.log4j.core.config.plugins.Plugin; 021 import org.apache.logging.log4j.core.config.plugins.PluginAttr; 022 import org.apache.logging.log4j.core.config.plugins.PluginFactory; 023 import org.apache.logging.log4j.core.helpers.Charsets; 024 import org.apache.logging.log4j.core.net.Facility; 025 import org.apache.logging.log4j.core.net.Priority; 026 027 import java.net.InetAddress; 028 import java.net.UnknownHostException; 029 import java.nio.charset.Charset; 030 import java.text.SimpleDateFormat; 031 import java.util.Date; 032 import java.util.Locale; 033 import java.util.regex.Matcher; 034 import java.util.regex.Pattern; 035 036 037 /** 038 * Formats a log event as a BSD Log record. 039 */ 040 @Plugin(name = "SyslogLayout", type = "Core", elementType = "layout", printObject = true) 041 public class SyslogLayout extends AbstractStringLayout { 042 /** 043 * Match newlines in a platform-independent manner. 044 */ 045 public static final Pattern NEWLINE_PATTERN = Pattern.compile("\\r?\\n"); 046 047 private final Facility facility; 048 private final boolean includeNewLine; 049 private final String escapeNewLine; 050 051 /** 052 * Date format used if header = true. 053 */ 054 private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss ", Locale.ENGLISH); 055 /** 056 * Host name used to identify messages from this appender. 057 */ 058 private final String localHostname = getLocalHostname(); 059 060 061 062 protected SyslogLayout(final Facility facility, final boolean includeNL, final String escapeNL, final Charset c) { 063 super(c); 064 this.facility = facility; 065 this.includeNewLine = includeNL; 066 this.escapeNewLine = escapeNL == null ? null : Matcher.quoteReplacement(escapeNL); 067 } 068 069 /** 070 * Formats a {@link org.apache.logging.log4j.core.LogEvent} in conformance with the log4j.dtd. 071 * 072 * @param event The LogEvent 073 * @return the event formatted as a String. 074 */ 075 public String toSerializable(final LogEvent event) { 076 final StringBuilder buf = new StringBuilder(); 077 078 buf.append("<"); 079 buf.append(Priority.getPriority(facility, event.getLevel())); 080 buf.append(">"); 081 addDate(event.getMillis(), buf); 082 buf.append(" "); 083 buf.append(localHostname); 084 buf.append(" "); 085 086 String message = event.getMessage().getFormattedMessage(); 087 if (null != escapeNewLine) { 088 message = NEWLINE_PATTERN.matcher(message).replaceAll(escapeNewLine); 089 } 090 buf.append(message); 091 092 if (includeNewLine) { 093 buf.append("\n"); 094 } 095 return buf.toString(); 096 } 097 098 /** 099 * 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 }