| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache license, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the license for the specific language governing permissions and |
| * limitations under the license. |
| */ |
| package org.apache.logging.log4j.core.layout; |
| |
| import org.apache.logging.log4j.core.Layout; |
| import org.apache.logging.log4j.core.LogEvent; |
| import org.apache.logging.log4j.core.net.Facility; |
| import org.apache.logging.log4j.core.net.Priority; |
| import org.apache.logging.log4j.core.util.NetUtils; |
| import org.apache.logging.log4j.plugins.Node; |
| import org.apache.logging.log4j.plugins.Plugin; |
| import org.apache.logging.log4j.plugins.PluginBuilderAttribute; |
| import org.apache.logging.log4j.plugins.PluginFactory; |
| import org.apache.logging.log4j.util.Chars; |
| |
| import java.nio.charset.Charset; |
| import java.nio.charset.StandardCharsets; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| /** |
| * Formats a log event as a BSD Log record. |
| */ |
| @Plugin(name = "SyslogLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) |
| public final class SyslogLayout extends AbstractStringLayout { |
| |
| /** |
| * Builds a SyslogLayout. |
| * <p>The main arguments are</p> |
| * <ul> |
| * <li>facility: The Facility is used to try to classify the message.</li> |
| * <li>includeNewLine: If true a newline will be appended to the result.</li> |
| * <li>escapeNL: Pattern to use for replacing newlines.</li> |
| * <li>charset: The character set.</li> |
| * </ul> |
| * @param <B> the builder type |
| */ |
| public static class Builder<B extends Builder<B>> extends AbstractStringLayout.Builder<B> |
| implements org.apache.logging.log4j.plugins.util.Builder<SyslogLayout> { |
| |
| public Builder() { |
| super(); |
| setCharset(StandardCharsets.UTF_8); |
| } |
| |
| @PluginBuilderAttribute |
| private Facility facility = Facility.LOCAL0; |
| |
| @PluginBuilderAttribute("newLine") |
| private boolean includeNewLine; |
| |
| @PluginBuilderAttribute("newLineEscape") |
| private String escapeNL; |
| |
| @Override |
| public SyslogLayout build() { |
| return new SyslogLayout(facility, includeNewLine, escapeNL, getCharset()); |
| } |
| |
| public Facility getFacility() { |
| return facility; |
| } |
| |
| public boolean isIncludeNewLine() { |
| return includeNewLine; |
| } |
| |
| public String getEscapeNL() { |
| return escapeNL; |
| } |
| |
| public B setFacility(final Facility facility) { |
| this.facility = facility; |
| return asBuilder(); |
| } |
| |
| public B setIncludeNewLine(final boolean includeNewLine) { |
| this.includeNewLine = includeNewLine; |
| return asBuilder(); |
| } |
| |
| public B setEscapeNL(final String escapeNL) { |
| this.escapeNL = escapeNL; |
| return asBuilder(); |
| } |
| |
| } |
| |
| @PluginFactory |
| public static <B extends Builder<B>> B newBuilder() { |
| return new Builder<B>().asBuilder(); |
| } |
| |
| /** |
| * Match newlines in a platform-independent manner. |
| */ |
| public static final Pattern NEWLINE_PATTERN = Pattern.compile("\\r?\\n"); |
| |
| private final Facility facility; |
| private final boolean includeNewLine; |
| private final String escapeNewLine; |
| |
| /** |
| * Date format used if header = true. |
| */ |
| private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss", Locale.ENGLISH); |
| |
| /** |
| * Host name used to identify messages from this appender. |
| */ |
| private final String localHostname = NetUtils.getLocalHostname(); |
| |
| protected SyslogLayout(final Facility facility, final boolean includeNL, final String escapeNL, final Charset charset) { |
| super(charset); |
| this.facility = facility; |
| this.includeNewLine = includeNL; |
| this.escapeNewLine = escapeNL == null ? null : Matcher.quoteReplacement(escapeNL); |
| } |
| |
| /** |
| * Formats a {@link org.apache.logging.log4j.core.LogEvent} in conformance with the BSD Log record format. |
| * |
| * @param event The LogEvent |
| * @return the event formatted as a String. |
| */ |
| @Override |
| public String toSerializable(final LogEvent event) { |
| final StringBuilder buf = getStringBuilder(); |
| |
| buf.append('<'); |
| buf.append(Priority.getPriority(facility, event.getLevel())); |
| buf.append('>'); |
| addDate(event.getTimeMillis(), buf); |
| buf.append(Chars.SPACE); |
| buf.append(localHostname); |
| buf.append(Chars.SPACE); |
| |
| String message = event.getMessage().getFormattedMessage(); |
| if (null != escapeNewLine) { |
| message = NEWLINE_PATTERN.matcher(message).replaceAll(escapeNewLine); |
| } |
| buf.append(message); |
| |
| if (includeNewLine) { |
| buf.append('\n'); |
| } |
| return buf.toString(); |
| } |
| |
| private synchronized void addDate(final long timestamp, final StringBuilder buf) { |
| final int index = buf.length() + 4; |
| buf.append(dateFormat.format(new Date(timestamp))); |
| // RFC 3164 says leading space, not leading zero on days 1-9 |
| if (buf.charAt(index) == '0') { |
| buf.setCharAt(index, Chars.SPACE); |
| } |
| } |
| |
| /** |
| * Gets this SyslogLayout's content format. Specified by: |
| * <ul> |
| * <li>Key: "structured" Value: "false"</li> |
| * <li>Key: "dateFormat" Value: "MMM dd HH:mm:ss"</li> |
| * <li>Key: "format" Value: "<LEVEL>TIMESTAMP PROP(HOSTNAME) MESSAGE"</li> |
| * <li>Key: "formatType" Value: "logfilepatternreceiver" (format uses the keywords supported by |
| * LogFilePatternReceiver)</li> |
| * </ul> |
| * |
| * @return Map of content format keys supporting SyslogLayout |
| */ |
| @Override |
| public Map<String, String> getContentFormat() { |
| final Map<String, String> result = new HashMap<>(); |
| result.put("structured", "false"); |
| result.put("formatType", "logfilepatternreceiver"); |
| result.put("dateFormat", dateFormat.toPattern()); |
| result.put("format", "<LEVEL>TIMESTAMP PROP(HOSTNAME) MESSAGE"); |
| return result; |
| } |
| |
| /** |
| * Gets the facility. |
| * |
| * @return the facility |
| */ |
| public Facility getFacility() { |
| return facility; |
| } |
| } |