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.log4j.bridge;
018
019import org.apache.log4j.NDC;
020import org.apache.log4j.helpers.OptionConverter;
021import org.apache.log4j.spi.LocationInfo;
022import org.apache.log4j.spi.LoggingEvent;
023import org.apache.log4j.spi.ThrowableInformation;
024import org.apache.logging.log4j.Level;
025import org.apache.logging.log4j.Marker;
026import org.apache.logging.log4j.ThreadContext;
027import org.apache.logging.log4j.core.LogEvent;
028import org.apache.logging.log4j.core.impl.ThrowableProxy;
029import org.apache.logging.log4j.core.time.Instant;
030import org.apache.logging.log4j.core.time.MutableInstant;
031import org.apache.logging.log4j.message.Message;
032import org.apache.logging.log4j.message.SimpleMessage;
033import org.apache.logging.log4j.spi.MutableThreadContextStack;
034import org.apache.logging.log4j.util.BiConsumer;
035import org.apache.logging.log4j.util.ReadOnlyStringMap;
036import org.apache.logging.log4j.util.TriConsumer;
037
038import java.util.HashMap;
039import java.util.Map;
040import java.util.Objects;
041
042/**
043 * Exposes a Log4j 1 logging event as a Log4j 2 LogEvent.
044 */
045public class LogEventWrapper implements LogEvent {
046
047    private final LoggingEvent event;
048    private final ContextDataMap contextData;
049    private final MutableThreadContextStack contextStack;
050    private Thread thread;
051
052    public LogEventWrapper(LoggingEvent event) {
053        this.event = event;
054        this.contextData = new ContextDataMap(event.getProperties());
055        this.contextStack = new MutableThreadContextStack(NDC.cloneStack());
056        this.thread = Objects.equals(event.getThreadName(), Thread.currentThread().getName())
057                ? Thread.currentThread() : null;
058    }
059
060    @Override
061    public LogEvent toImmutable() {
062        return this;
063    }
064
065    @Override
066    public Map<String, String> getContextMap() {
067        return contextData;
068    }
069
070    @Override
071    public ReadOnlyStringMap getContextData() {
072        return contextData;
073    }
074
075    @Override
076    public ThreadContext.ContextStack getContextStack() {
077        return contextStack;
078    }
079
080    @Override
081    public String getLoggerFqcn() {
082        return null;
083    }
084
085    @Override
086    public Level getLevel() {
087        return OptionConverter.convertLevel(event.getLevel());
088    }
089
090    @Override
091    public String getLoggerName() {
092        return event.getLoggerName();
093    }
094
095    @Override
096    public Marker getMarker() {
097        return null;
098    }
099
100    @Override
101    public Message getMessage() {
102        return new SimpleMessage(event.getRenderedMessage());
103    }
104
105    @Override
106    public long getTimeMillis() {
107        return event.getTimeStamp();
108    }
109
110    @Override
111    public Instant getInstant() {
112        MutableInstant mutable = new MutableInstant();
113        mutable.initFromEpochMilli(event.getTimeStamp(), 0);
114        return mutable;
115    }
116
117    @Override
118    public StackTraceElement getSource() {
119        LocationInfo info = event.getLocationInformation();
120        return new StackTraceElement(info.getClassName(), info.getMethodName(), info.getFileName(),
121                Integer.parseInt(info.getLineNumber()));
122    }
123
124    @Override
125    public String getThreadName() {
126        return event.getThreadName();
127    }
128
129    @Override
130    public long getThreadId() {
131        Thread thread = getThread();
132        return thread != null ? thread.getId() : 0;
133    }
134
135    @Override
136    public int getThreadPriority() {
137        Thread thread = getThread();
138        return thread != null ? thread.getPriority() : 0;
139    }
140
141    private Thread getThread() {
142        if (thread == null && event.getThreadName() != null) {
143            for (Thread thread : Thread.getAllStackTraces().keySet()) {
144                if (thread.getName().equals(event.getThreadName())) {
145                    this.thread = thread;
146                    return thread;
147                }
148            }
149        }
150        return thread;
151    }
152
153    @Override
154    public Throwable getThrown() {
155        ThrowableInformation throwableInformation = event.getThrowableInformation();
156        return throwableInformation == null ? null : throwableInformation.getThrowable();
157    }
158
159    @Override
160    public ThrowableProxy getThrownProxy() {
161        return null;
162    }
163
164    @Override
165    public boolean isEndOfBatch() {
166        return false;
167    }
168
169    @Override
170    public boolean isIncludeLocation() {
171        return false;
172    }
173
174    @Override
175    public void setEndOfBatch(boolean endOfBatch) {
176
177    }
178
179    @Override
180    public void setIncludeLocation(boolean locationRequired) {
181
182    }
183
184    @Override
185    public long getNanoTime() {
186        return 0;
187    }
188
189    private static class ContextDataMap extends HashMap<String, String> implements ReadOnlyStringMap {
190
191        ContextDataMap(Map<String, String> map) {
192            if (map != null) {
193                super.putAll(map);
194            }
195        }
196
197        @Override
198        public Map<String, String> toMap() {
199            return this;
200        }
201
202        @Override
203        public boolean containsKey(String key) {
204            return super.containsKey(key);
205        }
206
207        @Override
208        public <V> void forEach(BiConsumer<String, ? super V> action) {
209            super.forEach((k,v) -> action.accept(k, (V) v));
210        }
211
212        @Override
213        public <V, S> void forEach(TriConsumer<String, ? super V, S> action, S state) {
214            super.forEach((k,v) -> action.accept(k, (V) v, state));
215        }
216
217        @Override
218        public <V> V getValue(String key) {
219            return (V) super.get(key);
220        }
221    }
222}