grails only my log - grails

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
}

Related

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

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.

Why does stacktrace.log not fill with logback in grails 3?

When you create a new grails application, the default logback.groovy file (and almost every example of a logback.groovy, even Mr Haki's example) contains the following code, which I have simplified to focus on the relevant piece:
root(ERROR, ['STDOUT'])
appender("FULL_STACKTRACE", FileAppender) {
file = "build/stacktrace.log"
append = true
encoder(PatternLayoutEncoder) {
pattern = "%level %logger - %msg%n"
}
}
logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false )
However, following this approach does not result in errors being output to the stacktrace.log file.
#JeffScottBrown's answer contained the following Bootstrap.groovy file to test if the stacktrace was logging as expected:
class BootStrap {
def init = { servletContext ->
log.error 'this is a new error'
}
def destroy = {
}
}
With that bootstrap file, running the grails application will not produce any output into build/stacktrace.log.
If you remove the StackTrace logger, and add FULL_STACKTRACE to the root logger:
root(ERROR, ['STDOUT', 'FULL_STACKTRACE']
you will get output into the stacktrace.log.
Alternatively, rename the StackTrace logger to grails.app.init.Bootstrap (thanks to #JeffScottBrown for this line):
logger 'grails.app.init.BootStrap', ERROR, ['FULL_STACKTRACE'], false
and you will get output into the stacktrace.log
This observation leads me to believe that the StackTrace logger doesn't do anything. I further am led to believe that any logger not named for a package doesn't work.
As a result of all this, my question is:
Does logback work for non-package/class named loggers?
If so, why does the StackTrace logger in the default logback.groovy not result in output to stacktrace.log?
EDIT:
The main issue for me is that the StackTrace logger seems completely unnecessary, so why is it included in the default file?
Second Edit:
Another way to confirm this is to make only the StackTrace logger write to the STDOUT appender, and watch stacktraces disappear from the console when you throw an exception:
logger("StackTrace", ERROR, ['STDOUT','FULL_STACKTRACE'], false)
root(ERROR, [])
I expect that you aren't configuring the appender to be used properly.
The following works:
import grails.util.BuildSettings
import grails.util.Environment
// See http://logback.qos.ch/manual/groovy.html for details on configuration
appender('STDOUT', ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = "%level %logger - %msg%n"
}
}
root(ERROR, ['STDOUT'])
def targetDir = BuildSettings.TARGET_DIR
if (Environment.isDevelopmentMode() && targetDir) {
appender("FULL_STACKTRACE", FileAppender) {
file = "${targetDir}/stacktrace.log"
append = true
encoder(PatternLayoutEncoder) {
pattern = "%level %logger - %msg%n"
}
}
logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false)
}
logger 'grails.app.init.BootStrap',
ERROR, ['FULL_STACKTRACE'], false
In BootStrap.groovy...
class BootStrap {
def init = { servletContext ->
log.error 'this is a new error'
}
def destroy = {
}
}
That error shows up in stacktrace.log.
EDIT To Address New Questions:
Does logback work for non-package/class named loggers?
Yes.
If so, why does the StackTrace logger in the default logback.groovy
not result in output to stacktrace.log?
The StackTrace logger does result in output being written to stacktrace.log for all of the loggers associated with the corresponding appender.
change
logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false )
to
logger("grails.app", INFO, ['FULL_STACKTRACE'], false)
will write all the logs in grails-app to stacktrace.log
Your log statement in Bootstrap.groovy:
log.error 'this is a new error'
logs a regular ERROR level message to the logger named grails.app.init.yourapp.BootStrap. It does not log to the logger named StackTrace.
The FULL_STACKTRACE appender is for unfiltered stacktraces. These are written by the framework to the logger StackTrace.
If you replace
log.error 'this is a new error'
with
throw new RuntimeException("foo")
you will see the full stacktrace being logged to stacktrace.log
As a result of all this, my question is:
Does logback work for non-package/class named loggers?
Yes, logback works regardless of the logger name.
If so, why does the StackTrace logger in the default logback.groovy not result in output to stacktrace.log?
It does. I cannot reproduce the scenario where it doesn't. If you can, please file an issue at https://github.com/grails/grails-core/issues and include a sample app and we will get it straightened out.
Sorry for the trouble and thank you for the feedback.

Grails - How to add log pattern to file appender

I am implementing logging to my application, I am trying to add a pattern to my log file appender,
My code is like this:
log4j = {
appenders {
// append new appenders of your own and add log level and packages/files like to add.
rollingFile name: "myAppender",
maxFileSize: 1024,
file: "C:/GrailsWS/BaseGrails/target/basegrails.log"//""basegrails.log" // C:\GrailsWS\BaseGrails\target\basegrails.log
console name: "myAppender",
layout: pattern(conversionPattern: "%c{2} %m%n")
}
I am following Grails Logging page, After adding pattern line, my basegrails.log not getting any log data.
You don't want to have appenders of the same name. I believe what you want to do is give your appenders different names and then apply conversion patterns as needed. If you want, you can define a variable with a common pattern. So, something like:
log4j = {
def commonPattern = "%c{2} %m%n"
appenders {
// append new appenders of your own and add log level and packages/files like to add.
rollingFile name: "rollingLog",
maxFileSize: 1024,
file: "C:/GrailsWS/BaseGrails/target/basegrails.log",
layout: pattern(conversionPattern: commonPattern)
console name: "stdout",
layout: pattern(conversionPattern: commonPattern )
}
// then, use your appenders
trace stdout ['grails.app', ...]
debug rollingFile: ['your.package', ...]
}

Why is Config.groovy variable not defined in plugin's config?

I have a Grails app (myapp) that uses a custom plugin (grails-fizz). In myapp's Config.groovy I have the following var defined:
logfile = "/opt/myapp/logs/myapp.log"
I then pull in grails-fizz as a plugin inside the app's BuildConfig.groovy file. In grails-fizz's FizzGrailsPlugin.groovy, I try to use that value:
def doWithApplicationContext = { ctx ->
println("The logfile is ${logfile}.")
}
When this runs I get the following error:
Error initializing the application: No such property: logfile for class: FizzGrailsPlugin
It seems that the plugin doesn't have scope/visibility over this var? What's the solution?
You can access configuration values through the configuration object.
def doWithApplicationContext = { ctx ->
def config = ctx.config
println println "The logfile is ${config.logfile}."
}
From the documentation
Every plugin has an implicit application variable which is an instance of the GrailsApplication interface.
So you can use application.config to access the configuration.

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.

Resources