Logging additional information with java.util.logging.Logger - java

On my team we have a logging standard, and for the most part the
Logger.log(Level, String, [Throwable])
methods works fine (it gives us automatic timestamp, class name, method name, message, and throwable information in the log). However, we have an additional identifier we log, and it's part of our standard (we use it to help monitor the logs).
My problem is that I want to be able to easily enforce this standard in a fairly painless way. At first we created a wrapper logger class, but the problem is you lose the benefit of Logger knowing which method you are in.
void myLoggerMethod(Level level, String msg, String identifier) {
logger.log(level, identifier + " " + msg);
}
will log things mostly correct, but then it logs the wrong method name. You can use logp to get around this, but then you have to send in the method name as a String and it becomes pretty gross.
Is there a good way to allow people to enter an additional piece of data to log? Is there any extension mechanism that allows this, or something in the API i'm missing?

I don't fully understand your usecase, but you can try to implement a custom Formatter (or Handler) Or you can extend an existing one, like SimpleFormatter / FileHandler.

You could look at it another way and set up code templates in your IDE.
For instance I have my IDE set up to change logdebug, logerror, loginfo to code snippets for my logging.
In my IDE, I type logdebug, hit ctrl+space and it converts it to
if(logger.isDebugEnabled()){
logger.debug("xxx");}
I can then just fill in the message I want.

Related

How to Fix CWE-470: Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')

I got a 470 on a line in my code and rightfully so as defined by Vera.
Vera says to fix:
Apply strict input validation by using whitelists or indirect
selection to ensure that the user is only selecting allowable classes
or code.
So I created a strict whitelist of what class name reflection can have access to as a Set<String>
I then wrapped the Class.forName in an
if (whitelist.contains(className) {
Veracode still fires in here with a 470
}
Anyone know what the fix has to look like for Vera not to fire? I feel I have followed their recommended remediation.
I have managed to resolve it using sanitizer class/method that get className validate and return value from String from hard coded value - for example:
public class MySanitizer {
public static String sanitizeClassName(final String className) throws MyException {
if(!className.equals("com.my.MyClass"))
throw new MyException("Class not valid: " + className);
return "com.my.MyClass";
}
The answer is that all class names must come from a trusted source.
The only trusted source is a hard-coded string in a class file.
Nothing read from properties files, no collection you create and pass into a validation mechanism.
It must see a hard-coded constant "com.dang.this.is.strict.ClassName:" being loaded.
Hard-coded whitelist of strings.
You can have some great validation code to make sure nothing bad is going on, but it will not pass, since not hard coded string. In this situation you mitigate and provide the explanation and hope that it is sufficient for the person(s) reviewing the results.
They do say
Apply strict input validation by using whitelists or indirect
selection to ensure that the user is only selecting allowable classes
or code.
I just didn't realize whitelists were strictly string constants in classes. My mistake was thinking I could build the whitelist in code at run-time. Which sometimes I need to do, so I will be keeping my validator and claim mitigation.

How to refactor logging statements in sibling classes?

As system evolves, the logging statements will be changed to meet the new requirements, and ideally the logging statements which have identical or very similar context should be changed consistently. But in many cases it's hard for developers to remember the existence of all of them. Then they may only change a portion of them, and forget to change the other ones consistently.
Take this Java code snippet as an example, there are two sibling classes (ChildClassA, ChildClassB) which both extend the same superclass (ParentClass), and they have a pair of similar methods which have similar functions and contain the same logging statements.
public class ChildClassA implements ParentClass{
public void processShellCommand(){
...
logger.error("Error initializing command, field " + field.getName() + " is not accessible.");
...
}
public class ChildClassB implements ParentClass{
public void processNetworkCommand(){
...
logger.error("Error initializing command, field " + field.getName() + " is not accessible.");
...
}
Is there a solution such as a tool, or some documents, etc. that can help the consistent changing of them?
When it comes to logging I think you really should try to avoid putting details in the log.[whatever_leve].([message_text]] statement (at least when in comes to errors), instead you want to create your own Exception classes and put message details in them. Have a filter/interceptor for dealing with logging of unexpected exceptions is also a good practice.
So in you code example that would be that the sub-classes thrown a typed Exception, lets call it InitializingException(...). It is then up the the caller or a filter to deal with it and log it.
You want to care about the logging part of your code base in the same way as you do for business-logic code (one can argue it is part of it), so salute DRY (do-not-repeat-yourself).
Same logic applies for Debug and Trace statements as well, you don't want to copy-paste the same message across the system. So general refactoring should be applied to avoid it. But I generally think the a debug or trace message is likely to change (it is up to the developer).

Why do loggers in Java rarely have the .toString() that System.out.println does?

I'm frequently annoyed by having
System.out.println(someObject);
and, when changing it to using whatever logger is required
LOG.info(someObject);
and having to add the .toString() to make it compile
LOG.info(someObject.toString());
I cannot recall having used a logger that does not simply take in an Object and tries do to .toString() on it, making me wonder if there is a specific reason for this. Surely I cannot be the only one annoyed by having to add .toString() to everything?
The key point is to understand the purpose of logging. Loggers are there to print human readable english messages regarding any event that occurs within an application. And the logging API's are built following this basic principle
LOG.info(someObject.toString());
The problem with the above line is that the basic concept of logging is somewhat different from what you are trying to achieve. You want to log an object which is already not a human readable entity and then to make it work by casting it either to a string or you could implement the toString() method or lastly you can take a look at one of the overloaded function
public void info(String format, Object... arguments)
Logging an object directly is mostly done by developers when they want to debug to lets say the contents of the object or something like that, so the best way to achieve that would be to correctly implement the toString() method.
I would also advise to take a look into the Project Lombok, it provides ready to use implementations of common hashCode() and toString() functions of your beans so you don't have to go through your code and implement the method one by one.

Implementing logger for java application

I am trying to implement logger using apache commonn logging and log4j.xml file as configuration file .
So in the actual java code i am writing log as
I am using appache common logging
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
and i am logging information such as in . I am creating a instance of log for each class
private static Log logger = LogFactory.getLog( MyClass.class );
private static final String name ="SAM";
logger.info("name= "+name);
So now my question is does implementing logger like this create a performanace issue?
Is it necessary to check log like
if ( log.isInfoEnabled( ) )
{
log.info( "Info message" );
}
The confusion is mainly because in Apache common logging they have mentioned to do this and in log4j they have mentioned it is unnecessary.
Each time when we write log in the files?
-Sam
yes and no, logging always reduces your performance, but some functions are more expensive then others, e.g. getting the calling class/method-Name uses reflection and is very slow. But a normal logfuntion is not that expensive if you do not have an expensive statement in the calling logging function (this will be evaluated every time before the log-Level is checked. In this case you can use the .isLevelEnabledcheck to prevent the evaluation). Also logging to the console takes longer for the output than logging to a file. You will find more information about this by googling and in the FAQ/manual of log4j.
You do not have to check the Log-Level before logging. This is done within the log-function itself. Therefore are the different methods for every Level or the Level-Argument in the generic log-Method.
A big potential performance problem with logging is usually if you have something passed into the log method that is very expensive to convert to a string. That's why you have methods like isInfoEnabled(), so that the code can avoid creating the message string from the parameter (otherwise the check within the info() method is too late, the conversion is already done). If your objects passed into the log methods are strings or are not very involved then the is*Enabled() methods won't be that useful.
SLF4J is worth checking out. It doesn't depend on classloader tricks (which is a big part of why commons-logging is reviled), and it has a different way of creating log messages which delays when the message string gets created so that the enabled check can take place within the logging method.
There's a better way to do all of this. You can get really great performance without having to add the clutter of ifDebugEnabled, etc methods. Check out something like Logback (or SLF4J). Here's the great documentation about what kind of an API you want. Note that Log4J and Commons-Logging doesn't have an API like this. Use Parameterized Logging.

How do I avoid unwanted log messages on java project?

On my java project, I have a bunch of strings externalized on a messages.properties file. On its respective Messages.java file I had the same number of public static String-typed attributes, so I could access those externalized texts.
Then, I implemented a method called getString, which receives the name of the constant as its argument and returns the wanted text. This way, there is no need to declare all the public static Strings-typed attributes inside the Messages.java file.
But after doing this my log became filled with "NLS unused message" messages.
Do you know if there's a way to prevent those warning messages to be logged?
Thanks in advance.
Your Messages class - it sounds like it extends org.eclipse.osgi.util.NLS.
If this is the case, it is designed to fill the requirements:
to provide compile time checking that a message exists.
to avoid the memory usage of a map containing both keys and values (this would be the case in a resource bundle approach).
good i18n support.
i.e. NLS populates the value of the Message.staticVariable with the value of the staticVariable found in messages.properties.
The warning logging provides information about a mismatch between the Messages.java and the messages.properties file.
Your getString() method sounds like it does not use any of the advantages of NLS, so as others have suggested, you may be better off using a ResourceBundle.
Messages sounds like a class you wrote, because I don't see it in my JDK 6 javadocs.
It sounds like you've tried to reinvent java.util.ResourceBundle. I'd recommend using that instead and ditching your class. It'll have the added advantage of handling I18N properly.
I don't see any value in hard-coding the public static message keys in the class. It's just another thing you'll have to maintain. If I understand what you're doing properly, I'd throw away your Messages and use ResourceBundle instead.
duffymo, as jamesh said, Messages is a class I wrote, and it extends org.eclipse.osgi.util.NLS. It has a private static attribute, and its type is... ResourceBundle!
jamesh, thanks for detailing the way NLS works.
Based on your answers I removed my Messages class from my project and added a ResourceBundle-typed attribute on the classes that need to use the externalized strings. Plus, I did it in a way that the lines accessing the externalized strings did not need to be changed.
The number of files on our project has been reduced, the code was kept as clean as before and there are no more log warnings.
Thank you, guys. You rock.

Categories