View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.log4j.bridge;
18  
19  import org.apache.log4j.Category;
20  import org.apache.log4j.Level;
21  import org.apache.log4j.spi.LocationInfo;
22  import org.apache.log4j.spi.LoggingEvent;
23  import org.apache.log4j.spi.ThrowableInformation;
24  import org.apache.logging.log4j.core.LogEvent;
25  import org.apache.logging.log4j.core.util.Loader;
26  import org.apache.logging.log4j.core.util.Throwables;
27  import org.apache.logging.log4j.spi.StandardLevel;
28  import org.apache.logging.log4j.status.StatusLogger;
29  
30  import java.lang.reflect.Method;
31  import java.util.Map;
32  import java.util.Set;
33  
34  /**
35   * Converts a Log4j 2 LogEvent into the components needed by a Log4j 1.x LoggingEvent.
36   * This class requires Log4j 2.
37   */
38  public class LogEventAdapter extends LoggingEvent {
39  
40      private static final long JVM_START_TIME = initStartTime();
41  
42      private final LogEvent event;
43  
44      public LogEventAdapter(LogEvent event) {
45          this.event = event;
46      }
47  
48      /**
49       * Returns the time when the application started, in milliseconds
50       * elapsed since 01.01.1970.
51       * @return the time when the JVM started.
52       */
53      public static long getStartTime() {
54          return JVM_START_TIME;
55      }
56  
57      /**
58       * Returns the result of {@code ManagementFactory.getRuntimeMXBean().getStartTime()},
59       * or the current system time if JMX is not available.
60       */
61      private static long initStartTime() {
62          // We'd like to call ManagementFactory.getRuntimeMXBean().getStartTime(),
63          // but Google App Engine throws a java.lang.NoClassDefFoundError
64          // "java.lang.management.ManagementFactory is a restricted class".
65          // The reflection is necessary because without it, Google App Engine
66          // will refuse to initialize this class.
67          try {
68              final Class<?> factoryClass = Loader.loadSystemClass("java.lang.management.ManagementFactory");
69              final Method getRuntimeMXBean = factoryClass.getMethod("getRuntimeMXBean");
70              final Object runtimeMXBean = getRuntimeMXBean.invoke(null);
71  
72              final Class<?> runtimeMXBeanClass = Loader.loadSystemClass("java.lang.management.RuntimeMXBean");
73              final Method getStartTime = runtimeMXBeanClass.getMethod("getStartTime");
74              return (Long) getStartTime.invoke(runtimeMXBean);
75          } catch (final Throwable t) {
76              StatusLogger.getLogger().error("Unable to call ManagementFactory.getRuntimeMXBean().getStartTime(), "
77                      + "using system time for OnStartupTriggeringPolicy", t);
78              // We have little option but to declare "now" as the beginning of time.
79              return System.currentTimeMillis();
80          }
81      }
82  
83      public LogEvent getEvent() {
84          return this.event;
85      }
86  
87      /**
88       * Set the location information for this logging event. The collected
89       * information is cached for future use.
90       */
91      @Override
92      public LocationInfo getLocationInformation() {
93          return new LocationInfo(event.getSource());
94      }
95  
96      /**
97       * Return the level of this event. Use this form instead of directly
98       * accessing the <code>level</code> field.
99       */
100     @Override
101     public Level getLevel() {
102         switch (StandardLevel.getStandardLevel(event.getLevel().intLevel())) {
103             case TRACE:
104                 return Level.TRACE;
105             case DEBUG:
106                 return Level.DEBUG;
107             case INFO:
108                 return Level.INFO;
109             case WARN:
110                 return Level.WARN;
111             case FATAL:
112                 return Level.FATAL;
113             case OFF:
114                 return Level.OFF;
115             case ALL:
116                 return Level.ALL;
117             default:
118                 return Level.ERROR;
119         }
120     }
121 
122     /**
123      * Return the name of the logger. Use this form instead of directly
124      * accessing the <code>categoryName</code> field.
125      */
126     @Override
127     public String getLoggerName() {
128         return event.getLoggerName();
129     }
130 
131     /**
132      * Gets the logger of the event.
133      */
134     @Override
135     public Category getLogger() {
136         return Category.getInstance(event.getLoggerName());
137     }
138 
139     /*
140      Return the message for this logging event.
141     */
142     @Override
143     public Object getMessage() {
144         return event.getMessage();
145     }
146 
147     /*
148      * This method returns the NDC for this event.
149      */
150     @Override
151     public String getNDC() {
152         return event.getContextStack().toString();
153     }
154 
155     /*
156      Returns the the context corresponding to the <code>key</code> parameter.
157      */
158     @Override
159     public Object getMDC(String key) {
160         if (event.getContextData() != null) {
161             return event.getContextData().getValue(key);
162         } else {
163             return null;
164         }
165     }
166 
167     /**
168      * Obtain a copy of this thread's MDC prior to serialization or
169      * asynchronous logging.
170      */
171     @Override
172     public void getMDCCopy() {
173     }
174 
175     @Override
176     public String getRenderedMessage() {
177         return event.getMessage().getFormattedMessage();
178     }
179 
180     @Override
181     public String getThreadName() {
182         return event.getThreadName();
183     }
184 
185     /**
186      * Returns the throwable information contained within this
187      * event. May be <code>null</code> if there is no such information.
188      *
189      * <p>Note that the {@link Throwable} object contained within a
190      * {@link ThrowableInformation} does not survive serialization.
191      *
192      * @since 1.1
193      */
194     @Override
195     public ThrowableInformation getThrowableInformation() {
196         if (event.getThrown() != null) {
197             return new ThrowableInformation(event.getThrown());
198         }
199         return null;
200     }
201 
202     /**
203      * Return this event's throwable's string[] representaion.
204      */
205     @Override
206     public String[] getThrowableStrRep() {
207         if (event.getThrown() != null) {
208             return Throwables.toStringList(event.getThrown()).toArray(new String[0]);
209         }
210         return null;
211     }
212 
213     @Override
214     public String getProperty(final String key) {
215         return event.getContextData().getValue(key);
216     }
217 
218     @Override
219     public Set getPropertyKeySet() {
220         return event.getContextData().toMap().keySet();
221     }
222 
223     @Override
224     public Map getProperties() {
225         return event.getContextData().toMap();
226     }
227 }