SolrJetty logging - how to get custom log formatter to work? - java

I have a Solr server on Linux running under Jetty 6 and am trying to set up a custom formatter for java logging however I can't seem to get it to recognize my custom class. I am new to Java so it is quote possible it is an issue with how I am exporting my class or something like that. Note this is almost the same question as can be found here, however the answer there does not help since I do have a public no-parameter constructor.
My formatter looks like the following (as described here):
package myapp.solr;
import java.text.MessageFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
public class LogFormatter extends Formatter {
private static final MessageFormat fmt = new MessageFormat("{0,date,yyyy-MM-dd HH:mm:ss} {1} [{2}] {3}\n");
public LogFormatter() {
super();
}
#Override public String format(LogRecord record) {
Object[] args = new Object[5];
args[0] = new Date(record.getMillis());
args[1] = record.getLevel();
args[2] = record.getLoggerName() == null ? "root" : record.getLoggerName();
args[3] = record.getMessage();
return fmt.format(args);
}
}
In my logging.properties file I then have the below (as well as properties to configure the file path/pattern and rotation limit and count) :
handlers = java.util.logging.FileHandler
java.util.logging.FileHandler.formatter = myapp.solr.LogFormatter
I then export my class into myapp.jar and put it in the lib/ext folder in jetty.home (I also tried placing it directly under lib and I tried specifying the path to it with the -Djetty.class.path parameter). However when I run my solr app it still uses the XmlFormatter instead. I am able to successfully change it to use the SimpleFormatter, just not my own custom formatter.
I also created a test class that imports my LogFormatter, creates an instance variable and calls the format method and prints the result to the console and that worked without any issues from within Eclipse.
If it helps, the command I am using to start up Solr/Jetty is:
nohup java -DSTOP.PORT=8079 -DSTOP.KEY=secret -Dsolr.solr.home=../solr_home/local -Djava.util.config.file=../solr_home/local/logging.properties -jar start.jar > /var/log/solr/stdout.log 2&>1 &
So what am I doing wrong, why won't it use my custom formatter?

Got it working thanks to some useful suggestions here. The problem was that the java logging is set up before the custom class is loaded from the lib or lib/ext folders so I needed to add it into the start.jar.
How I did that was I created a new package of my own that I called org.mortbay.start and added my custom LogFormatter class to that. Eclipse automatically built the LogFormatter.class from that in the bin/org/mortbay/start folder. I then opened the start.jar archive up and added my custom class into it so I had start.jar/org/mortbay/start/LogFormatter.class. Once that was there I was then able to set my formatter using:
handlers = java.util.logging.FileHandler
java.util.logging.FileHandler.formatter = org.mortbay.start.LogFormatter

Related

java jar arguments for swing application [duplicate]

What is a good way of parsing command line arguments in Java?
Check these out:
http://commons.apache.org/cli/
http://www.martiansoftware.com/jsap/
Or roll your own:
http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
For instance, this is how you use commons-cli to parse 2 string arguments:
import org.apache.commons.cli.*;
public class Main {
public static void main(String[] args) throws Exception {
Options options = new Options();
Option input = new Option("i", "input", true, "input file path");
input.setRequired(true);
options.addOption(input);
Option output = new Option("o", "output", true, "output file");
output.setRequired(true);
options.addOption(output);
CommandLineParser parser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();
CommandLine cmd = null;//not a good practice, it serves it purpose
try {
cmd = parser.parse(options, args);
} catch (ParseException e) {
System.out.println(e.getMessage());
formatter.printHelp("utility-name", options);
System.exit(1);
}
String inputFilePath = cmd.getOptionValue("input");
String outputFilePath = cmd.getOptionValue("output");
System.out.println(inputFilePath);
System.out.println(outputFilePath);
}
}
usage from command line:
$> java -jar target/my-utility.jar -i asd
Missing required option: o
usage: utility-name
-i,--input <arg> input file path
-o,--output <arg> output file
Take a look at the more recent JCommander.
I created it. I’m happy to receive questions or feature requests.
I have been trying to maintain a list of Java CLI parsers.
Airline
Active Fork: https://github.com/rvesse/airline
argparse4j
argparser
args4j
clajr
cli-parser
CmdLn
Commandline
DocOpt.java
dolphin getopt
DPML CLI (Jakarta Commons CLI2 fork)
Dr. Matthias Laux
Jakarta Commons CLI
jargo
jargp
jargs
java-getopt
jbock
JCLAP
jcmdline
jcommander
jcommando
jewelcli (written by me)
JOpt simple
jsap
naturalcli
Object Mentor CLI article (more about refactoring and TDD)
parse-cmd
ritopt
Rop
TE-Code Command
picocli has ANSI colorized usage help and autocomplete
It is 2022, time to do better than Commons CLI... :-)
Should you build your own Java command line parser, or use a library?
Many small utility-like applications probably roll their own command line parsing to avoid the additional external dependency. picocli may be an interesting alternative.
Picocli is a modern library and framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It lives in 1 source file so apps can include it as source to avoid adding a dependency.
It supports colors, autocompletion, subcommands, and more. Written in Java, usable from Groovy, Kotlin, Scala, etc.
Features:
Annotation based: declarative, avoids duplication and expresses programmer intent
Convenient: parse user input and run your business logic with one line of code
Strongly typed everything - command line options as well as positional parameters
POSIX clustered short options (<command> -xvfInputFile as well as <command> -x -v -f InputFile)
Fine-grained control: an arity model that allows a minimum, maximum and variable number of parameters, e.g, "1..*", "3..5"
Subcommands (can be nested to arbitrary depth)
Feature-rich: composable arg groups, splitting quoted args, repeatable subcommands, and many more
User-friendly: usage help message uses colors to contrast important elements like option names from the rest of the usage help to reduce the cognitive load on the user
Distribute your app as a GraalVM native image
Works with Java 5 and higher
Extensive and meticulous documentation
The usage help message is easy to customize with annotations (without programming). For example:
(source)
I couldn't resist adding one more screenshot to show what usage help messages are possible. Usage help is the face of your application, so be creative and have fun!
Disclaimer: I created picocli. Feedback or questions very welcome.
Someone pointed me to args4j lately which is annotation based. I really like it!
I've used JOpt and found it quite handy: http://jopt-simple.sourceforge.net/
The front page also provides a list of about 8 alternative libraries, check them out and pick the one that most suits your needs.
I know most people here are going to find 10 million reasons why they dislike my way, but nevermind. I like to keep things simple, so I just separate the key from the value using a '=' and store them in a HashMap like this:
Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
String[] parts = arg.split("=");
argsMap.put(parts[0], parts[1]);
}
You could always maintain a list with the arguments you are expecting, to help the user in case he forgot an argument or used a wrong one... However, if you want too many features this solution is not for you anyway.
This is Google's command line parsing library open-sourced as part of the Bazel project. Personally I think it's the best one out there, and far easier than Apache CLI.
https://github.com/pcj/google-options
Installation
Bazel
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
sha1 = "85d54fe6771e5ff0d54827b0a3315c3e12fdd0c7",
)
Gradle
dependencies {
compile 'com.github.pcj:google-options:1.0.0'
}
Maven
<dependency>
<groupId>com.github.pcj</groupId>
<artifactId>google-options</artifactId>
<version>1.0.0</version>
</dependency>
Usage
Create a class that extends OptionsBase and defines your #Option(s).
package example;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;
import java.util.List;
/**
* Command-line options definition for example server.
*/
public class ServerOptions extends OptionsBase {
#Option(
name = "help",
abbrev = 'h',
help = "Prints usage info.",
defaultValue = "true"
)
public boolean help;
#Option(
name = "host",
abbrev = 'o',
help = "The server host.",
category = "startup",
defaultValue = ""
)
public String host;
#Option(
name = "port",
abbrev = 'p',
help = "The server port.",
category = "startup",
defaultValue = "8080"
)
public int port;
#Option(
name = "dir",
abbrev = 'd',
help = "Name of directory to serve static files.",
category = "startup",
allowMultiple = true,
defaultValue = ""
)
public List<String> dirs;
}
Parse the arguments and use them.
package example;
import com.google.devtools.common.options.OptionsParser;
import java.util.Collections;
public class Server {
public static void main(String[] args) {
OptionsParser parser = OptionsParser.newOptionsParser(ServerOptions.class);
parser.parseAndExitUponError(args);
ServerOptions options = parser.getOptions(ServerOptions.class);
if (options.host.isEmpty() || options.port < 0 || options.dirs.isEmpty()) {
printUsage(parser);
return;
}
System.out.format("Starting server at %s:%d...\n", options.host, options.port);
for (String dirname : options.dirs) {
System.out.format("\\--> Serving static files at <%s>\n", dirname);
}
}
private static void printUsage(OptionsParser parser) {
System.out.println("Usage: java -jar server.jar OPTIONS");
System.out.println(parser.describeOptions(Collections.<String, String>emptyMap(),
OptionsParser.HelpVerbosity.LONG));
}
}
https://github.com/pcj/google-options
Take a look at the Commons CLI project, lots of good stuff in there.
Yeap.
I think you're looking for something like this:
http://commons.apache.org/cli
The Apache Commons CLI library provides an API for processing command line interfaces.
If you are already using Spring Boot, argument parsing comes out of the box.
If you want to run something after startup, implement the ApplicationRunner interface:
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(ApplicationArguments args) {
args.containsOption("my-flag-option"); // test if --my-flag-option was set
args.getOptionValues("my-option"); // returns values of --my-option=value1 --my-option=value2
args.getOptionNames(); // returns a list of all available options
// do something with your args
}
}
Your run method will be invoked after the context has started up successfully.
If you need access to the arguments before you fire up your application context, you can just simply parse the application arguments manually:
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
ApplicationArguments arguments = new DefaultApplicationArguments(args);
// do whatever you like with your arguments
// see above ...
SpringApplication.run(Application.class, args);
}
}
And finally, if you need access to your arguments in a bean, just inject the ApplicationArguments:
#Component
public class MyBean {
#Autowired
private ApplicationArguments arguments;
// ...
}
Maybe these
JArgs command line option parsing
suite for Java - this tiny project provides a convenient, compact, pre-packaged and comprehensively documented suite of command line option parsers for the use of Java programmers. Initially, parsing compatible with GNU-style 'getopt' is provided.
ritopt, The Ultimate Options Parser for Java - Although, several command line option standards have been preposed, ritopt follows the conventions prescribed in the opt package.
I wrote another one: http://argparse4j.sourceforge.net/
Argparse4j is a command line argument parser library for Java, based on Python's argparse.
If you are familiar with gnu getopt, there is a Java port at: http://www.urbanophile.com/arenn/hacking/download.htm.
There appears to be a some classes that do this:
http://docs.sun.com/source/816-5618-10/netscape/ldap/util/GetOpt.html
http://xml.apache.org/xalan-j/apidocs/org/apache/xalan/xsltc/cmdline/getopt/GetOpt.html
airline # Github looks good. It is based on annotation and is trying to emulate Git command line structures.
Argparse4j is best I have found. It mimics Python's argparse libary which is very convenient and powerful.
I want to show you my implementation: ReadyCLI
Advantages:
for lazy programmers: a very small number of classes to learn, just see the two small examples on the README in the repository and you are already at 90% of learning; just start coding your CLI/Parser without any other knowledge;
ReadyCLI allows coding CLIs in the most natural way;
it is designed with Developer Experience in mind; it largely uses the Builder design pattern and functional interfaces for Lambda Expressions, to allow a very quick coding;
it supports Options, Flags and Sub-Commands;
it allows to parse arguments from command-line and to build more complex and interactive CLIs;
a CLI can be started on Standard I/O just as easily as on any other I/O interface, such as sockets;
it gives great support for documentation of commands.
I developed this project as I needed new features (options, flag, sub-commands) and that could be used in the simplest possible way in my projects.
If you want something lightweight (jar size ~ 20 kb) and simple to use, you can try argument-parser. It can be used in most of the use cases, supports specifying arrays in the argument and has no dependency on any other library. It works for Java 1.5 or above. Below excerpt shows an example on how to use it:
public static void main(String[] args) {
String usage = "--day|-d day --mon|-m month [--year|-y year][--dir|-ds directoriesToSearch]";
ArgumentParser argParser = new ArgumentParser(usage, InputData.class);
InputData inputData = (InputData) argParser.parse(args);
showData(inputData);
new StatsGenerator().generateStats(inputData);
}
More examples can be found here
As one of the comments mentioned earlier (https://github.com/pcj/google-options) would be a good choice to start with.
One thing I want to add-on is:
1) If you run into some parser reflection error, please try use a newer version of the guava. in my case:
maven_jar(
name = "com_google_guava_guava",
artifact = "com.google.guava:guava:19.0",
server = "maven2_server",
)
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
server = "maven2_server",
)
maven_server(
name = "maven2_server",
url = "http://central.maven.org/maven2/",
)
2) When running the commandline:
bazel run path/to/your:project -- --var1 something --var2 something -v something
3) When you need the usage help, just type:
bazel run path/to/your:project -- --help
Take a look at Spring Shell
Spring Shell’s features include
A simple, annotation driven, programming model to contribute custom commands
Use of Spring Boot auto-configuration functionality as the basis for a command plugin strategy
Tab completion, colorization, and script execution
Customization of command prompt, shell history file name, handling of results and errors
Dynamic enablement of commands based on domain specific criteria
Integration with the bean validation API
Already built-in commands, such as clear screen, gorgeous help, exit
ASCII art Tables, with formatting, alignment, fancy borders, etc.
For Spring users, we should mention also https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html and his twin brother https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/JOptCommandLinePropertySource.html (JOpt implementation of the same functionality).
The advantage in Spring is that you can directly bind the command line arguments to attributes, there is an example here https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/CommandLinePropertySource.html

Execute .jar file in Spoon (Pentaho Kettle)

I need to execute a java jar file from Spoon.
The program has only one class, and all I want is to run it with or without parameters.
The class is named "Limpieza", and is inside a package named:
com.overflow.csv.clean
I have deploy the jar to:
C:\Program Files (x86)\Kettle\data-integration\lib
And from a Modified JavaScriptValue step, I am calling it this way:
var jar = com.everis.csv.clean.Limpieza;
This is not working at all, is there a way around to make it work?
Also would be nice to have a way to see the logs printed by the program when it runs.
I am not getting any error when I run the transformation.
Thanks.
Check the blog below:
https://anotherreeshu.wordpress.com/2015/02/07/using-external-jars-import-in-pentaho-data-integration/
Hope this might help :)
Spoon will load any jar files present in its
data-integration\lib
folder and its subfolders during startup, so if you want to access classes from a custom jar, you could place the jar here.
So you need to create a custom jar and place the jar in
data-integration\lib
location.
While calling a custom class in "Modified Java Script Value" or in "User Defined Java Class step" you should call with fully qualified name. For example var jar = com.everis.csv.clean.Limpieza.getInstance().getMyString();
Note: After placing the jar, make sure you restart the Spoon.
If still does not work please attach the Pentaho.log (data-integration-server/logs/Pentaho.log) and catalina.out(data-integration-server/tomcat/logs) logs
The answer was to create a User Defined Java Class (follow the guide Rishu pointed), and here is my working code:
import java.util.*;
import com.everis.csv.Cleaner;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
Cleaner c = new Cleaner();
c.clean();
// The rest of it is for making it work
// You will also need to make a Generate Rows step that inputs a row to this step.
Object[] r = getRow();
if (r == null) {
setOutputDone();
return false;
}
r = createOutputRow(r, data.outputRowMeta.size());
putRow(data.outputRowMeta, r);
return true;
}

this.getClass().getResource("").getPath() returns an incorrect path

I am currently making a small simple Java program for my Computer Science Final, which needs to get the path of the current running class. The class files are in the C:\2013\game\ folder.
To get this path, I call this code segment in my main class constructor:
public game(){
String testPath = this.getClass().getResource("").getPath();
//Rest of game
}
However, this command instead returns this String: "/" despite the correct output being "C:/2013/game"
Additionally, I attempted to rectify this by using this code:
public game(){
String testPath = this.getClass().getClassLoader().getResource("").getPath();
}
This returns a NullPointerException, which originates from the fact that getClassLoader() returns null, despite working on my Eclipse IDE. Any Ideas?
If you want to load a file in the same path as the code then I suggest you put it in the same root folder as the code and not the same path as the class.
Reason : class can be inside a jar, data file can be put in same jar but its more difficult to edit and update then.
Also suggest you see the preferences class suggested in comments : http://www.javacodegeeks.com/2011/09/use-javautilprefspreferences-instead-of.html though in some cases I think its okay to have your own data/ excel/csv/ java.util.Properties file
Not sure about why it is working in eclipse but I would suggest you focus on running it from a command prompt/ terminal as that is the 'real mode' when it goes live
You could just ask for your class
String s = getClass().getName();
int i = s.lastIndexOf(".");
if(i > -1) s = s.substring(i + 1);
s = s + ".class";
System.out.println("name " +s);
Object testPath = this.getClass().getResource(s);
System.out.println(testPath);
This will give you
name TstPath.class
file:/java/Projects/tests3b/build/classes/s/TstPath.class
Which is my eclipse build path ...
need to parse this to get the path where the class was loaded.
Remember:
App could be started from elsewhere
class can be in jar then path will be different (will point to a jar and file inside that
classpaths can be many at runtime and point 1
a class might be made at runtime via network/ Proxy / injection etc and thus not have a file source, so this is not a generic solution.
think what you want to acheive at a higher level and post that question. meaning why do you want this path?
do you want the app path :-
File f = new File("./");
f.getCanonicalPath();//...
So an app can be started from folder c:\app1\run\
The jar could be at c:\app1\libsMain\myapp.jar
and a helper jar could be at c:\commonlibs\set1
So this will only tell you where the JVM found your class, that may or maynot be what you need.
if inside a jar will give you some thing like this in unix or windows
jar:file:c:\app\my.jar!/s/TstPath.class
If package is s and class is TstPath, you can be sure this will work as the class has to be there ...
now to parse this you can look for your class name and remove / or \ till you get path you want. String lastIndexOf will help
You can use :
URL classURL = getClass().getProtectionDomain().getCodeSource().getLocation();
The call to getResource([String]) requires a path relative to the folder that contains the class it is being called from. So, if you have the following, anything you pass into MyClass.class.getResource([path]); must be a valid path relative to the com/putable/ package folder and it must point to a real file:
package com.putable;
public class MyClass{}
Using the empty string simply isn't valid, because there can never be a file name that equals the empty string. But, you could do getResource(getClass().getSimpleName()). Just remove the file name from the end of the path returned by that call and you will have the class directory you want.
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("Test.class"));
also
Test.class.getProtectionDomain().getCodeSource().getLocation().getPath());
Try this.
import java.io.File;
public class TT {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String path = TT.class.getResource("").getPath();
File file = new File(path);
System.out.println(file.getAbsolutePath());
}
}
Try use this code
public game()
{
String className = this.getClass().getSimpleName();
String testPath = this.getClass().getResource(className+".class");
System.out.println("Current Running Location is :"+testPath);
}
visit the link for more information
Find where java class is loaded from
Print out absolute path for a file in your classpath i.e. build/resources/main/someFileInClassPath.txt Disclaimer, this is similar to another solution on this page that used TT.class..., but this did not work for me instead TT..getClassLoader()... did work for me.
import java.io.File;
public class TT {
/**
* #param args
*/
public static void main(String[] args) {
String path = TT.getClassLoader().getResource("someFileInClassPath.txt").getPath();
File file = new File(path);
System.out.println(file.getAbsolutePath());
}
}
Because you used class.getResource(filePath).getpath() in a *.jar file. So the path includes "!". If you want to get content of file in *.jar file, use the following code:
MyClass.class.getResourceAsStream("/path/fileName")

How to add a line in all java files in eclipse

I am not sure if that is possible but I have a old java application projects which have 1000+ java files. I am trying to add log4j support to the application which require me to add
public static Logger logger = Logger.getLogger(MyClass.class.getName());
in every file.
Is there any way I can perform the operation using eclipse. I have tried source->format but that is not allowing me to add the line. Do I have to open every file and add that line?
You could make use of templates in eclipse, but in this case, you need to edit each file and add it.
Update :
Save following content in some file-named with extension ".xml"
<?xml version="1.0" encoding="UTF-8" standalone="no"?><templates><template autoinsert="true" context="java-members" deleted="false" description="adds the logger statement" enabled="true" name="logger">public static Logger logger = Logger.getLogger(${enclosing_type}.class.getName());</template></templates>
Press CTRL+3, Type - "templates" and choose for Templates- Java Editor as shown below
Import the file from menu from right as shown below
now go to any of your file and type "logger"in your class file and do CTRL+space , quick assist will show you the "logger" template
as shown below
and your logging statement will appear, with your class in which you are editing as shown below
You can do it programatically. Start with a filter for all your .java:
public class FileExtensionFilter implements FilenameFilter {
private Set<String> filteredExtensions;
public FileExtensionFilter() {
filteredExtensions = new HashSet<String>();
}
#Override
public boolean accept(File dir, String name) {
boolean accept = true;
for (String filteredExtension:filteredExtensions) {
accept = accept && !name.endsWith(filteredExtension);
}
return accept;
}
public void addFilteredExtension(String extension) {
filteredExtensions.add(extension);
}
}
Then you can look for the file using a recursive method:
public Set<String> searchFileBasedOnExtension(File file) {
Set<String> extensions = new HashSet<String>();
if (file.isDirectory()) {
for (File f : file.listFiles(fileExtensionFilter)) {
extensions.addAll(checkForExtensions(f));
}
} else {
String extension = file.getName().substring(Math.max(file.getName().lastIndexOf('.'),0));
extensions.add(extension);
fileExtensionFilter.addFilteredExtension(extension);
}
return extensions;
}
Then based on the set you receive, you can iterate it, read the file to find the position to add the "import" and also find the class name, and save it into a variable to replace it for each file, since each file represents a different class.
Sample:
for (String s : setWithFileNames) {
// Use BufferedReader to read the file, save the content in a String, then look inside the String the classname and the first import position.
// Use bufferedWriter to re-write the file with the changes you made.
}
Hope it gives you a hand with your requirement. Best regards.
Opening each file and adding this line would be tedious.
I am not sure if Eclipse has such thing.
But I would suggest to go for a shell script or a Java function to do this.
Read each file.
Search for the first '{' character.
Insert the logger statement in the line next to that.
You can get the class name from the file name.
I know this might not be the best solution for you.
Hope this helps.
If you have notepad ++ you can do it. Use the find replace feature for a direcory using regular expressions.
so a line starting with public class need to be replaced by the line and another line with the log statement.
Another suggestion is to use AspectJ. AspectJ is an extension to Java that allows you to systematically weave in extra functionality to existing classes. You would first need to install AJDT (AspectJ development tools). Then you need to create an Aspect like this:
aspect LoggingAspect {
before (Object thiz) : execution(public * *(..)) && this(thiz) {
Logger logger = Logger.getLogger(thiz.getClass().getName());
logger.log("Something");
}
}
The aspect above will log every execution of a public method of one of the classes that you compile. You can certainly tweak this in many ways. Logging is one of the simplest things that AspectJ can do. The nice thing about going down this path is that you can easily enable/disable logging from your project by commenting out 4 lines.
The main AspectJ website. And the AspectJ programming guide is a good place to start with AspectJ.
You can run the below command to add any line on the specific line number, Just provide the folder name it will search all the subfolders with the file extension as .java and add the line on the specific position:
find <Folder Path> -name "*.java" -exec sed -i '1i<Text: You want to add>' {} \;

How do I set log4j level on the command line?

I want to add some log.debug statements to a class I'm working on, and I'd like to see that in output when running the test. I'd like to override the log4j properties on the command line, with something like this:
-Dlog4j.logger.com.mypackage.Thingie=DEBUG
I do this kind of thing frequently. I am specifically only interested in a way to pass this on the command line. I know how to do it with a config file, and that doesn't suit my workflow.
As part of your jvm arguments you can set -Dlog4j.configuration=file:"<FILE_PATH>". Where FILE_PATH is the path of your log4j.properties file.
Please note that as of log4j2, the new system variable to use is log4j.configurationFile and you put in the actual path to the file (i.e. without the file: prefix) and it will automatically load the factory based on the extension of the configuration file:
-Dlog4j.configurationFile=/path/to/log4jconfig.{ext}
These answers actually dissuaded me from trying the simplest possible thing! Simply specify a threshold for an appender (say, "console") in your log4j.configuration like so:
log4j.appender.console.threshold=${my.logging.threshold}
Then, on the command line, include the system property -Dlog4j.info -Dmy.logging.threshold=INFO. I assume that any other property can be parameterized in this way, but this is the easiest way to raise or lower the logging level globally.
With Log4j2, this can be achieved using the following utility method added to your code.
private static void setLogLevel() {
if (Boolean.getBoolean("log4j.debug")) {
Configurator.setLevel(System.getProperty("log4j.logger"), Level.DEBUG);
}
}
You need these imports
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
Now invoke the setLogLevel method in your main() or whereever appropriate and pass command line params -Dlog4j.logger=com.mypackage.Thingie and -Dlog4j.debug=true.
log4j does not support this directly.
As you do not want a configuration file, you most likely use programmatic configuration. I would suggest that you look into scanning all the system properties, and explicitly program what you want based on this.
Based on Thorbjørn Ravn Andersens suggestion I wrote some code that makes this work
Add the following early in the main method and it is now possible to set the log level from the comand line. This have been tested in a project of mine but I'm new to log4j and might have made some mistake. If so please correct me.
Logger.getRootLogger().setLevel(Level.WARN);
HashMap<String,Level> logLevels=new HashMap<String,Level>();
logLevels.put("ALL",Level.ALL);
logLevels.put("TRACE",Level.TRACE);
logLevels.put("DEBUG",Level.DEBUG);
logLevels.put("INFO",Level.INFO);
logLevels.put("WARN",Level.WARN);
logLevels.put("ERROR",Level.ERROR);
logLevels.put("FATAL",Level.FATAL);
logLevels.put("OFF",Level.OFF);
for(String name:System.getProperties().stringPropertyNames()){
String logger="log4j.logger.";
if(name.startsWith(logger)){
String loggerName=name.substring(logger.length());
String loggerValue=System.getProperty(name);
if(logLevels.containsKey(loggerValue))
Logger.getLogger(loggerName).setLevel(logLevels.get(loggerValue));
else
Logger.getRootLogger().warn("unknown log4j logg level on comand line: "+loggerValue);
}
}
In my pretty standard setup I've been seeing the following work well when passed in as VM Option (commandline before class in Java, or VM Option in an IDE):
-Droot.log.level=TRACE
Based on #lijat, here is a simplified implementation. In my spring-based application I simply load this as a bean.
public static void configureLog4jFromSystemProperties()
{
final String LOGGER_PREFIX = "log4j.logger.";
for(String propertyName : System.getProperties().stringPropertyNames())
{
if (propertyName.startsWith(LOGGER_PREFIX)) {
String loggerName = propertyName.substring(LOGGER_PREFIX.length());
String levelName = System.getProperty(propertyName, "");
Level level = Level.toLevel(levelName); // defaults to DEBUG
if (!"".equals(levelName) && !levelName.toUpperCase().equals(level.toString())) {
logger.error("Skipping unrecognized log4j log level " + levelName + ": -D" + propertyName + "=" + levelName);
continue;
}
logger.info("Setting " + loggerName + " => " + level.toString());
Logger.getLogger(loggerName).setLevel(level);
}
}
}

Categories

Resources