log4j2 new compression algorithm - java

I would like to use log4j2 RollingFileAppender with a customized compression algorithm (ZStd).
It seems that the compression algorithms supported so far are the ones in the FileExtension enum (zip, gz, bz2, ...), see https://github.com/apache/logging-log4j2/blob/efa64bfad3f67c5b5fed6b25d65ef5ca2212011b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FileExtension.java, and I believe it is not possible to add a new one (apart from patching the library).
A solution could be to reimplement the RollingFileAppender using the approach suggested here: https://logging.apache.org/log4j/2.x/manual/extending.html#Appenders, but this would involve a lot of ugly copy and paste, this appender really does a lot of things.
The approach I would like to follow is to create instead a new Action, implementing the AbstractAction interface, but I do not know how to tell log4j2 to execute this action on rollover. Is this doable? Is this the correct way to achieve this goal?

Yes. The Rollover strategy uses FileExtension to automatically add a CompressAction based on the file extension, but you can do this yourself just by configuring a custom Action. While you can look at ZipoCompressAction as a template for how to implement the action, you would also need to look at DeleteAction to see how to declare your custom action as a plugin.

Related

Best way to manage a Configuration File?

A colleague and I were discussing best practices for managing a Configuration file, and we wanted to get some further feedback from others.
Our goal is for the configuration-file to specify what action should be taken, when certain events occur.
The 2 options that we are debating:
In the config-file, specify the class-path of the class, which implements the action to be taken (eg: "ActionToTake" : "com.company.publish.SendEveryoneAnEmailClass").
Inside the code, when this event is encountered, we can then do Class.forName(config.ActionToTake).newInstance().run() in order to invoke the specified action.
In the config-file, specify in a human-readable-phrase, the action that should be taken (eg: "ActionToTake" : "SendEveryoneAnEmail"). Inside the code, when this event is encountered, we can then parse config.ActionToTake, and perform a mapping that translates this to action implementation (eg: new SendEveryoneAnEmailClass().run())
We are currently a very small team, and the only people reading/using this config file currently, is our team of software devs. But it's unclear if this will continue to be true in future.
Reasoning behind option 1: Anyone reading the config file will explicitly and immediately know what class will get invoked, and where it's implemented. This also allows for the action-class to be implemented/imported from a completely separate JAR file, without recompiling/changing our code.
Reasoning behind option 2: The config file should be a high level description of user-intent, and should not contain implementation details such as specific class names & package paths. Refactoring of class/package names can also be done without having to make config file changes.
Thoughts on which of these 2 design philosophies is preferred for configuration files?
1st option's advantage is, as jas noticed, the ability to 'link' code in the future. It's a real advantage only if you sell/distribute your software as a closed sourced package or if you plan to hot-swap behavior on production. You've already pointed out the cons - refactoring
2nd option:
It won't help you with refactoring. If you change your action from SendEmail to BringBeer but you leave the string send email then you failed.
Readability. send-everyone-an-email is as good as SendEveryoneAnEmail. Every developer will know what will happen. It can't be confused with LaunchRockets. Your code can find class based on some text, not necessarily the full qualified name. Your code can assume that Actions are in some specific package unless explicitly provided. And that is a way to combine both options.
Consider also another possibility: do the configuration in code. If you don't want to recompile the package, you can use scripting language (groovy). It lets you create very readable dsl, and you will have refactoring.

What is a good usecase for Guice Mapbinder?

I've seen it used, but I'm not sure the usage were good usecase examples. Do you have examples of idiomatic usages of Guice Mapbinder? (Cases where Mapbinder is really the correct tool to solve a problem)
Offhand, it looks like a reasonable way to create a registry of runtime-named implementations of a common interface. Consider selecting one of many plugins/modes/whatever from a command line or configuration file: the desired injection can't be known at compile time. A MapBinder provides an easy runtime lookup without resorting to type-switching.
I extensively use it in Guts-GUI.
You can take a look, in particular, at the ResourceModule, where it is used to map the right ResourceConverter<T> for a given type T:
Map<TypeLiteral<?>>, ResourceConverter<?>>
The MapBinder is directly created in the Resources helper class.
This way, any module can add its own resource converters for its own types, e.g. MessageModule adds its own converters.
I also used it as Map<Integer, WindowProcessor>> in WindowsModule to define an ordered list of WindowProcessors to be applied, one after another, to a newly created window..
Once again, this allows various modules to insert their own processor to the list applied to every window: ResourceModule uses it to add the ability of automatic injection of i18n resources to windows.

Struts2 internationalization using a database

We have a rather large application, with a great deal of dynamic content. Is there anyway to force struts to use a database for the i18n lookups, instead of properties files?
I'd be open for other ways to solve this as well, if anyone has ever done i18n with dynamic content.
I don't know of an easy plug-and-play solution for this, so you will probably have to implement it yourself -- plan on spending quite a bit of time just coming to grips with how the localization features of struts 2 (and XWork) are implemented. The key will probably be to provide your own implementation of com.opensymphony.xwork2.TextProvider (and tell struts to use it by providing a <bean> tag in struts.xml). I can think of at least two ways of fitting this into the overall architecture:
Have your TextProvider implementation access the database directly. In the spirit of YAGNI, this is probably the best way to start (you can always refactor later, if necessary).
Alternatively, you could place the database code into an implementation of Java's ResourceBundle interface, which is what XWork uses internally. To me this sounds like an even more design-heavy approach, but on the plus side there are some articles around describing how to do this.
No, there is no built-in way to have Struts2 load localized content from a database. You would need to write that yourself.
What are your requirements? Do you need for users to be able to dynamically change field prompts, error messages, etc.?
You may be able to do something like that by building a custom interceptor. You could have the interceptor read all the key value pairs from your database and inject them into the value stack. The only thing I am not sure about, not really having messed with i18n with struts before, is if the i18n stuff pulls that information from the value stack. If not, I am not sure if maybe you could do something else in the interceptor to load up the information.
Building a custom interceptor is not too terribly complicated. There are plenty of tutorial sites out there, including (brace for self promotion here) my blog: http://ddubbya.blogspot.com/2011/01/creating-custom-struts2-interceptors.html.
Use properties files just for static content, like labels, messages etc.
For dynamic content start with a database table that includes a language-code-id for every language you want to use. All the dynamic content entries that are already translated go with their respective language-code-id added to their primary key. If a translation is missing, you can program your application to fall back to your default language in order to make things easier until the right translation is present.
Let your users provide their contributions in the language they like and store it with the appropriate language-id. Someone should provide the translation to the other languages in order to make the contribution complete.
...
PRIMARY KEY (`subject_id`,`language_id`),
...

Simple logger, how to?

I want to write a default Logger for my application. Currently I am using the default Java API Class Logger .
I was wondering if it's possible to format my logs to look somthing like this:
[level] [dd:MM:YYYY] [hh:mm:ss] message
The logger should also be able to print the messages into the System.out and into a file ?
Where should I look for this functionality ?
Can you please give me some code snippets ?
Extend java.util.logging.Formatter, overide format(LogRecord record) method.
LogRecord contains all data you need to build up your custom message.
Then change standard SimpleFormatter in logging.properties file in properties
java.util.logging.ConsoleHandler.formatter/java.util.logging.FileHandler.formatter
to your formatter.
Have you considered using Log4j?
If that is not an option for you, you could change the output format of the logger you are currently using. The following article shows a way to do just that and provide a custom formatter for the java.util.logging API.
I should also mention that, unless doing this to learn and expand your knowledge, or beeing forced by ugly circumstances, it is never a good idea to write your own logger implementation.
Check this question. I think I was asking a similar one.
A simple log file format
EDIT:
As I wrote there, I found a tool called LogExpert. You can write to a file in a format like "level;dd:MM:YYYY;hh:mm:ss;message" and view it with this tool, changind columnizer to CSV.

How to set javax logger handle to be refactor sensitive

Someone might yell at me to read the faqqing faq, but I'm in a hurry ...
Does anyone have a way to make javax or log4j logger refactor-sensitive?
Say, that currently utils.Something has the logger handle:
final static private Logger logger = Logger.getLogger(Something.class.getName());
And logging.properties has
.level = warning
utils.Something.level=info
Then using Eclipse to refactor Something to
nutilla.Somewhere
resulting in my logger handle and logger property becoming out of sync.
Perhaps, set logging levels programmatically?
Has anyone bothered to do it and was it worth the trouble?
Clarification:
After refactoring utils.Something to nutilla.Somewhere, the logger handle now would only log warning and not info, because of the entry in logging.properties file. So the question is, is there a way to replace the function of logging.properties file with programmatic means and if so, is it worth the trouble?
Reason and Motivation for question
I'm obstinate at not listening when advising me to avoid refactoring because ...
Refactoring is a constant habit of mine. I create classes by the hour, merge them, delete them, extract methods, etc ... I'm a restless class creator who finds no time wondering where to initially place a class. I dislike sitting down wasting time wondering where to place them initially - so I just place them in the most convenient package namespace.
After building a good amount of class/interface structure, it becomes apparent to me where certain classes, interfaces or methods shd have been then all the refactoring activities take place and ... tada ... that's when my logging.properties file is ruined a hundred lines.
If you configure logging using class (as opposed to package) names, checking "Update fully qualified class names in non-Java text files" in eclipse's rename refactoring dialog should do the trick.
I do not think there is a way out of the box that updated the package names and class names in your properties file as a result of refactoring actions.
You can:
update the properties file by hand when refactoring is done (refactoring should be an action that is not undertaken eveery week :=)
use fixed strings to create loggers (make logging more functional instead of physical)
load the properties file and adjust the property names on the basis of constants you declare in your class before initialising log4j with that properties collection
I would go for the first option myself, too much automagic behaviour can get you in a very non-transparent situation quickly.
I wouldn't use it (I think it makes more sense to be careful when refactoring) but here it goes:
private static Logger logger = Logger.getLogger(new Exception().getStackTrace()[0].getClassName());

Categories