Change Log4J2 Output File During Runtime - java

I'm trying to integrate Log4J2 with a bit of custom logging functionality in a project of mine and running into some issues getting Log4J2 to behave similarly to my own implementation. I'd like to be able to change the log file being written to (make if doesn't exist, cease writing to old file, only write to new file) based on events that occur in execution.
I'll give an example that hopefully illustrates what I'm looking for. We start the application and write to some predetermined log file name but we're just recording preliminary logs because nothing of interest has really happened yet. Once environmental conditions are correct and we've received user input the software is engaged and we'd like to begin logging for both debugging information and data capture. To separate the preliminary data from the interesting data we'd like to change our log file to a new log file who's name contains more information about the state of the environment when the system was engaged, to make it easier to sort through which log files we want to analyze and post-process.
I've seen posts on how to accomplish similar things, but they seem to either require the new filename to be known before Log4J2 is initialized (i.e. setting a system property) or using a RoutingAppender which seems to be closer but appears to require knowing all possible values (to define the routes) that we might want to put in our file name. We'd have to define one route per each environment state (or worse yet, each state combination) we want to put in the file name.
Any ideas?

You use the RoutingAppender to dynamically create new files based on a ThreadContext key/value.
Here is an example of how to do this:
https://logging.apache.org/log4j/2.x/faq.html#separate_log_files
In the example, the value of ROUTINGKEY in the ThreadContext map determines the new file name.

Related

What is the simplest way to configure `java.util.logging`

I have a 3rd-party developed big complex application full of java.util.logging.Logger#finer() calls.
Normally I use log4j and sl4j for logging, and I don't know very much of java.util.logging, even less about all the configuration details and possibilities.
Every single google about "java.util.logging" points to a full explanation about streams handlers, formatters, levels. Everyone assumes I really care about all this stuff (it is a reasonable assumption actually). But I couldn't care less.
I'm not really interested in separating logs per file, or file rotation, zipping, email, remote log etc. I'm also not concerned about log level and message formatting thrills.
All I want to do is to run this application with all available log messages spitting to stdout.
Is there an easy simple direct way to do this?
Something like jvmargs -Djava.util.logging.level=FINEST -Djava.util.logging.to=stdout.
Or maybe some simple file dropped into some location in the classpath?
All I want to do is to run this application with all available log messages spitting to stdout
Don't do this in production but it is the fast, easy, hacky way:
Edit the logging.properties file located in java/conf. E.G. /usr/lib/jvm/default-java/conf/logging.properties
That file is setup to attach a ConsoleHandler to the root logger which is what you want to do this. You just need to adjust the levels to see the output. This is a global change so be aware.
Edit that file and:
Change .level= INFO -> .level=ALL
Change java.util.logging.ConsoleHandler.level = INFO to java.util.logging.ConsoleHandler.level = ALL
Save the changes and restart your app.
The recommended way:
Most JVMs are not in your control (production/dev server) so you can instead copy that file to a location you own and use the java.util.logging.config.file system property.
E.G. -Djava.util.logging.config.file=/home/myuser/myapp/logging.properties
That way you are free to make changes that are local to your program and not global to the machine.

Logback-rolling multiple services

I'm trying to write logs of multiple services to same file, but my rolling policy given is not working, tried with both time based and size based rollings. Thing is my services are running simultanously and writting there logs to same file in my local directory. When tried to write logs by single service it is working as expected.
Please help me to solve this issue tried with different rolling policies.
Appender to log to file​
${LOG_FILE}
Minimum logging level to be presented in the console logs
INFO
${LOG_PATH}/archived/log_%d{dd-MM-yyyy}_%i.log
10KB
I had an experience similar to yours with Log4j 1.x then I debugged an appender back then (~5-6 years ago) and came to the following conclusions:
I don't think you can write data from multiple services into the same file. In other words,
Logging framework usually assumes that only it can change the file. In some Operating Systems (windows) it will even stop writing into file if some other process will rename / change the current file.
Of course its just a code and you could create a more sophisticated appeneder that will probable make it work, but frankly I don't think it worth the effort.
So I suggest writing into different files, where file name can be generated in a way that it will contain a pid of the resource. The downside of this method is that if the process dies and then re-runs, on-one will take care of the old resources.
Another approach (somewhat similar) - is to create a folder with logs for each service so that they'll get different logs based on folder (even if files in these folders will be with the same name).

How to know my Java application is run for first time

I have a standalone Java application which i shall be shipping to the customers. The first time the exe is run I would like to show some welcome messages,configuration details etc. Its like a one time helping out the user to get started
How to reliably ascertain that my application is run for the first time? I have a log4j logger file that I shall create on the users system for logging. I was thinking of using its timestamp.
Is there an industry standard approach to this probelm?
Take a look at java.util.prefs package. It allows to write / read config data in system dependent storage, eg Windows registry
Read and write Properties files. One property can be "Run before?" with a default value of "0" or "never". You don't even have to have the property in the default file because you can supply the default in the program call querying the property. You don't even have to have a property file because the program can write one out the first time. Thus the mere existence of a property file can be a cue to the program that it has run before.
Approaches like this can lead to self-installing programs (with or without user options asked via gui).

Centralized Application properties for multiple system

I am looking for a open-source solutions which allow hosting different properties for different applications and allow changes. On any change of properties it should notify or push the change to the application appropriately.
So, instead every application managing the properties in physical file and deploying physically; these properties can be pushed to a single system. User will have GUI to load and change the properties as per right. Should allow push as mentioned.
If you have already similar open source solutions in mind please advice.
Is this something that Puppet can manage for you?
I don't think what you've described (as nice as it would be) will be likely to exist in an app server. If a program is looking for a file, it's either going to load it with a FileReader (or similar), or it will use ClassLoader.getResourceAsStream(). It might be looking for data that is returned in properties, format, XML properties format, or even something completely different like RDF with which to configure itself. Also many programs read their config on start-up and then hold the values in memory, so you would still need to reboot them to get them to change.
To get something like this to work there would need to be a standard for configuration provisioning and live updates. Once that existed the webapp authors and server vendors would each need to add support for the standard.
If you are the one writing the programs to be managed however, then you can write your programs to request configuration from a service, and have a configuration push feature.... there may be packages out there that can speed up adding that to your code, but I get the impression you are looking to manage programs written by others.
Have you considered to use JMX? I think he could be a good starting point to implement your requirements.
MBeans's attributes can store your application's properties, the MBeanServer will allow you to make them available from remotting, JConsole offers you an GUI to update properties values.
You also can write within the MBean some code that notify the corrrespondig application when a user change any properties using the GUI.

Implementing logging

I was just wondering if following thing exists.
I have a TCP communicator which keeps communicating with thousands of devices.
Currently, the TCP communicator logs all the events in one log file.
Now, is it possible to log communication with every device in different files. The IMEI number of every device is different. So the logger will check if a file with name equal to the IMEI number of the device exists. If the file exists, logger will start logging events of the device in that file, otherwise it will create a new file with IMEI as the file's name and start logging the events in that file.
(We are developing our application in Java.)
LogBack is the future, and it's here!
Created as a successor of log4j and fully complaint with the slf4j framework, logback might be the easy (and clean) way to fulfill your need.
I'm not an expert but I guess that SiftingAppender might be the right answer. There should be a discriminator option for you. Maybe you can build your own discriminator, extend the SiftingAppender, or get some extra help from Janino library.
Hope this helps!
If you are implementing the logger yourself, there's nothing to stop you from doing this.
For example, give the log function as a parameter the number of the device you're currently communicating with, and implement it the way you described.
If you're using Apache log4j, which I highly recommend, create a custom logging appender by extending AppenderSkeleton and writing unique files for individual connections will be as simple as doing standard file I/O with a variable filename.
If you are using java.util.logging, look at the Handler base class, if you are using log4j, look at Appender. In both cases, you need to somehow get the IMEI associated with the message, so the code writing the log message can pick the appropriate file.
There are two approaches to doing this.
First is to extend the log event class (LogRecord or LoggingEvent respectively). This would allow you to log using your event, which contains the IMEI. However, this does not account for logging performed by other libraries etc while performing the conversation with a device.
The other alternative is to use a ThreadLocal. Set the IMEI associated with a socket whenever you receive a message or are formulating message. Make sure that the logging happens in the same thread, and any queuing is done at the log handler/appender. Look for / ask questions about ThreadLocals if you are unfamiliar with this approach. I believe that Log4J's NDC and MDC implements this sort of strategy, but I've not tried to do specialized processing of context at the appender.
Finally, be aware some operating systems will run out of file handles if you are indeed thinking of keeping "thousands" of log files open. Depending on just how many files, you may want to consider writing log messages (with IMEI) to a database, or doing some sort of LRU-based file closing. In the latter, you would basically not have file handles for log files that haven't been touched in a while.

Categories

Resources