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"
Related
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.
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...
Section 3.4 of Grails documentation says that Grails app can be configured from an external source:
grails.config.locations = [
"classpath:${appName}-config.properties",
"classpath:${appName}-config.groovy",
"file:${userHome}/.grails/${appName}-config.properties",
"file:${userHome}/.grails/${appName}-config.groovy" ]
Also, it is possible to load config by specifying a class that is a config script:
grails.config.locations = [com.my.app.MyConfig]
My questions are:
Could you please give an example of how MyConfig class implementation could look like? It is not quite clear from the documentation.
If I want to use some external JSON REST service as a source for my config data, how can this be implemented?
Answer for second question: you can do that in BootStrap.groovy init closure, because basically, it allows you to execute any code:
// Inject grails app
def grailsApplication
def init = { servletContext ->
def externalValue = getItUsingRest(someUrl)
grailsApplication.config.my.custom.var = externalValue
}
Depending on version of grails you are using, you might need to use
org.codehaus.groovy.grails.commons.ConfigurationHolde.config
to get to config instead.
Your application configuration can actually be a Groovy script. So any class which looks like your Config.groovy can act as a configuration class. In our projects we tend to keep the configuration outside the grails application so that the application can be configured without recompiling everything.
Maybe this post of mine will give you a hint on how to use and load external configuration files.
Inside a grails application, I need to upload a file under web-app/js, add a prefix, and put it in S3. I'm having trouble figuring out how to read the js file in a way that will work in development (/web-app/js) and production (/js). I'm doing this from inside a domain object.
In your controllers, you can call :
def jsFolder = grailsAttributes.getApplicationContext().getResource("js/").getFile()
and then proceed with jsFolder.
To determine the base directory of a running Grails application, use
String dir = applicationContent.getResource("/").getFile()
Getting the js path from a service is a little bit tricky:
You need to implement the ApplicationContextAware interface like this :
class MyService implements ApplicationContextAware {
ApplicationContext applicationContext
However, calling this code from a domain class is not a good idea (see this thread for some explanations) and I am not even sure if it's possible except from getting paths from manual configurations
Hope it helps.
In GWT I have to specify what locales are supported in my application. The code get compiled in various files, one for each locale (beside other versions), but I have to give my clients one only URL. This URL is supposed to be a page that should be displayed according to the locale preferred by the browser.
I dont't want to have an HTTP parameter for the locale since I want to forse the locale preferred by the browser.
How can this be coded in GWT?
Should I try to to this using apache rewrite rules? I thied it, but I think I cannot access such parameter easely in a rewrite rule.
Thanks a lot,
Giuseppe
I had the same problem as you, but as I really need to know the current locale (I'm requesting a second server for data that I want to be localizable) I found this class:
com.google.gwt.i18n.client.LocaleInfo#getCurrentLocale(). That should give you what GWT uses currently.
GWT has good support for internationalization. See this link. The i18nCreator command can help you to set up the internationalization infrastructure for similar to the way projectCreator and applicationCreator set up the GWT application.
If you have static strings (i.e. Invalid Entry!) that need to be internationalized, you don't need any additional flag to i18nCreator command to create the properties files and infrastructure.
If you have strings that need to accept parameters (i.e. Hello {0}), you need to pass the -createMessages flag to i18nCreator command to create the properties files and infrastructure.
Now your module needs to include the i18n module in your MyApplication.gwt.xml:
<inherits name="com.google.gwt.i18n.I18N"/>
Define a Java interface in the same package as your property files that extends Constants or Messages and defines methods (name matches the property entries) that all return string.
MyConstants.properties contains:
errorMessage=Invalid Entry!
MyConstants.java contains:
import com.google.gwt.i18n.client.Constants;
public interface myConstants extends Constants {
String errorMessage();
}
Now to access these internationalized Strings from you application:
public class MyApplication implements EntryPoint {
private static final MyConstants constants = (MyConstants)GWT.create(MyConstants.class);
public void onModuleLoad() {
final Label errorMessage = new Label(constants.errorMessage);
}
}
GWT implements the interface for you automagically.
You can get messages in a similar way.
Hopefully this can help you get started.
Unless I am reading the documentation incorrectly I don't think you have to do anything.
GWT and Locale
By making locale a client property, the standard startup process in gwt.js chooses the appropriate localized version of an application, providing ease of use (it's easier than it might sound!), optimized performance, and minimum script size.
The way I read it, as long as your module has added all the locale choices to it, it should be automatic?
Check this com.google.gwt.i18n.client.LocaleInfo.getCurrentLocale()
<inherits name="com.google.gwt.i18n.I18N"/>
<!-- Use browser-specified locale for i18n -->
<set-configuration-property name="locale.useragent" value="Y"/>
<!-- Specify locales your application support -->
<extend-property name="locale" values="en"/>
<extend-property name="locale" values="de_DE"/>
<extend-property name="locale" values="ru_RU"/>