[logback-dev] Concerning Logback's Groovy Configuration API
Добрынин Дмитрий
dobrynya at inbox.ru
Tue Jun 29 17:15:45 CEST 2010
Hi all
I've read the documentation on Logback's Groovy Configuration API and found that API is not concise and convenient as it can be. I would like to explain my thoughts.
1) There is no need to use string literals to identify appenders. Configuring an appender in a closure mainly takes several lines of code, a better idea is to use groovy map literal to specify appender's parameters.
For example:
appender myAppender, [class: FileAppender, file: "myComponent.log", append: true, encoder: encoder(class: PatternEncoder, pattern: "%m%n" ]
appender myConsole // configuring an appender with default settings such as ConsoleAppender etc
// or excluding square brackets, but name of the appender is specified right in the parameter's map
appender name: myAppender, class: FileAppender, file: "myComponent.log", append: true, encoder: patternEncoder("%m%n")
// here convenient method patternEncoder is used to avoid specifying the encoder's class
2) Loggers can refer appenders by name, no need to use strings. There is no need to use list literal to specify a collection of appenders, just using varargs.
logger com.myorg.myapp.mypackage, INFO, myAppender
logger com.myorg.myapp.mypackage.subpackage, DEBUG, false, myAppender, myConsole
In the last statement also additivity flag is specified.
logger root, INFO, myApp // configuring the root logger is achieved with the same API
In my opinion this DSL is looking more naturally and clearer. All statements take one line. If convenient functions for creating encoders and other components is provided it would be easy-to-use configuration API. In the rest of this letter I've added sample code to show how it can be implemented. Hope this is useful.
Best regards,
Dmitry
Here is logging configuration in method config.
package org.logger
import org.junit.Test
import org.apache.log4j.*
import static org.apache.log4j.Level.*
/**
* Configuration API
* @author Dmitry Dobrynin
* Created 28.06.2010 16:35:45
*/
class GrTest {
Map<String, Logger> loggers = [:]
Map<String, Appender> appenders = [:]
@Before
void config() {
appender myApp, [class: FileAppender, file: "myLog.log", encoder: encoder()]
appender oneMoreAppender
logger root, INFO, myApp
logger org.nomin, DEBUG, false, myApp, oneMoreAppender
}
@Test
void test() {
getLogger(org.logger).info "Loggers work! "
getLogger(GrTest).info "Found logger by class!"
getLogger(List).info "Found logger by class!"
}
def propertyMissing(String name) {
appenders[name] ?: loggers[name] ?: new Name(name: name, config: this)
}
def encoder(params = null) {}
Logger getLogger(loggerName) {
switch (loggerName) {
case String: return loggers[loggerName]
case Name: return loggers[loggerName.toString()]
default: throw new Exception("Undefined logger ${loggerName}!"
}
}
Logger getLogger(Class clazz) { loggers.find { clazz.name.startsWith(it.key) }?.value ?: loggers["root"] }
Logger logger(Name name, Level level, boolean additivity = true, Appender... appenders) {
loggers[name.toString()] = new Logger(additivity: additivity, appenders: appenders.collect { it })
}
Appender appender(Name name, Map params = [:]) {
appenders[name.toString()] = new Appender(name: name.toString(), appenderClass: params.class ?: ConsoleAppender)
}
static class Logger {
def name
def additivity = true
def appenders = []
void info(message) { appenders.each { it.append("${name}: ${message}" }}
}
static class Appender {
String name
Class appenderClass
void append(message) { println("${name}:${appenderClass?.name}: ${message}" }
}
}
class Name {
String name
Name prev
def config
def propertyMissing(String name) { new Name(name: name, prev: this) }
String toString() { prev ? "${prev.toString()}.${name}" : name }
}
More information about the logback-dev
mailing list