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.async;
018    
019    import java.util.HashMap;
020    import java.util.Map;
021    
022    import org.apache.logging.log4j.Level;
023    import org.apache.logging.log4j.Marker;
024    import org.apache.logging.log4j.ThreadContext.ContextStack;
025    import org.apache.logging.log4j.core.LogEvent;
026    import org.apache.logging.log4j.core.config.Property;
027    import org.apache.logging.log4j.core.lookup.StrSubstitutor;
028    import org.apache.logging.log4j.message.Message;
029    import org.apache.logging.log4j.message.SimpleMessage;
030    
031    import com.lmax.disruptor.EventFactory;
032    
033    /**
034     * When the Disruptor is started, the RingBuffer is populated with event
035     * objects. These objects are then re-used during the life of the RingBuffer.
036     */
037    public class RingBufferLogEvent implements LogEvent {
038        private static final long serialVersionUID = 8462119088943934758L;
039    
040        /**
041         * Creates the events that will be put in the RingBuffer.
042         */
043        private static class Factory implements EventFactory<RingBufferLogEvent> {
044            // @Override
045            @Override
046            public RingBufferLogEvent newInstance() {
047                return new RingBufferLogEvent();
048            }
049        }
050    
051        /** The {@code EventFactory} for {@code RingBufferLogEvent}s. */
052        public static final Factory FACTORY = new Factory();
053    
054        private AsyncLogger asyncLogger;
055        private String loggerName;
056        private Marker marker;
057        private String fqcn;
058        private Level level;
059        private Message message;
060        private Throwable thrown;
061        private Map<String, String> contextMap;
062        private ContextStack contextStack;
063        private String threadName;
064        private StackTraceElement location;
065        private long currentTimeMillis;
066        private boolean endOfBatch;
067        private boolean includeLocation;
068    
069        public void setValues(AsyncLogger asyncLogger, String loggerName,
070                Marker marker, String fqcn, Level level, Message data, Throwable t,
071                Map<String, String> map, ContextStack contextStack,
072                String threadName, StackTraceElement location,
073                long currentTimeMillis) {
074            this.asyncLogger = asyncLogger;
075            this.loggerName = loggerName;
076            this.marker = marker;
077            this.fqcn = fqcn;
078            this.level = level;
079            this.message = data;
080            this.thrown = t;
081            this.contextMap = map;
082            this.contextStack = contextStack;
083            this.threadName = threadName;
084            this.location = location;
085            this.currentTimeMillis = currentTimeMillis;
086        }
087    
088        /**
089         * Event processor that reads the event from the ringbuffer can call this
090         * method.
091         * 
092         * @param endOfBatch flag to indicate if this is the last event in a batch
093         *            from the RingBuffer
094         */
095        public void execute(boolean endOfBatch) {
096            this.endOfBatch = endOfBatch;
097            asyncLogger.actualAsyncLog(this);
098        }
099    
100        /**
101         * Returns {@code true} if this event is the end of a batch, {@code false}
102         * otherwise.
103         * 
104         * @return {@code true} if this event is the end of a batch, {@code false}
105         *         otherwise
106         */
107        @Override
108        public boolean isEndOfBatch() {
109            return endOfBatch;
110        }
111    
112        @Override
113        public void setEndOfBatch(boolean endOfBatch) {
114            this.endOfBatch = endOfBatch;
115        }
116    
117        @Override
118        public boolean isIncludeLocation() {
119            return includeLocation;
120        }
121    
122        @Override
123        public void setIncludeLocation(boolean includeLocation) {
124            this.includeLocation = includeLocation;
125        }
126    
127        // @Override
128        @Override
129        public String getLoggerName() {
130            return loggerName;
131        }
132    
133        // @Override
134        @Override
135        public Marker getMarker() {
136            return marker;
137        }
138    
139        // @Override
140        @Override
141        public String getFQCN() {
142            return fqcn;
143        }
144    
145        // @Override
146        @Override
147        public Level getLevel() {
148            return level;
149        }
150    
151        // @Override
152        @Override
153        public Message getMessage() {
154            if (message == null) {
155                message = new SimpleMessage("");
156            }
157            return message;
158        }
159    
160        // @Override
161        @Override
162        public Throwable getThrown() {
163            return thrown;
164        }
165    
166        // @Override
167        @Override
168        public Map<String, String> getContextMap() {
169            return contextMap;
170        }
171    
172        // @Override
173        @Override
174        public ContextStack getContextStack() {
175            return contextStack;
176        }
177    
178        // @Override
179        @Override
180        public String getThreadName() {
181            return threadName;
182        }
183    
184        // @Override
185        @Override
186        public StackTraceElement getSource() {
187            return location;
188        }
189    
190        // @Override
191        @Override
192        public long getMillis() {
193            return currentTimeMillis;
194        }
195    
196        /**
197         * Merges the contents of the specified map into the contextMap, after
198         * replacing any variables in the property values with the
199         * StrSubstitutor-supplied actual values.
200         * 
201         * @param properties configured properties
202         * @param strSubstitutor used to lookup values of variables in properties
203         */
204        public void mergePropertiesIntoContextMap(
205                Map<Property, Boolean> properties, StrSubstitutor strSubstitutor) {
206            if (properties == null) {
207                return; // nothing to do
208            }
209    
210            Map<String, String> map = (contextMap == null) ? new HashMap<String, String>()
211                    : new HashMap<String, String>(contextMap);
212    
213            for (Map.Entry<Property, Boolean> entry : properties.entrySet()) {
214                Property prop = entry.getKey();
215                if (map.containsKey(prop.getName())) {
216                    continue; // contextMap overrides config properties
217                }
218                String value = entry.getValue() ? strSubstitutor.replace(prop
219                        .getValue()) : prop.getValue();
220                map.put(prop.getName(), value);
221            }
222            contextMap = map;
223        }
224    }