001 /*
002 * Copyright 2004-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.codehaus.griffon.runtime.logging
017
018 import griffon.util.Environment
019 import griffon.util.Metadata
020 import org.apache.log4j.helpers.LogLog
021 import org.apache.log4j.varia.NullAppender
022 import org.apache.log4j.xml.XMLLayout
023 import org.codehaus.groovy.runtime.InvokerHelper
024 import org.apache.log4j.*
025
026 /**
027 * Encapsulates the configuration of Log4j.
028 *
029 * @author Graeme Rocher (Grails 1.1)
030 * @since 0.9.2
031 */
032 class Log4jConfig {
033 static final DEFAULT_PATTERN_LAYOUT = new PatternLayout(
034 conversionPattern: '%d [%t] %-5p %c{2} %x - %m%n')
035
036 static final LAYOUTS = [xml: XMLLayout, html: HTMLLayout, simple: SimpleLayout, pattern: PatternLayout]
037 static final APPENDERS = ["null": NullAppender, console: ConsoleAppender,
038 file: FileAppender, rollingFile: RollingFileAppender,
039 event: GriffonApplicationEventAppender]
040
041 private appenders = [:]
042
043 def methodMissing(String name, args) {
044 if (APPENDERS.containsKey(name) && args) {
045 def constructorArgs = args[0] instanceof Map ? args[0] : [:]
046 if (!constructorArgs.layout) {
047 constructorArgs.layout = DEFAULT_PATTERN_LAYOUT
048 }
049 def appender = APPENDERS[name].newInstance()
050 InvokerHelper.setProperties appender, constructorArgs
051 if (appender.name) {
052 appenders[appender.name] = appender
053 } else {
054 LogLog.error "Appender of type $name doesn't define a name attribute, and hence is ignored."
055 }
056 appender.activateOptions()
057 return appenders[name]
058 }
059
060 if (LAYOUTS.containsKey(name) && args) {
061 return LAYOUTS[name].newInstance(args[0])
062 }
063
064 if (isCustomEnvironmentMethod(name, args)) {
065 return invokeCallable(args[0])
066 }
067
068 LogLog.error "Method missing when configuring log4j: $name"
069 }
070
071 private boolean isCustomEnvironmentMethod(String name, args) {
072 Environment.current == Environment.CUSTOM &&
073 Environment.current.name == name &&
074 args && (args[0] instanceof Closure)
075 }
076
077 def environments(Closure callable) {
078 invokeCallable(callable)
079 }
080
081 private invokeCallable(Closure callable) {
082 callable.delegate = this
083 callable.resolveStrategy = Closure.DELEGATE_FIRST
084 callable.call()
085 }
086
087 def development(Closure callable) {
088 if (Environment.current == Environment.DEVELOPMENT) {
089 invokeCallable(callable)
090 }
091 }
092
093 def production(Closure callable) {
094 if (Environment.current == Environment.PRODUCTION) {
095 invokeCallable(callable)
096 }
097 }
098
099 def test(Closure callable) {
100 if (Environment.current == Environment.TEST) {
101 invokeCallable(callable)
102 }
103 }
104
105 def configure(Closure callable = {}) {
106
107 Logger root = Logger.getRootLogger()
108
109 callable.delegate = this
110 callable.resolveStrategy = Closure.DELEGATE_FIRST
111
112 try {
113 callable.call(root)
114 for (appender in appenders.values()) root.addAppender appender
115
116 if (!root.allAppenders.hasMoreElements()) {
117 def consoleAppender = createConsoleAppender()
118 root.setLevel Level.ERROR
119 appenders['stdout'] = consoleAppender
120
121 error 'org.codehaus.griffon'
122
123 root.addAppender appenders['stdout']
124 }
125 /*
126 Logger logger = Logger.getLogger("StackTrace")
127 logger.additivity = false
128 def fileAppender = createFullstackTraceAppender()
129 if (!logger.allAppenders.hasMoreElements()) {
130 logger.addAppender fileAppender
131 }
132 */
133 }
134 catch (Exception e) {
135 LogLog.error "WARNING: Exception occured configuring log4j logging: $e.message"
136 }
137 }
138
139 private createConsoleAppender() {
140 def consoleAppender = new ConsoleAppender(layout: DEFAULT_PATTERN_LAYOUT, name: "stdout")
141 consoleAppender.activateOptions()
142 appenders.console = consoleAppender
143 return consoleAppender
144 }
145
146 private createFullstackTraceAppender() {
147 if (appenders.stacktrace) {
148 return appenders.stacktrace
149 }
150
151 def fileAppender = new FileAppender(layout: DEFAULT_PATTERN_LAYOUT, name: "stacktraceLog")
152 if (Environment.current == Environment.DEVELOPMENT) {
153 def targetDir = Metadata.current.getGriffonWorkingDir()
154 if (targetDir) targetDir.mkdirs()
155 fileAppender.file = targetDir ? "${targetDir.absolutePath}/stacktrace.log" : "stacktrace.log"
156 }
157 else {
158 fileAppender.file = "stacktrace.log"
159 }
160 fileAppender.activateOptions()
161 appenders.stacktrace = fileAppender
162 return fileAppender
163 }
164
165 Logger root(Closure c) {
166 def root = Logger.getRootLogger()
167
168 if (c) {
169 c.delegate = new RootLog4jConfig(root, this)
170 c.resolveStrategy = Closure.DELEGATE_FIRST
171 c.call()
172 }
173
174 return root
175 }
176
177 def appenders(Closure callable) {
178 callable.delegate = this
179 callable.resolveStrategy = Closure.DELEGATE_FIRST
180 callable.call()
181 }
182
183 def appender(Map name, Appender instance) {
184 if (name && instance) {
185 String appenderName = name.values().iterator().next()
186 instance.name = appenderName
187 appenders[appenderName] = instance
188 instance.activateOptions()
189 }
190 }
191
192 def appender(Appender instance) {
193 if (instance && instance.name) {
194 appenders[instance.name] = instance
195 instance.activateOptions()
196 }
197 else {
198 LogLog.error "Appender [$instance] is null or does not define a name."
199 }
200 }
201
202 def off(Map appenderAndPackages) {
203 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.OFF)
204 }
205
206 def fatal(Map appenderAndPackages) {
207 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.FATAL)
208 }
209
210 def error(Map appenderAndPackages) {
211 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.ERROR)
212 }
213
214 def warn(Map appenderAndPackages) {
215 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.WARN)
216 }
217
218 def info(Map appenderAndPackages) {
219 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.INFO)
220 }
221
222 def debug(Map appenderAndPackages) {
223 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.DEBUG)
224 }
225
226 def trace(Map appenderAndPackages) {
227 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.TRACE)
228 }
229
230 def all(Map appenderAndPackages) {
231 setLogLevelForAppenderToPackageMap(appenderAndPackages, Level.ALL)
232 }
233
234 private setLogLevelForAppenderToPackageMap(appenderAndPackages, Level level) {
235
236 def additivity = appenderAndPackages.additivity != null ? appenderAndPackages.remove('additivity') : true
237
238 appenderAndPackages?.each { appender, packages ->
239 eachLogger(packages) { Logger logger ->
240 logger.level = level
241 if (appenders[appender]) {
242 logger.addAppender appenders[appender]
243 logger.additivity = additivity
244 }
245 else {
246 LogLog.error "Appender $appender not found configuring logger ${logger.getName()}"
247 }
248 }
249 }
250 }
251
252 def eachLogger(packages, Closure callable) {
253 if (packages instanceof String || packages instanceof GString) {
254 Logger logger = Logger.getLogger(packages)
255 callable(logger)
256 }
257 else {
258 for (p in packages) {
259 p = p?.toString()
260 if (p) {
261 Logger logger = Logger.getLogger(p)
262 callable(logger)
263 }
264 }
265 }
266 }
267
268 def off(Object[] packages) {
269 eachLogger(packages) { logger -> logger.level = Level.OFF }
270 }
271
272 def fatal(Object[] packages) {
273 eachLogger(packages) { logger -> logger.level = Level.FATAL }
274 }
275
276 def error(Object[] packages) {
277 eachLogger(packages) { logger -> logger.level = Level.ERROR }
278 }
279
280 def warn(Object[] packages) {
281 eachLogger(packages) { logger -> logger.level = Level.WARN }
282 }
283
284 def info(Object[] packages) {
285 eachLogger(packages) { logger -> logger.level = Level.INFO }
286 }
287
288 def debug(Object[] packages) {
289 eachLogger(packages) { Logger logger -> logger.level = Level.DEBUG }
290 }
291
292 def trace(Object[] packages) {
293 eachLogger(packages) { logger -> logger.level = Level.TRACE }
294 }
295
296 def all(Object[] packages) {
297 eachLogger(packages) { logger -> logger.level = Level.ALL }
298 }
299
300 def removeAppender(String name) {
301 Logger.getRootLogger().removeAppender name
302 }
303 }
304
305 class RootLog4jConfig {
306 Logger root
307 Log4jConfig config
308
309 def RootLog4jConfig(root, config) {
310 this.root = root
311 this.config = config
312 }
313
314 def debug(Object[] appenders = null) {
315 setLevelAndAppender(Level.DEBUG, appenders)
316 }
317
318 private setLevelAndAppender(Level level, Object[] appenders) {
319 root.level = level
320 for (appName in appenders) {
321 Appender app
322 if (appName instanceof Appender) {
323 app = appName
324 } else {
325 app = config.appenders[appName?.toString()]
326 }
327 if (app) {
328 root.addAppender app
329 }
330 }
331 }
332
333 def info(Object[] appenders = null) {
334 setLevelAndAppender(Level.INFO, appenders)
335 }
336
337 def warn(Object[] appenders = null) {
338 setLevelAndAppender(Level.WARN, appenders)
339 }
340
341 def trace(Object[] appenders = null) {
342 setLevelAndAppender(Level.TRACE, appenders)
343 }
344
345 def all(Object[] appenders = null) {
346 setLevelAndAppender(Level.ALL, appenders)
347 }
348
349 def error(Object[] appenders = null) {
350 setLevelAndAppender(Level.ERROR, appenders)
351 }
352
353 def fatal(Object[] appenders = null) {
354 setLevelAndAppender(Level.FATAL, appenders)
355 }
356
357 def off(Object[] appenders = null) {
358 setLevelAndAppender(Level.OFF, appenders)
359 }
360
361 void setProperty(String s, Object o) {
362 root."$s" = o
363 }
364 }
|