It seems that in Grails or better to say Groovy, it is not possible to set the logging pattern to log line numbers, method and class names. Or you can but you would receive the line number and method name from Log4j class like:
%F:%L -≥ SLF4JLog.java:213
I've found an issue related to that which was no considered as Grails related:
http://jira.grails.org/browse/GRAILS-9789
So is there any way how to log these information in Grails?
Please take a look at Grails logging - Is there any existing solution to be able to log the File + Line where the call actually occured?
So, you need to use a custom appender...
Related
I'm working on a Grails 2.3.6 application
Assuming I have multiple users, I want to have for each one a different log file, is it possible to dynamically choose which log file to use at runtime?
You can use the Commons logging api manually. The documentation says you can use something like:
class MyClass {
private static final log = LogFactory.getLog(this)
}
The commons API documentation says you can create a log by String, too, so you could create logs with LogFactory.getLog(userName) and store them somewhere, perhaps in a Map, then retrieve the right one when you need to log, e.g. loggers[userName].info "Client did X"
As described in Can't call one closure from another, I am using a pluggable script from within a Grails app.
Unfortunately, I've found that I can't use log4j from within these scripts. I am forced to use println.
I tried using
import org.apache.commons.logging.LogFactory
def Log log = LogFactory.getLog(getClass())
but I got no output. When I print out the result of the call to getClass(), I get something like
myscript$_run_closure5
So I'm thinking the issue is that there is no configuration in my Grails Config.groovy file for this class.
Is there a way for me to programmatically add these pluggable scripts to the log4j configuration? Keep in mind that I do not know in advance what the names of the scripts are, so this has to happen at runtime.
Consider the following code:
import org.apache.log4j.Logger
// ...
Logger log = Logger.getLogger('MyPlugin')
new File( grailsApplication.config.externalFiles ).eachFile { file ->
Binding binding = new Binding()
binding.variables.log = log
GroovyShell shell = new GroovyShell(binding)
shell.evaluate(file)
strategies.put( binding.variables.key, binding.variables )
}
Explanation:
It is not obligatory to pass class name to getLogger, it can be actually any string. You just need to make sure that this string is matched in log4j.properties of the main program.
You pass once created log to plugin scripts via binding variable "log". Then plugin scripts can access it simply as log.info('test123')
My personal recommendation would be to use logback instead of log4j. Both libraries were developed by the same guy and it is stated that logback supersedes log4j.
I'm using grails.
In some groovy classes declared in the src I want to have extensive log, with many details.
I need to have details like the method name and line number for extensive debug session of a critical component. So I use a pattern like that:
layout:pattern(conversionPattern: '%d{ABSOLUTE} %5p [%c{3}].%M:%L %m %n')
But whatever the way I declare my loggers (#Commons or #Slf4j on top of the class, or direct use a LogFactory), I only end up with some garbage info about the current method/line number.
With #Log4j annotation I got lines like:
date DEBUG [my.package.MyClass].call:? my message
With #Commons:
date DEBUG [my.package.MyClass].debug:128 my debug message
date INFO [my.package.MyClass].info:128 my info
where the line number is coming from the logger itself
At the same time hibernate logs are formatted the right way and give me meaningful output:
11:12:11,767 TRACE [descriptor.sql.BasicExtractor].extract:71 found [62364] as column [TL5_4_0_]
where extract:71 is really where the log occured.
So grails (or groovy) is messing around the logging pattern and I'm looking for a way to get the info I need on my logs lines.
How can I fix that?
As per http://docs.codehaus.org/display/GROOVY/Groovy+1.8+release+notes#Groovy18releasenotes-Log groovy does surround log statements with checks like isDebugEnabled() etc.
Does grails do that for the generated code?
For this log call in a grails service:
log.debug("competitors errors stage 1: ${failedCarrierRequests}")
In the decompiled .class file I see only this:
arrayOfCallSite[85].call(log, new GStringImpl(new Object[] { allCompetitorDepartmentsRows.get() }, new String[] { "All competitors: ", "" }));
It is unclear whether there is a check for log level behind the scenes or not.
As of 2.2.2: no.
Grails injects an apache commons Log field into the artefact classes, and the log4j plugin marries that to a log4j Logger.
However, in your example you pass a GString as the only parameter. Since they are lazy-transformed to Java Strings, the log4j logger would hit it's own internal debug enabled check and skip the toString() call.
If you do something expensive like parameter building, however, and you're concerned about the wasted cycles, you must call isDebugEnabled() yourself:
if (log.isDebugEnabled()) {
log.debug("Some string concatenation with a slow method: " + slowMethod())
}
I should point out that this contrived example could be converted to use GString to save the debug check:
log.debug "GString with lazily initialized slow method call: ${slowMethod()}"
There was some discussion awhile back on the grails-user mailing list about adding an AST transformation to add the checks, but it didn't go anywhere.
Okay response that GStrings are lazy loaded doesn't seems to hold up against my testing.
I have created a test to basically log something four different ways, and it does appear to evaluate any logging statement GString.
Here is my test file GIST: https://gist.github.com/tgsoverly/34f9a56287291297777b
The test fails for the GString and the method IS called when in the log statement.
It would also not be something the groovy people say should be the case according to their template section: http://groovy.codehaus.org/Strings+and+GString
I am trying to use codeNarc on a grails project, after installing it and running it I've have some rulesets violations messages that I would like to understand and resolve. The first on concern "GrailsStatelessService" and the second the "equals() and toString()" methods...
For the first one "GrailsStatelessService" the message I received is:
***************************
Violation in class app.TheServiceName. The class is marked as stateless but contains the non-final field 'aVariableName'
***************************
I've searched a little about that but not found a lot of tricks about that. Can someone please explain me what the real meaning of this ruleset and what I have to do to solve this problem/
About the second kind of ruleSet I found somewhere that it solved by overriding those methods in all the domain classes but is hat an obligation, a need, or do I just have to modify the ruleSet File to avoid those kinds of messages related to those rulesets?
And that introduces my last question: where to find this ruleSet File( the default one within codenarc) or the one i must include myself?
I find that the GrailsStatelessService rule does sometimes catch a real violation, so rather than disabling it, I modify it to ignore my commonly used field names.
BuildConfig.groovy:
codenarc.propertiesFile = 'grails-app/conf/codenarc.properties'
codenarc.properties:
GrailsStatelessService.addToIgnoreFieldNames=grailsApplication,applicationContext,sessionFactory
I am able to configure this CodeNarc rules as follows:
Install CodeNarc plugin [grails install-plugin codenarc]
Add following line in BuildConfig.groovy file [for details configuration]:
codenarc.propertiesFile = 'grails-app/conf/codenarc.properties'
In codenarc.properties - file, I add following rule for ignore few RULEs
codenarc.properties = {
GrailsDomainHasEquals.enabled = false
GrailsDomainHasToString.enabled = false
EmptyMethod.enabled = false
}
Run following command for generating CodeNarc Report: grails codenarc
Sometimes condenarc mix things ups. Adding Service at the end of the name of the service remove this "issue" if you are not using a class as stateless but codenarc believes so. I had this problem with this Service:
private CurrencyConverterFactory currencyConverterFactory
And I fixed with:
private CurrencyConverterFactory currencyConverterFactoryService
I hope this helps someone.
The documentation does a good job of explaining that rule:
Checks for non-final fields on a Grails service class. Grails service
classes are singletons by default, and so they should be reentrant. In
most cases, this implies (or at least encourages) that they should be
stateless.
This rule ignores final fields (either instance or static). Fields
that are static and non-final, however, do cause a violation.
If you are using the Grails CodeNarc plugin, then see the plugin documentation for a list of the CodeNarc rulesets that are included by default. There is also a section on "Configuring The CodeNarc RuleSet File(s)" -- so by all means create your own custom ruleset.
http://www.grails.org/plugin/codenarc/
It is expected that you customize the set of rules appropriate for your team/project. Other than the "basic" rulset, the other provided rulesets all contain rules that may or may not be appropriate for you.
The GrailsDomainHasToString and GrailsDomainHasEquals rules are perfect examples -- many organizations disable those rules.
See the CodeNarc documentation for more information on turning off a rule:
http://codenarc.sourceforge.net/codenarc-configuring-rules.html