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.util.HashMap;
020    import java.util.Map;
021    import org.apache.logging.log4j.core.LogEvent;
022    import org.apache.logging.log4j.core.config.plugins.Plugin;
023    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
024    
025    import java.io.ByteArrayOutputStream;
026    import java.io.IOException;
027    import java.io.ObjectOutputStream;
028    import java.io.OutputStream;
029    
030    /**
031     * Format a LogEvent in its 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[] header;
037    
038        static {
039            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
040            try {
041                final ObjectOutputStream oos = new ObjectOutputStream(baos);
042                oos.close();
043                header = baos.toByteArray();
044            } catch (final Exception ex) {
045                LOGGER.error("Unable to generate Object stream header", ex);
046            }
047        }
048    
049        private SerializedLayout() {
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 {
062                final ObjectOutputStream oos = new PrivateObjectOutputStream(baos);
063                try {
064                    oos.writeObject(event);
065                    oos.reset();
066                } finally {
067                    oos.close();
068                }
069            } catch (final IOException ioe) {
070                LOGGER.error("Serialization of LogEvent failed.", ioe);
071            }
072            return baos.toByteArray();
073        }
074    
075        /**
076         * Returns the LogEvent.
077         *
078         * @param event The Logging Event.
079         * @return The LogEvent.
080         */
081        @Override
082        public LogEvent toSerializable(final LogEvent event) {
083            return event;
084        }
085    
086        /**
087         * Create a SerializedLayout.
088         * @return A SerializedLayout.
089         */
090        @PluginFactory
091        public static SerializedLayout createLayout() {
092    
093            return new SerializedLayout();
094        }
095    
096        @Override
097        public byte[] getHeader() {
098            return header;
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    }