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