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