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 */
017package org.apache.logging.log4j.core.layout;
018
019import java.io.IOException;
020import java.nio.charset.Charset;
021
022import org.apache.commons.csv.CSVFormat;
023import org.apache.commons.csv.CSVPrinter;
024import org.apache.commons.csv.QuoteMode;
025import org.apache.logging.log4j.core.Layout;
026import org.apache.logging.log4j.core.LogEvent;
027import org.apache.logging.log4j.core.config.Configuration;
028import org.apache.logging.log4j.core.config.Node;
029import org.apache.logging.log4j.core.config.plugins.Plugin;
030import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
031import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
032import org.apache.logging.log4j.core.config.plugins.PluginFactory;
033import org.apache.logging.log4j.message.Message;
034import org.apache.logging.log4j.status.StatusLogger;
035
036/**
037 * A Comma-Separated Value (CSV) layout to log event parameters.
038 * The event message is currently ignored. 
039 * 
040 * <p>
041 * Best used with:
042 * </p>
043 * <p>
044 * {@code logger.debug(new ObjectArrayMessage(1, 2, "Bob"));}
045 * </p>
046 * 
047 * Depends on Apache Commons CSV 1.2.
048 * 
049 * @since 2.4
050 */
051@Plugin(name = "CsvParameterLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
052public class CsvParameterLayout extends AbstractCsvLayout {
053
054    public static AbstractCsvLayout createDefaultLayout() {
055        return new CsvParameterLayout(null, Charset.forName(DEFAULT_CHARSET), CSVFormat.valueOf(DEFAULT_FORMAT), null, null);
056    }
057
058    public static AbstractCsvLayout createLayout(final CSVFormat format) {
059        return new CsvParameterLayout(null, Charset.forName(DEFAULT_CHARSET), format, null, null);
060    }
061
062    @PluginFactory
063    public static AbstractCsvLayout createLayout(
064            // @formatter:off
065            @PluginConfiguration final Configuration config,
066            @PluginAttribute(value = "format", defaultString = DEFAULT_FORMAT) final String format,
067            @PluginAttribute("delimiter") final Character delimiter,
068            @PluginAttribute("escape") final Character escape,
069            @PluginAttribute("quote") final Character quote,
070            @PluginAttribute("quoteMode") final QuoteMode quoteMode,
071            @PluginAttribute("nullString") final String nullString,
072            @PluginAttribute("recordSeparator") final String recordSeparator,
073            @PluginAttribute(value = "charset", defaultString = DEFAULT_CHARSET) final Charset charset,
074            @PluginAttribute("header") final String header, 
075            @PluginAttribute("footer") final String footer)
076            // @formatter:on
077    {
078
079        final CSVFormat csvFormat = createFormat(format, delimiter, escape, quote, quoteMode, nullString, recordSeparator);
080        return new CsvParameterLayout(config, charset, csvFormat, header, footer);
081    }
082
083    public CsvParameterLayout(final Configuration config, final Charset charset, final CSVFormat csvFormat, final String header, final String footer) {
084        super(config, charset, csvFormat, header, footer);
085    }
086
087    @Override
088    public String toSerializable(final LogEvent event) {
089        final Message message = event.getMessage();
090        final Object[] parameters = message.getParameters();
091        final StringBuilder buffer = getStringBuilder();
092        try {
093            getFormat().printRecord(buffer, parameters);
094            return buffer.toString();
095        } catch (final IOException e) {
096            StatusLogger.getLogger().error(message, e);
097            return getFormat().getCommentMarker() + " " + e;
098        }
099    }
100
101}