I use grails 3.0.2 and logback. How can I use this logger in my code, can I somehow autoinject it, like log.debug() in grails 2.x which was using org.apache.commons.logging.Log?
add the #Slf4j annotation on your class.
This local transform adds a logging ability to your program using
LogBack logging. Every method call on a unbound variable named log
will be mapped to a call to the logger. For this a log field will be
inserted in the class. If the field already exists the usage of this transform
will cause a compilation error. The method name will be used to determine
what to call on the logger.
log.name(exp)
is mapped to
if (log.isNameLoggable() {
log.name(exp)
}
Here name is a place holder for info, debug, warning, error, etc.
If the expression exp is a constant or only a variable access the method call will
not be transformed. But this will still cause a call on the injected logger.
Related
I am having a grails application where I get a log variable in controller and service folders implicitly. However, I have my own logger that I want to use across the application. How can I override that grails implicit log variable?
How can I override that grails implicit log variable?
If you omit the org.grails:grails-logging plugin, the default provided logger won't be introduced. At that point you could define your own log property and do what you want with it. If you want to automatically add your own log property to all of your controllers and services you could do that a number of ways. One would be to write an AST transformation. Another would be to write a trait that provides your logger property and then have your classes implement that trait, either explicitly, or by way of #Enhances.
Migrated grails2 to grails3.
In grails2 i used lots of
log.info,log.debug
statements in side src/main/groovy files.
but in grails-3 by default log is not injected.
it's giving error like No such property: log for class
This is a planned change. You can use #groovy.util.logging.Commons annotations on your non-grails classes to have log available. Also other like #Log4j, #Slf4j are available, depending on your logging library.
There is one more difference which is important - those annotations will add log as private property and classes which will inherit from them, will also need to be annotated to use logging. Alternative is to manually define protected logger on your class.
I add two annotations on the service method, after compiled, I found the method were compiled to a new class file, and I decompiled the generated class files and found the #CompileStatic were not work as wished.
Is is right or a bug of grails?
class FoobarService {
#grails.transaction.Transactional
#groovy.transform.CompileStatic
void foobar() {
....
}
}
The grails.transaction.Transactional annotation is a replacement for the traditional Spring org.springframework.transaction.annotation.Transactional annotation. It has the same attributes and features and works essentially the same, but it avoids an unfortunate side effect of using the Spring annotation.
The Spring annotation triggers the creation of a runtime proxy of the annotated class. Spring uses CGLIB to create a subclass of the target class (typically a Grails service) and an instance of the CGLIB proxy is registered as the Spring bean instead of registering a service instance directly. The proxy gets an instance of your service as a data variable.
Each method call is intercepted in the proxy, where it does whatever checks and/or setup is required based on the transaction settings, e.g. joining an existing transaction, creating a new one, throwing an exception because one isn't already running, etc. Once that's done, your real method is called.
But if you call another annotated method with different settings (e.g. the first method uses the default settings from #Transactional but the second should be run in a new separate transaction because it's annotated with #Transactional(propagation=REQUIRES_NEW)) then the second annotations settings will be ignored because you're "underneath" the proxy , inside the real instance of your service that the proxy is intercepting calls to. But it can't intercept direct calls like that.
The traditional workaround for this is to avoid direct calls and instead make the call on the proxy. You can't (at least not conveniently) inject the service bean into itself, but you can access the application context and access it that way. So the call that you would need in that situation would be something like
ctx.getBean('myService').otherMethod()
which works, but is pretty ugly.
The new Grails annotation works differently though. It triggers a reworking of the code via an AST transformation during compilation. A second method is created for each annotated method, and the code from the real method is moved inside there, in a GrailsTransactionTemplate that runs the code using the annotations settings. Once there, the code runs with the required transaction settings, but since every method is rewritten in this way, you don't have to worry about the proxy and where you're calling the methods from - there is no proxy.
Unfortunately there's a side effect that you're seeing - apparently the transformation happens in a way that isn't preserving the #CompileStatic annotation, so the code runs in dynamic mode. Sounds like a bug to me.
I want to be informed when uncaught exceptions occur in my Grails 2.2.4 application. Log4j has an SMTPAppender doing something similar, but only based on a specific log level. In my application there are already a lot of log entries in all available log levels, so sending email on ERROR or FATAL is not really an option because it would also contain non-exception entries.
Filtering uncaught exceptions in Grails is quite easy, I just redirect them to a specific controller and handle it there:
static mappings = {
[...]
"500"(controller: "errors", action: "serverError")
}
My plan was to introduce my own log level and use it only for uncaught exceptions. Documentation suggests this:
final Level EXCEPTION = Level.forName("EXCEPTION", 50);
logger.log(EXCEPTION, "uncaught exception", e);
But I don't know how to use this in Grails with the injected log object. It only supports the base options like log.error('foo',e). Grails documentation says how to add custom appenders, but nothing about custom levels (or did I miss it?!)
Any suggestions?
Grails uses Slf4j and Commons Logging to abstract the logger implementation and allow changing from Log4j to another framework without having to edit every file with a logger. Instead, the wrapper library gets the correct implementation instance based on the requested logger name and what's available from the native API. If you change implementations, the wrapper loggers work the same way as far as your app code is concerned, but they call different implementation loggers to do the actual logging.
But there's no standard between implementations for configuration, so internal Grails startup code works directly with the API to configure loggers, appenders, levels, etc. You can do the same - use the traditional Log4j logger access code to get an instance by logger name, using the same one as the preconfigured logger Grails wired up. I can never remember the naming convention for loggers in artifacts, so I cheat and add a line of code
println log.name
in a method that I know runs, and call that method indirectly via whatever controller action can get there. So for example, if I want to know the logger of FractalService, put that code in its graphJuliaSet method and call the controller action that graphs Julia Sets using this service.
Log4j loggers are singletons, if you access the logger and change it, that will affect all future calls.
So that logger is available via something like:
String name = ... // the name from the println above
Logger logger = Logger.getLogger(name)
I am currently getting the warning in Grails of
'The [update] action accepts a parameter of type [edu.acu.teachereval.SubjectCode] which has not been marked with #Validateable. Data binding will still be applied to this command object but the instance will not be validateable.
#Transactional'
along with the same errors for show, save, edit, and delete for the controller mentioned in the error and other controllers that I have created. I have seen this issue for user created functions, but I have not seen this error for functions that are built in to grails. Any assistance would be appreciated.
I think you need to add a #Validateable annotation to your SubjectCode class.
Reference
This may be coming late, But this error is likely to occur when you use models not created in the domain conventional folder.
It seems grails automatically injects the #Validateable annotation to domain classes/models in the domain Folder,
If you therefore create your models in the src/grails or src/java folder, You are likely to get this error when the model object is passed/posted/submited via a View to a controller function.
Try adding the #Validateable annotation to the domain object
Move the domain model to the domain grails convention folder
or maybe Grails is overreaching while simultaneously giving misleading error messages... nah, that never happens. For a more relevant answer, see:
Groovy / Grails using a map as a parameter of a function