View Javadoc

1   package org.apache.velocity.runtime.log;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import java.io.IOException;
23  import java.lang.reflect.Field;
24  import org.apache.log4j.Level;
25  import org.apache.log4j.Logger;
26  import org.apache.log4j.PatternLayout;
27  import org.apache.log4j.RollingFileAppender;
28  import org.apache.velocity.runtime.RuntimeConstants;
29  import org.apache.velocity.runtime.RuntimeServices;
30  import org.apache.velocity.util.ExceptionUtils;
31  
32  /**
33   * Implementation of a simple log4j system that will either latch onto
34   * an existing category, or just do a simple rolling file log.
35   *
36   * @author <a href="mailto:geirm@apache.org>Geir Magnusson Jr.</a>
37   * @author <a href="mailto:dlr@finemaltcoding.com>Daniel L. Rall</a>
38   * @author <a href="mailto:nbubna@apache.org>Nathan Bubna</a>
39   * @version $Id: Log4JLogChute.java 718424 2008-11-17 22:50:43Z nbubna $
40   * @since Velocity 1.5
41   * @since 1.5
42   */
43  public class Log4JLogChute implements LogChute
44  {
45      public static final String RUNTIME_LOG_LOG4J_LOGGER =
46              "runtime.log.logsystem.log4j.logger";
47      public static final String RUNTIME_LOG_LOG4J_LOGGER_LEVEL =
48              "runtime.log.logsystem.log4j.logger.level";
49  
50      private RuntimeServices rsvc = null;
51      private boolean hasTrace = false;
52      private RollingFileAppender appender = null;
53  
54      /**
55       * <a href="http://jakarta.apache.org/log4j/">Log4J</a> logging API.
56       */
57      protected Logger logger = null;
58  
59      /**
60       * @see org.apache.velocity.runtime.log.LogChute#init(org.apache.velocity.runtime.RuntimeServices)
61       */
62      public void init(RuntimeServices rs) throws Exception
63      {
64          rsvc = rs;
65  
66          /* first see if there is a category specified and just use that - it allows
67           * the application to make us use an existing logger
68           */
69          String name = (String)rsvc.getProperty(RUNTIME_LOG_LOG4J_LOGGER);
70          if (name != null)
71          {
72              logger = Logger.getLogger(name);
73              log(DEBUG_ID, "Log4JLogChute using logger '" + name + '\'');
74          }
75          else
76          {
77              // create a logger with this class name to avoid conflicts
78              logger = Logger.getLogger(this.getClass().getName());
79  
80              // if we have a file property, then create a separate
81              // rolling file log for velocity messages only
82              String file = rsvc.getString(RuntimeConstants.RUNTIME_LOG);
83              if (file != null && file.length() > 0)
84              {
85                  initAppender(file);
86              }
87          }
88  
89          /* get and set specified level for this logger */
90          String lvl = rsvc.getString(RUNTIME_LOG_LOG4J_LOGGER_LEVEL);
91          if (lvl != null)
92          {
93              Level level = Level.toLevel(lvl);
94              logger.setLevel(level);
95          }
96          
97          /* Ok, now let's see if this version of log4j supports the trace level. */
98          try
99          {
100             Field traceLevel = Level.class.getField("TRACE");
101             // we'll never get here in pre 1.2.12 log4j
102             hasTrace = true;
103         }
104         catch (NoSuchFieldException e)
105         {
106             log(DEBUG_ID,
107                 "The version of log4j being used does not support the \"trace\" level.");
108         }
109     }
110 
111     // This tries to create a file appender for the specified file name.
112     private void initAppender(String file) throws Exception
113     {
114         try
115         {
116             // to add the appender
117             PatternLayout layout = new PatternLayout("%d - %m%n");
118             this.appender = new RollingFileAppender(layout, file, true);
119 
120             // if we successfully created the file appender,
121             // configure it and set the logger to use only it
122             appender.setMaxBackupIndex(1);
123             appender.setMaximumFileSize(100000);
124 
125             // don't inherit appenders from higher in the logger heirarchy
126             logger.setAdditivity(false);
127             logger.addAppender(appender);
128             log(DEBUG_ID, "Log4JLogChute initialized using file '"+file+'\'');
129         }
130         catch (IOException ioe)
131         {
132             rsvc.getLog().error("Could not create file appender '"+file+'\'', ioe);
133             throw ExceptionUtils.createRuntimeException("Error configuring Log4JLogChute : ", ioe);
134         }
135     }
136 
137     /**
138      *  logs messages
139      *
140      *  @param level severity level
141      *  @param message complete error message
142      */
143     public void log(int level, String message)
144     {
145         switch (level)
146         {
147             case LogChute.WARN_ID:
148                 logger.warn(message);
149                 break;
150             case LogChute.INFO_ID:
151                 logger.info(message);
152                 break;
153             case LogChute.TRACE_ID:
154                 if (hasTrace)
155                 {
156                     logger.trace(message);
157                 }
158                 else
159                 {
160                     logger.debug(message);
161                 }
162                 break;
163             case LogChute.ERROR_ID:
164                 logger.error(message);
165                 break;
166             case LogChute.DEBUG_ID:
167             default:
168                 logger.debug(message);
169                 break;
170         }
171     }
172 
173     /**
174      * @see org.apache.velocity.runtime.log.LogChute#log(int, java.lang.String, java.lang.Throwable)
175      */
176     public void log(int level, String message, Throwable t)
177     {
178         switch (level)
179         {
180             case LogChute.WARN_ID:
181                 logger.warn(message, t);
182                 break;
183             case LogChute.INFO_ID:
184                 logger.info(message, t);
185                 break;
186             case LogChute.TRACE_ID:
187                 if (hasTrace)
188                 {
189                     logger.trace(message, t);
190                 }
191                 else
192                 {
193                     logger.debug(message, t);
194                 }
195                 break;
196             case LogChute.ERROR_ID:
197                 logger.error(message, t);
198                 break;
199             case LogChute.DEBUG_ID:
200             default:
201                 logger.debug(message, t);
202                 break;
203         }
204     }
205 
206     /**
207      * @see org.apache.velocity.runtime.log.LogChute#isLevelEnabled(int)
208      */
209     public boolean isLevelEnabled(int level)
210     {
211         switch (level)
212         {
213             case LogChute.DEBUG_ID:
214                 return logger.isDebugEnabled();
215             case LogChute.INFO_ID:
216                 return logger.isInfoEnabled();
217             case LogChute.TRACE_ID:
218                 if (hasTrace)
219                 {
220                     return logger.isTraceEnabled();
221                 }
222                 else
223                 {
224                     return logger.isDebugEnabled();
225                 }
226             case LogChute.WARN_ID:
227                 return logger.isEnabledFor(Level.WARN);
228             case LogChute.ERROR_ID:
229                 // can't be disabled in log4j
230                 return logger.isEnabledFor(Level.ERROR);
231             default:
232                 return true;
233         }
234     }
235 
236     /**
237      * Also do a shutdown if the object is destroy()'d.
238      * @throws Throwable
239      */
240     protected void finalize() throws Throwable
241     {
242         shutdown();
243     }
244 
245     /** Close all destinations*/
246     public void shutdown()
247     {
248         if (appender != null)
249         {
250             logger.removeAppender(appender);
251             appender.close();
252             appender = null;
253         }
254     }
255 
256 }