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}