I have a config.properties file that i want to update during runtime (for example, if the app receives a certain rest call, it updates the config properties).
Is this doable in java? or we can't change the config file on runtime?
thanks
In case you are using Java's Properties class, you can easily do it like this:
final Properties config = new Properties();
You can load a config file to your in-memory config like this:
final File f = new File("config.properties");
if(!f.exists) {
f.createNewFile();
}
final InputStream in = new FileInputStream(in);
config.load(in); //loads the config into the Properties object
in.close();
And if you wish to save the Properties back to a file, you can do:
final OutputStream out = new FileOutputStream(f);
config.save(out, "Some config comments...");
out.close();
You would probably need to wrap this in a try-catch block, but that's basically it.
This is possible, i assume you're using the Properties API? http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html
You can use the store method specifying an OutputStream
logback uses Joran internally, which enabled logback to read configuration files and update them "on the fly" when their content changes. I used this functionality in 2011 and as far as I know Joran still is part of logback.
You could do something like this:
ruleMap = new HashMap<Pattern, Action>();
SetProfileParameterAction profile = new SetProfileParameterAction();
ruleMap.put(new Pattern("*/profile"), new AddProfileAction());
ruleMap.put(new Pattern("*/profile/description"), profile );
ruleMap.put(new Pattern("*/profile/link"), profile);
SimpleConfigurator simpleConfigurator = new SimpleConfigurator(ruleMap);
simpleConfigurator.setContext(context);
try {
simpleConfigurator.doConfigure(cfgFile);
} catch (JoranException e) {
log.error( "failed ...", e);
StatusPrinter.print(context);
}
Please note: this is just a non-complete cut-down version of my code but if Joran works for you this example will give you a hint in which direction to go ...
Related
I have a real quick question. I have a Java program in which I use a properties file. The file is used for keeping track of the program's users. My problem is I cannot figure out how to ADD to the file. I know how to set existing properties to a value, but I don't know how to add more properties without over writing the other ones.
I would like the program to 'register' users, so to speak. Whenever a new users 'signs up', I want the program to add a new property containing the new user's information. I run into this problem though:
Example:
File: numOfUsers=0
One user registers. The username is 'c00lGuy'. The program registers this in the file:
File: numOfUsers=1 user1-username=c00lGuy
Another user registers. She decides to call her username 'theGr8Girl'. The program registers this:
File: numOfUsers=2 user2-username=theGr8Girl
The file after the two users registered:
File: numOfUsers=2 user2-username=theGr8Girl
How do I prevent my program from overwriting existing lines in the file? It seems to erase the file's contents, and then add what I tell it to. I don't want it to erase the file's contents.
The code I am using to register the properties:
Properties prop = new Properties();
OutputStream output = null;
int userCount = getUserCount();
userCount++;
try {
output = new FileOutputStream(fileName);
// set the properties value
prop.setProperty("numOfUsers", String.valueOf(userCount));
prop.setProperty("user" + userCount + "-username", username);
// save properties to project root folder
prop.store(output, null);
} catch (IOException io) {
io.printStackTrace();
} finally {
if (output != null)
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Try something like this:
FileOutputStream out = new FileOutputStream(fileName);
props.setProperty("numOfUsers", 2);
...
props.store(out, null);
out.close();
Properties files aren't really intended for this sort of usage, but if you have a small enough data set it'll work.
The step you are missing is that you need to read the properties from disk, make the changes, then save them back to disk.
Properties props = new Properties();
try{
props.load(inputStream);
} finally {
inputStream.close();
}
props.setProperty(....);
try{
props.store(outputStream);
} finally {
outputStream.close();
}
Just bear in mind that this is not at all suitable for any sort of volume processing. Also, there is a race condition if you have two threads trying to make changes to the properties file at the same time.
If you are looking for a lightweight persistent store, I highly recommend mapdb.
You code is creating a new Properties object each time. Make sure to reuse the old instance when adding a user.
The typical format for a line in this file would be
user=hashedPassword
so use the username as the key and the password as a value. The number of users does not need to be stored, it is just the size of the properties map.
I need a configuration file (Properties) for this project I'm working on.
The issue is that the Properties instance fails to load from the file (no exceptions, no visible problems) although it can store properly.
Because I have a defaults HashMap, any property that doesn't exist has it's default value placed in the Properties instance, which then stores everything, so that new properties are seamlessly added when the production server is updated.
I've been tracking this bug for hours, and I can't fix it. I've read dozens of questions here on StackOverflow as well as code examples on other sites. Nothing helped.
The one reason I haven't dropped it already and used the DB instead is that the JDBC driver URL, user and password are stored in that file as well. Notice that the file is being read and written to the hard drive.
Since the defaults system puts stuff in place, even if the file doesn't exist when I try to read, after it's saved it appears, but the next run still won't read anything. I noticed the bug after I changed a setting, and checked the file after a few runs, and to my shock, all values were default.
What's currently happening is the following:
1) No matter if the file is there or not, Properties will not load anything.
2) Since there's nothing in the Properties instance, it is filled with defaults.
3) The instance will now save, overwriting the file with the default values.
Here's all the relevant code:
private static Properties getConfig(){
Properties properties = new Properties();
File cfgFile = new File("data/titallus.properties");
try{
if(cfgFile.createNewFile()){
System.out.println("Config file not found. A default config file will be created automatically.");
}
FileReader reader = new FileReader(cfgFile);
FileWriter writer = new FileWriter(cfgFile);
properties.load(reader);
reader.close();
System.out.println(properties); // Debug, always prints '{}'
for(String k : defaults.keySet()){
if(!properties.containsKey(k)){
properties.setProperty(k, defaults.get(k));
}
}
properties.store(writer, "Titallus Configuration File");
writer.close();
}catch(Exception e){
e.printStackTrace();
System.exit(-1);
}
return properties;
}
I have tried everything I could think of, to no avail.
I also have a Properties subclass for multi-language support, which works just fine.
Does anyone have any idea how to fix this, or at least, another approach to this?
FileWriter writer = new FileWriter(cfgFile);
will be erasing your file before you read from it.
You create a FileWriter for the file before you load the file, which clears the existing data.
is it possible to override the "File" property of an appender that has been configured in the log4j.properties without creating a new appender?
And if so - how?
This is the situation: I have two apenders, A1 is a ConsoleAppender and A2 is a FileAppender. A2's "File" points a generic error.log:
log4j.appender.A2.File=error.csv
This appender only logs error-level events or worse through
log4j.appender.A2.Threshold=error.
Now I want those errors to be written in different files depending on which class caused the error, as there are several classes that instances are being created of.
Being able to see which class created the error(s) fast would be of great help, as it is a lot more helpful then skimming through the error.log looking for the class-tags.
So my idea was to override the "File" property e.g. in the constructors of these newly created classes, so they log errors in different files.
Thanks a lot in advance!
For changing log4j properties on runtime visit this link
http://alperkaratepe.wordpress.com/2010/01/16/how-to-change-log4j-properties-at-runtime/
private void updateLog4jConfiguration(String logFile) {
Properties props = new Properties();
try {
InputStream configStream = getClass().getResourceAsStream( "/log4j.properties");
props.load(configStream);
configStream.close();
} catch (IOException e) {
System.out.println("Error: Cannot laod configuration file ");
}
props.setProperty("log4j.appender.FILE.file", logFile);
PropertyConfigurator.configure(props);
}
Old question (well indexed in google). In addition to OP's requirement, adding additional methods iv'e read about to manipulate log4j.properties
Modify loaded log4j.properties in runtime
private void updateLog4jConfiguration(String logFile) {
Properties props = new Properties();
try {
InputStream configStream = getClass().getResourceAsStream( "/log4j.properties");
props.load(configStream);
configStream.close();
} catch (IOException e) {
System.out.println("Errornot laod configuration file ");
}
props.setProperty("log4j.appender.FILE.file", logFile);
LogManager.resetConfiguration();
PropertyConfigurator.configure(props);
}
full example is in this article
Setting log4j.properties in runtime
Can be done manually
Properties properties = new Properties();
properties.setProperty("log4j.logger.org.hibernate", "ERROR");
// ...
LogManager.resetConfiguration();
PropertyConfigurator.configure(properties);
Or by loading a different properties file
Properties properties = new Properties();
properties.load(new FileInputStream("/etc/myapp/properties/custom-log4j.properties"));
LogManager.resetConfiguration();
PropertyConfigurator.configure(properties);
VM Option
You can tell log4j to load a different file using log4j.configuration VM option
java -Dlog4j.configuration=file:///etc/myapp/properties/custom-log4j.properties
if you choose this option, it must be provided in the execution line
I have a stupid java logging problem: I'm loading the logging configuration from my app configuration file - but it just doesn't log anything after reading the file (which looks pretty much like the examples you will find on the net except for the additional application configuration - removing this also doesn't help). The "initializing..." log line appears just fine, but the "starting app" and any further messages are neither logged to the console, nor is the logfile ever created. What am I missing here?
The Logger code looks like this:
...
Logger log = Logger.getLogger("myApp");
log.setLevel(Level.ALL);
log.info("initializing - trying to load configuration file ...");
Properties preferences = new Properties();
try {
FileInputStream configFile = new FileInputStream("/path/to/app.properties");
preferences.load(configFile);
LogManager.getLogManager().readConfiguration(configFile);
} catch (IOException ex)
{
System.out.println("WARNING: Could not open configuration file");
System.out.println("WARNING: Logging not configured (console output only)");
}
log.info("starting myApp");
...
And this is the configuration file:
appconfig1 = foo
appconfig2 = bar
# Logging
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level = ALL
# File Logging
java.util.logging.FileHandler.pattern = %h/myApp.log
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level = INFO
# Console Logging
java.util.logging.ConsoleHandler.level = ALL
you can set your logging configuration file through command line:
$ java -Djava.util.logging.config.file=/path/to/app.properties MainClass
this way seems cleaner and easier to maintain.
Okay, first intuition is here:
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level = ALL
The Java prop file parser isn't all that smart, I'm not sure it'll handle this. But I'll go look at the docs again....
In the mean time, try:
handlers = java.util.logging.FileHandler
java.util.logging.ConsoleHandler.level = ALL
Update
No, duh, needed more coffee. Nevermind.
While I think more, note that you can use the methods in Properties to load and print a prop-file: it might be worth writing a minimal program to see what java thinks it reads in that file.
Another update
This line:
FileInputStream configFile = new FileInputStream("/path/to/app.properties"));
has an extra end-paren. It won't compile. Make sure you're working with the class file you think you are.
I have tried your code in above code don't use
[preferences.load(configFile);]
statement and it will work. Here is a running sample code
public static void main(String[] s) {
Logger log = Logger.getLogger("MyClass");
try {
FileInputStream fis = new FileInputStream("p.properties");
LogManager.getLogManager().readConfiguration(fis);
log.setLevel(Level.FINE);
log.addHandler(new java.util.logging.ConsoleHandler());
log.setUseParentHandlers(false);
log.info("starting myApp");
fis.close();
} catch(IOException e) {
e.printStackTrace();
}
}
Logger log = Logger.getLogger("myApp");
log.setLevel(Level.ALL);
log.info("initializing - trying to load configuration file ...");
//Properties preferences = new Properties();
try {
//FileInputStream configFile = new //FileInputStream("/path/to/app.properties");
//preferences.load(configFile);
InputStream configFile = myApp.class.getResourceAsStream("app.properties");
LogManager.getLogManager().readConfiguration(configFile);
} catch (IOException ex)
{
System.out.println("WARNING: Could not open configuration file");
System.out.println("WARNING: Logging not configured (console output only)");
}
log.info("starting myApp");
this is working..:)
you have to pass InputStream in readConfiguration().
Are you searching for the log file in the right path:
%h/one%u.log
Here %h resolves to your home : In windows this defaults to :
C:\Documents and Settings(user_name).
I have tried the sample code you have posted and it works fine after you specify the configuration file path (logging.properties either through code or java args) .
i am writing standalone java app for production monitoring. once it starts running the api is configured for default values which is set in .properties file. in running state the api's configuration can be changed and the .properties file should be updated accordingly. is there a way to achieve this ? or are there any other approaches to implement this ?
Thanks in advance
The Java Properties class (api here) specifies "load" and "store" methods which should do exactly that. Use FileInputStream and FileOutputStream to specify the file to save it into.
You could use a very simple approach based on the java.util.Properties class which has indeed a load and store methods that you can use in conjunction with a FileInputStream and FileOutputStream:
But actually, I'd recommend to use an existing configuration library like Commons Configuration (amongst others). Check the Properties Howto to see how to load, save and automatically reload a properties file using its API.
I completely agree that Apache Commons Configuration API is really good choice.
This example update properties at runtime
File propertiesFile = new File(getClass().getClassLoader().getResource(fileName).getFile());
PropertiesConfiguration config = new PropertiesConfiguration(propertiesFile);
config.setProperty("hibernate.show_sql", "true");
config.save();
From the post how to update properties file in Java
Hope this help!
java.util.Properties doesn't provide runtime reloading out-of-the-box as far as I know.
Commons Configuration provides support for reloading configuration at runtime. The reload strategy can be configured by setting a ReloadingStrategy on the PropertiesConfiguration object. It also offers various other useful utilities for making your application configurable.
In addition to the load and store method of the Properties class, you can also use the Apache Commons Configuration library, which provides functions to easily manipulate configuration files (and not only .properties files).
Apache common configuration API provided different strategies to reload property files at run time. FileChangedReloadingStrategy is one of them. Refer this link to see an example for property file reloading at run time using FileChangedReloadingStrategy.
Try this:
// Write in property file at runtime
public void setValue(String key, String value) {
Properties props = new Properties();
String path = directoryPath+ "/src/test/resources/runTime.properties";
File f = new File(path);
try {
final FileInputStream configStream = new FileInputStream(f);
props.load(configStream);
configStream.close();
props.setProperty(key, value);
final FileOutputStream output = new FileOutputStream(f);
props.store(output, "");
output.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
// Read same file
public String getValue(String key) {
String value = null;
try {
Properties prop = new Properties();
File f = new File(directoryPath+"/src/test/resources/runTime.properties");
if (f.exists()) {
prop.load(new FileInputStream(f));
value = prop.getProperty(key);
}
} catch (Exception e) {
System.out.println("Failed to read from runTime.properties");
}
return value;
}