001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.commons.io.log.log4j; 020 021import java.io.IOException; 022import java.io.PrintWriter; 023import java.nio.charset.Charset; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.Map; 027import java.util.Map.Entry; 028 029import lucee.commons.io.CharsetUtil; 030import lucee.commons.io.log.Log; 031import lucee.commons.io.log.LogUtil; 032import lucee.commons.io.log.log4j.appender.ConsoleAppender; 033import lucee.commons.io.log.log4j.appender.RollingResourceAppender; 034import lucee.commons.io.log.log4j.appender.TaskAppender; 035import lucee.commons.io.log.log4j.layout.ClassicLayout; 036import lucee.commons.io.res.Resource; 037import lucee.commons.io.res.util.ResourceUtil; 038import lucee.commons.io.retirement.RetireListener; 039import lucee.commons.lang.ClassUtil; 040import lucee.commons.lang.StringUtil; 041import lucee.runtime.config.Config; 042import lucee.runtime.config.ConfigImpl; 043import lucee.runtime.config.ConfigWeb; 044import lucee.runtime.config.ConfigWebUtil; 045import lucee.runtime.exp.PageException; 046import lucee.runtime.op.Caster; 047import lucee.runtime.reflection.Reflector; 048 049import org.apache.log4j.Appender; 050import org.apache.log4j.AppenderSkeleton; 051import org.apache.log4j.HTMLLayout; 052import org.apache.log4j.Layout; 053import org.apache.log4j.Level; 054import org.apache.log4j.LogManager; 055import org.apache.log4j.Logger; 056import org.apache.log4j.PatternLayout; 057import org.apache.log4j.xml.XMLLayout; 058 059public class Log4jUtil { 060 061 public static final long MAX_FILE_SIZE=1024*1024*10; 062 public static final int MAX_FILES=10; 063 private static final String DEFAULT_PATTERN = "%d{dd.MM.yyyy HH:mm:ss,SSS} %-5p [%c] %m%n"; 064 065 066 067 public static Logger getResourceLog(Config config, Resource res, Charset charset, String name, Level level, int timeout,RetireListener listener, boolean async) throws IOException { 068 Appender a = new RollingResourceAppender( 069 new ClassicLayout() 070 ,res 071 ,charset 072 ,true 073 ,RollingResourceAppender.DEFAULT_MAX_FILE_SIZE 074 ,RollingResourceAppender.DEFAULT_MAX_BACKUP_INDEX 075 ,timeout,listener); // no open stream at all 076 077 if(async) { 078 a=new TaskAppender(config, a); 079 } 080 081 082 return getLogger(config, a, name, level); 083 } 084 085 public static Logger getConsoleLog(Config config, boolean errorStream, String name, Level level) { 086 // Printwriter 087 PrintWriter pw=errorStream?config.getErrWriter():config.getOutWriter(); 088 if(pw==null)pw=new PrintWriter(errorStream?System.err:System.out); 089 090 return getLogger(config, new ConsoleAppender(pw,new PatternLayout(DEFAULT_PATTERN)), name, level); 091 } 092 093 public static final Logger getLogger(Config config,Appender appender, String name, Level level){ 094 // fullname 095 String fullname=name; 096 if(config instanceof ConfigWeb) { 097 ConfigWeb cw=(ConfigWeb) config; 098 fullname="web."+cw.getLabel()+"."+name; 099 } 100 else fullname="server."+name; 101 102 Logger l = LogManager.exists(fullname); 103 if(l!=null) l.removeAllAppenders(); 104 else l = LogManager.getLogger(fullname); 105 l.setAdditivity(false); 106 l.addAppender(appender); 107 l.setLevel(level); 108 return l; 109 } 110 111 112 public static final Appender getAppender(Config config,Layout layout,String name,String strAppender, Map<String, String> appenderArgs){ 113 if(appenderArgs==null)appenderArgs=new HashMap<String, String>(); 114 115 // Appender 116 Appender appender=null; 117 if(!StringUtil.isEmpty(strAppender)) { 118 // Console Appender 119 if("console".equalsIgnoreCase(strAppender) || ConsoleAppender.class.getName().equalsIgnoreCase(strAppender)) { 120 // stream-type 121 boolean doError=false; 122 String st = Caster.toString(appenderArgs.get("streamtype"),null); 123 if(!StringUtil.isEmpty(st,true)) { 124 st=st.trim().toLowerCase(); 125 if(st.equals("err") || st.equals("error")) 126 doError=true; 127 } 128 appenderArgs.put("streamtype",doError?"error":"output"); 129 130 131 // get print writer 132 PrintWriter pw; 133 if(doError) { 134 if(config.getErrWriter()==null)pw=new PrintWriter(System.err); 135 else pw=config.getErrWriter(); 136 } 137 else { 138 if(config.getOutWriter()==null)pw=new PrintWriter(System.out); 139 else pw=config.getOutWriter(); 140 } 141 appender = new ConsoleAppender(pw,layout); 142 } 143 else if("resource".equalsIgnoreCase(strAppender) || RollingResourceAppender.class.getName().equalsIgnoreCase(strAppender)) { 144 145 // path 146 Resource res=null; 147 String path = Caster.toString(appenderArgs.get("path"),null); 148 if(!StringUtil.isEmpty(path,true)) { 149 path=path.trim(); 150 path=ConfigWebUtil.translateOldPath(path); 151 res=ConfigWebUtil.getFile(config, config.getConfigDir(),path, ResourceUtil.TYPE_FILE); 152 if(res.isDirectory()) { 153 res=res.getRealResource(name+".log"); 154 } 155 } 156 if(res==null) { 157 res=ConfigWebUtil.getFile(config, config.getConfigDir(),"logs/"+name+".log", ResourceUtil.TYPE_FILE); 158 } 159 160 161 // charset 162 Charset charset = CharsetUtil.toCharset(Caster.toString(appenderArgs.get("charset"),null),null); 163 if(charset==null){ 164 charset=((ConfigImpl)config)._getResourceCharset(); 165 appenderArgs.put("charset",charset.name()); 166 } 167 168 // maxfiles 169 int maxfiles = Caster.toIntValue(appenderArgs.get("maxfiles"),10); 170 appenderArgs.put("maxfiles",Caster.toString(maxfiles)); 171 172 // maxfileSize 173 long maxfilesize = Caster.toLongValue(appenderArgs.get("maxfilesize"),1024*1024*10); 174 appenderArgs.put("maxfilesize",Caster.toString(maxfilesize)); 175 176 // timeout 177 int timeout = Caster.toIntValue(appenderArgs.get("timeout"),60); // timeout in seconds 178 appenderArgs.put("timeout",Caster.toString(timeout)); 179 180 try { 181 appender=new RollingResourceAppender(layout,res,charset,true,maxfilesize,maxfiles,timeout,null); 182 } 183 catch (IOException e) { 184 e.printStackTrace(); 185 } 186 } 187 // class defintion 188 else { 189 Object obj = ClassUtil.loadInstance(strAppender,null,null); 190 if(obj instanceof Appender) { 191 appender=(Appender) obj; 192 193 AppenderSkeleton as=obj instanceof AppenderSkeleton?(AppenderSkeleton)obj:null; 194 195 Iterator<Entry<String, String>> it = appenderArgs.entrySet().iterator(); 196 Entry<String, String> e; 197 String n; 198 while(it.hasNext()){ 199 e = it.next(); 200 n=e.getKey(); 201 /*print.e("------------------------- "); 202 print.e(e.getKey()); 203 print.e(e.getValue()); 204 print.e("is as:"+(as!=null));*/ 205 if(as!=null) { 206 if("threshold".equalsIgnoreCase(n)) { 207 Level level = Level.toLevel(e.getValue(),null); 208 if(level!=null) { 209 as.setThreshold(level); 210 continue; 211 } 212 } 213 } 214 215 try { 216 Reflector.callSetter(obj, e.getKey(), e.getValue()); 217 } 218 catch (PageException e1) { 219 e1.printStackTrace(); // TODO log 220 } 221 } 222 } 223 } 224 } 225 if(appender instanceof AppenderSkeleton) { 226 ((AppenderSkeleton)appender).activateOptions(); 227 } 228 else if(appender==null) { 229 PrintWriter pw; 230 if(config.getOutWriter()==null)pw=new PrintWriter(System.out); 231 else pw=config.getOutWriter(); 232 appender=new ConsoleAppender(pw,layout); 233 } 234 235 236 return appender; 237 } 238 239 public static final Layout getLayout(String strLayout, Map<String, String> layoutArgs) { 240 if(layoutArgs==null)layoutArgs=new HashMap<String, String>(); 241 242 // Layout 243 Layout layout=null; 244 if(!StringUtil.isEmpty(strLayout)) { 245 // Classic Layout 246 if("classic".equalsIgnoreCase(strLayout) || ClassicLayout.class.getName().equalsIgnoreCase(strLayout)) 247 layout=new ClassicLayout(); 248 249 // HTML Layout 250 else if("html".equalsIgnoreCase(strLayout) || HTMLLayout.class.getName().equalsIgnoreCase(strLayout)) { 251 HTMLLayout html = new HTMLLayout(); 252 layout=html; 253 254 // Location Info 255 Boolean locInfo = Caster.toBoolean(layoutArgs.get("locationinfo"),null); 256 if(locInfo!=null) html.setLocationInfo(locInfo.booleanValue()); 257 else locInfo=Boolean.FALSE; 258 layoutArgs.put("locationinfo", locInfo.toString()); 259 260 // Title 261 String title = Caster.toString(layoutArgs.get("title"),""); 262 if(!StringUtil.isEmpty(title,true)) html.setTitle(title); 263 layoutArgs.put("title", title); 264 265 } 266 // XML Layout 267 else if("xml".equalsIgnoreCase(strLayout) || XMLLayout.class.getName().equalsIgnoreCase(strLayout)) { 268 XMLLayout xml = new XMLLayout(); 269 layout=xml; 270 271 // Location Info 272 Boolean locInfo = Caster.toBoolean(layoutArgs.get("locationinfo"),null); 273 if(locInfo!=null) xml.setLocationInfo(locInfo.booleanValue()); 274 else locInfo=Boolean.FALSE; 275 layoutArgs.put("locationinfo", locInfo.toString()); 276 277 // Properties 278 Boolean props = Caster.toBoolean(layoutArgs.get("properties"),null); 279 if(props!=null) xml.setProperties(props.booleanValue()); 280 else props=Boolean.FALSE; 281 layoutArgs.put("properties", props.toString()); 282 283 } 284 // Pattern Layout 285 else if("pattern".equalsIgnoreCase(strLayout) || PatternLayout.class.getName().equalsIgnoreCase(strLayout)) { 286 PatternLayout patt = new PatternLayout(); 287 layout=patt; 288 289 // pattern 290 String pattern = Caster.toString(layoutArgs.get("pattern"),null); 291 if(!StringUtil.isEmpty(pattern,true)) patt.setConversionPattern(pattern); 292 else { 293 patt.setConversionPattern(DEFAULT_PATTERN); 294 layoutArgs.put("pattern", DEFAULT_PATTERN); 295 } 296 } 297 // class defintion 298 else { 299 Object obj = ClassUtil.loadInstance(strLayout,null,null); 300 if(obj instanceof Layout) { 301 layout=(Layout) obj; 302 Iterator<Entry<String, String>> it = layoutArgs.entrySet().iterator(); 303 Entry<String, String> e; 304 while(it.hasNext()){ 305 e = it.next(); 306 try { 307 Reflector.callSetter(obj, e.getKey(), e.getValue()); 308 } 309 catch (PageException e1) { 310 e1.printStackTrace(); // TODO log 311 } 312 } 313 314 } 315 } 316 } 317 if(layout!=null) return layout; 318 return new ClassicLayout(); 319 } 320 321 //private static LoggerRepository repository=new Hierarchy(null); 322 323 public static Level toLevel(int level) { 324 switch(level){ 325 case Log.LEVEL_FATAL: return Level.FATAL; 326 case Log.LEVEL_ERROR: return Level.ERROR; 327 case Log.LEVEL_WARN: return Level.WARN; 328 case Log.LEVEL_DEBUG: return Level.DEBUG; 329 case Log.LEVEL_INFO: return Level.INFO; 330 case LogUtil.LEVEL_TRACE: return Level.TRACE; 331 } 332 return Level.INFO; 333 } 334 335 public static int toLevel(Level level) { 336 if(Level.FATAL.equals(level)) return Log.LEVEL_FATAL; 337 if(Level.ERROR.equals(level)) return Log.LEVEL_ERROR; 338 if(Level.WARN.equals(level)) return Log.LEVEL_WARN; 339 if(Level.DEBUG.equals(level)) return Log.LEVEL_DEBUG; 340 if(Level.INFO.equals(level)) return Log.LEVEL_INFO; 341 if(Level.TRACE.equals(level)) return LogUtil.LEVEL_TRACE; 342 return Log.LEVEL_INFO; 343 } 344 345 public static Level toLevel(String strLevel, Level defaultValue) { 346 if(strLevel==null) return defaultValue; 347 strLevel=strLevel.toLowerCase().trim(); 348 if(strLevel.startsWith("info")) return Level.INFO; 349 if(strLevel.startsWith("debug")) return Level.DEBUG; 350 if(strLevel.startsWith("warn")) return Level.WARN; 351 if(strLevel.startsWith("error")) return Level.ERROR; 352 if(strLevel.startsWith("fatal")) return Level.FATAL; 353 if(strLevel.startsWith("trace")) return Level.TRACE; 354 return defaultValue; 355 } 356}