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.ByteArrayOutputStream;
020import java.io.IOException;
021import java.io.ObjectOutputStream;
022import java.io.OutputStream;
023
024import org.apache.logging.log4j.core.Layout;
025import org.apache.logging.log4j.core.LogEvent;
026import org.apache.logging.log4j.core.config.Node;
027import org.apache.logging.log4j.core.config.plugins.Plugin;
028import org.apache.logging.log4j.core.config.plugins.PluginFactory;
029
030/**
031 * Formats a {@link LogEvent} in its Java serialized form.
032 */
033@Plugin(name = "SerializedLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
034public final class SerializedLayout extends AbstractLayout<LogEvent> {
035
036    private static byte[] serializedHeader;
037
038    static {
039        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
040        try {
041            new ObjectOutputStream(baos).close();
042            serializedHeader = baos.toByteArray();
043        } catch (final Exception ex) {
044            LOGGER.error("Unable to generate Object stream header", ex);
045        }
046    }
047
048    private SerializedLayout() {
049        super(null, null, null);
050    }
051
052    /**
053     * Formats a {@link org.apache.logging.log4j.core.LogEvent} as a serialized byte array of the LogEvent object.
054     *
055     * @param event The LogEvent.
056     * @return the formatted LogEvent.
057     */
058    @Override
059    public byte[] toByteArray(final LogEvent event) {
060        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
061        try (final ObjectOutputStream oos = new PrivateObjectOutputStream(baos)) {
062            oos.writeObject(event);
063            oos.reset();
064        } catch (final IOException ioe) {
065            LOGGER.error("Serialization of LogEvent failed.", ioe);
066        }
067        return baos.toByteArray();
068    }
069
070    /**
071     * Returns the LogEvent.
072     *
073     * @param event The Logging Event.
074     * @return The LogEvent.
075     */
076    @Override
077    public LogEvent toSerializable(final LogEvent event) {
078        return event;
079    }
080
081    /**
082     * Creates a SerializedLayout.
083     * @return A SerializedLayout.
084     */
085    @PluginFactory
086    public static SerializedLayout createLayout() {
087        return new SerializedLayout();
088    }
089
090    @Override
091    public byte[] getHeader() {
092        return serializedHeader;
093    }
094
095    /**
096     * SerializedLayout returns a binary stream.
097     * @return The content type.
098     */
099    @Override
100    public String getContentType() {
101        return "application/octet-stream";
102    }
103
104    /**
105     * The stream header will be written in the Manager so skip it here.
106     */
107    private class PrivateObjectOutputStream extends ObjectOutputStream {
108
109        public PrivateObjectOutputStream(final OutputStream os) throws IOException {
110            super(os);
111        }
112
113        @Override
114        protected void writeStreamHeader() {
115        }
116    }
117}