How to add Console appenders(which has pattern layout) to Root Logger programtically - log4j2

I need to add a console appender with pattern layout to Root Logger programtically.My previous code with log4j1.x has something like Logger.getLogger(new Appender(console,fname,patternlayout,"Specific pattern")
How to convert this one to log4j 2.3.2

Log4j 2.3.2 is an old version and lacks many new features like the ConfigurationBuilder API.
However you can build your console appender and attach directly to the root logger through:
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Logger logger = ctx.getLogger(LogManager.ROOT_LOGGER_NAME);
final Layout<String> layout = PatternLayout.newBuilder()
.withConfiguration(ctx.getConfiguration())
.withPattern("some pattern")
.build();
final Appender appender = ConsoleAppender.newBuilder()
.setName("some name")
.setLayout(layout)
.build();
/*
* This is simpler, but it is not API:
*
* logger.addAppender(appender);
*
* Instead we shoud use:
*/
ctx.getConfiguration().addLoggerAppender(logger, appender);
Remark: this is a temporary patch of the current configuration. If the configuration is reloaded (e.g. the log4j2.xml file changes), the modifications will be lost.

Related

Copying default external configuration on first run of Grails web app

In our Grails web applications, we'd like to use external configuration files so that we can change the configuration without releasing a new version. We'd also like these files to be outside of the application directory so that they stay unchanged during continuous integration.
The last thing we need to do is to make sure the external configuration files exist. If they don't, then we'd like to create them, fill them with predefined content (production environment defaults) and then use them as if they existed before. This allows any administrator to change settings of the application without detailed knowledge of the options actually available.
For this purpose, there's a couple of files within web-app/WEB-INF/conf ready to be copied to the external configuration location upon the first run of the application.
So far so good. But we need to do this before the application is initialized so that production-related modifications to data sources definitions are taken into account.
I can do the copy-and-load operation inside the Config.groovy file, but I don't know the absolute location of the WEB-INF/conf directory at the moment.
How can I get the location during this early phase of initialization? Is there any other solution to the problem?
There is a best practice for this.
In general, never write to the folder where the application is deployed. You have no control over it. The next rollout will remove everything you wrote there.
Instead, leverage the builtin configuration capabilities the real pro's use (Spring and/or JPA).
JNDI is the norm for looking up resources like databases, files and URL's.
Operations will have to configure JNDI, but they appreciate the attention.
They also need an initial set of configuration files, and be prepared to make changes at times as required by the development team.
As always, all configuration files should be in your source code repo.
I finally managed to solve this myself by using the Java's ability to locate resources placed on the classpath.
I took the .groovy files later to be copied outside, placed them into the grails-app/conf directory (which is on the classpath) and appended a suffix to their name so that they wouldn't get compiled upon packaging the application. So now I have *Config.groovy files containing configuration defaults (for all environments) and *Config.groovy.production files containing defaults for production environment (overriding the precompiled defaults).
Now - Config.groovy starts like this:
grails.config.defaults.locations = [ EmailConfig, AccessConfig, LogConfig, SecurityConfig ]
environments {
production {
grails.config.locations = ConfigUtils.getExternalConfigFiles(
'.production',
"${userHome}${File.separator}.config${File.separator}${appName}",
'AccessConfig.groovy',
'Config.groovy',
'DataSource.groovy',
'EmailConfig.groovy',
'LogConfig.groovy',
'SecurityConfig.groovy'
)
}
}
Then the ConfigUtils class:
public class ConfigUtils {
// Log4j may not be initialized yet
private static final Logger LOG = Logger.getGlobal()
public static def getExternalConfigFiles(final String defaultSuffix, final String externalConfigFilesLocation, final String... externalConfigFiles) {
final def externalConfigFilesDir = new File(externalConfigFilesLocation)
LOG.info "Loading configuration from ${externalConfigFilesDir}"
if (!externalConfigFilesDir.exists()) {
LOG.warning "${externalConfigFilesDir} not found. Creating..."
try {
externalConfigFilesDir.mkdirs()
} catch (e) {
LOG.severe "Failed to create external configuration storage. Default configuration will be used."
e.printStackTrace()
return []
}
}
final def cl = ConfigUtils.class.getClassLoader()
def result = []
externalConfigFiles.each {
final def file = new File(externalConfigFilesDir, it)
if (file.exists()) {
result << file.toURI().toURL()
return
}
final def error = false
final def defaultFileURL = cl.getResource(it + defaultSuffix)
final def defaultFile
if (defaultFileURL) {
defaultFile = new File(defaultFileURL.toURI())
error = !defaultFile.exists();
} else {
error = true
}
if (error) {
LOG.severe "Neither of ${file} or ${defaultFile} exists. Skipping..."
return
}
LOG.warning "${file} does not exist. Copying ${defaultFile} -> ${file}..."
try {
FileUtils.copyFile(defaultFile, file)
} catch (e) {
LOG.severe "Couldn't copy ${defaultFile} -> ${file}. Skipping..."
e.printStackTrace()
return
}
result << file.toURI().toURL()
}
return result
}
}

log4 properties injection in grails Config.groovy

I would like to inject log4j config stuff stored in a properties file in my Config.groovy.
Here is my properties file :
log.file=path/to/my/log
log.root.level=info
log.grails.app.level=info
No problem for file path EL syntax ${} but it doesn't work for levels as it is not strings. Here is the config.groovy :
appenders {
file name:'file', file:"${config.log.file}"
}
root {
${log.root.level} 'stdout', 'file'
}
Any advise ?
You have to read the properties file and convert it to a ConfigObject to use in Config.groovy.
log4j {
def props = new Properties()
new File("path/to/log.properties").withReader{
props.load(it)
}
def slurp = new ConfigSlurper().parse(props)
appenders {
file name:'file', file:"$slurp.log.file"
}
root {
"$slurp.log.root.level" 'stdout', 'file'
}
}
Refer this similar question.
If I'm reading the code of the Grails Log4J DSL parser correctly you should just be able to say
root {
"${config.config.log.root.level}" 'stdout', 'file'
}
or if that doesn't work then
root {
delegate."${config.config.log.root.level}" 'stdout', 'file'
}
Normally, within the log4j closure you have access to the complete grailsApplication.config (including options merged in from external configuration files) as the variable config but it looks like you need a second config in front of that when you're inside the root {} block.
Explanation - the closure delegate of the root closure is a RootLog4jConfig object, which has a property config pointing to the main Log4jConfig which is the delegate for the rest of the log4j closure, and that in turn has its own property config pointing to the parsed ConfigObject. I somehow doubt that this behaviour is deliberate, and it might be worth a JIRA to suggest that config should resolve to the same thing inside the root block as outside it.

grails only my log

in my Config.groovy I have log4j configuration :
log4j = {
appenders {
file name:'connection', file: '/tmp/connection.log'
}
info "grails.app.controllers.myController"
root {
info 'connection'
}
how I can configure for getting only myController logs?
how I can configure for getting only myController logs?
You are currently setting the root logger to "info" level, thus the
info "grails.app.controllers.myController"
doesn't actually do anything (as this logger would inherit a level of info from the root anyway). If you want to disable all logging apart from that from myController then you need to set the root logger to "off" rather then info
root {
off 'connection'
}
If instead you want to put myController output into /tmp/connection.log and leave the other log messages on stdout as normal then you need
root {
info 'stdout'
}
info connection:'grails.app.controllers.myController', additivity:false
(or just leave out the root block entirely to get the default behaviour, which is the equivalent of saying root { error "stdout" }). The additivity:false tells the myController logger to log only to the appenders attached directly to it (your "connection" appender). Without this the messages would also go to the appenders inherited from the parent, i.e. the default "stdout" appender.
you should define appender specific loggers, e.g.
info connection: "grails.app.controllers.myController"
next you should remove your "connection" appender from the root block to avoid root logger inheritance.
for further information see the logging section in the grails documentation: http://grails.org/doc/latest/guide/conf.html#logging
try something like that:
log4j = {
def loggerPattern = '%d %-5p >> %m%n'
def errorClasses = [] // add more classes if needed
def infoClasses = ['grails.app.controllers.myController'] // add more classes if needed
def debugClasses = [] // add more classes if needed
appenders {
console name:'stdout', layout:pattern(conversionPattern: loggerPattern)
rollingFile name: "file", maxFileSize: 1024, file: "./tmp/logs/logger.log", layout:pattern(conversionPattern: loggerPattern)
}
error stdout: errorClasses, file: errorClasses
info stdout: infoClasses, file: infoClasses
debug stdout: debugClasses, file: debugClasses
}

How to update external config files without rebuilding war file in Grails

How to update external config files (e.g.: config-ex.groovy, config-ex.properties) without rebuilding the war file in Grails?
Restarting the application server will apply the new updates from external config files.
If I understand well you want to externalized Grails config outside the war.
You can define an external config in your config.groovy like this
grails.config.locations = ["file:path/to/your/Configfile.groovy"]
See the Grails doc 4.4 Externalized Configuration
Define your external Grails config with:
grails.config.locations = ["file:some/path/to/Config.groovy"]
Then to reload them at runtime, you can use code like this:
def config = grailsApplication.config
def locations = config.grails.config.locations
locations.each {
String configFileName = it.split('file:')[0]
config.merge(new ConfigSlurper().parse(new File(configFileName).text))
}
I have the above code in an admin protected Controller.
Went around the houses for this one, thanks Gregg
For services or groovy src files you could use:
import org.springframework.context.ApplicationContext
ApplicationContext ctx = (ApplicationContext) org.codehaus.groovy.grails.web.context.ServletContextHolder.getServletContext().getAttribute(org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes.APPLICATION_CONTEXT);
def grailsApplication = ctx.getBean("grailsApplication")
ConfigObject config = ctx.getBean(GrailsApplication).config
def locations = config.grails.config.locations
locations.each {
String configFileName = it.split("file:")[1]
config.merge(new ConfigSlurper().parse(new File(configFileName).text))
}
And for abstract classes that are typically extended from controllers:
import grails.util.Holders
def config = Holders.config
def locations = config.grails.config.locations
locations.each {
String configFileName = it.split("file:")[1]
config.merge(new ConfigSlurper().parse(new File(configFileName).text))
}

Configuration of Grails plugin

I'm developing my first Grails plugin. It has to access a webservice. The Plugin will obviously need the webservice url. What is the best way to configure this without hardcoding it into the Groovy classes? It would be nice with different config for different environments.
You might want to Keep It Simple(tm). You may define the URL directly in Config.groovy -including per-environment settings- and access it from your plugin as needed using grailsApplication.config (in most cases) or a ConfigurationHolder.config object (See further details in the manual).
As an added bonus that setting may also be defined in standard Java property files or on other configuration files specified in grails.config.locations.
e.g. in Config.groovy
// This will be the default value...
myPlugin.url=http://somewhe.re/test/endpoint
environments {
production {
// ...except when running in production mode
myPlugin.url=http://somewhe.re/for-real/endpoint
}
}
later, in a service provided by your plugin
import org.codehaus.groovy.grails.commons.ConfigurationHolder
class MyPluginService {
def url = ConfigurationHolder.config.myPlugin.url
// ...
}
If its only a small (read: one item) config option, it might just be easier to slurp in a properties file. If there are some number of configuration options, and some of them should be dynamic, i would suggest doing what the Acegi Security plugin does - add a file to /grails-app/conf/plugin_name_config.groovy perhaps.
added bonus is that the user can execute groovy code to compute their configuration options (much better over using properties files), as well as being able to do different environments with ease.
check out http://groovy.codehaus.org/ConfigSlurper , which is what grails internally use to slurp configs like config.groovy.
//e.g. in /grails-app/conf/MyWebServicePluginConfig.groovy
somePluginName {
production {
property1 = "some string"
}
test {
property1 = "another"
}
}
//in your myWebServicePlugin.groovy file, perhaps in the doWithSpring closure
GroovyClassLoader classLoader = new GroovyClassLoader(getClass().getClassLoader())
ConfigObject config
try {
config = new ConfigSlurper().parse(classLoader.loadClass('MyWebServicePluginConfig'))
} catch (Exception e) {/*??handle or what? use default here?*/}
assert config.test.property1.equals("another") == true

Resources