patternjavaMinor
Logging using function as decorator in Guava
Viewed 0 times
loggingfunctionguavausingdecorator
Problem
I needed to add a logger into my flow based on
Of course the natural solution for this problem is to use the decorator pattern, so I created something like this:
Is this code a good way to solve my problem? Is there a better way to do this?
FluentIterable from the Guava library. I have a lot of functions and in some cases I would like to add logging when in other cases (for the same function) I would not. Of course the natural solution for this problem is to use the decorator pattern, so I created something like this:
/**
* Decorator function that add logging into function passed as parameter.
*
* @param input type
* @param output type.
*/
public class DecoratorLoggerInfoFunc implements Function {
/**
* Original function
*/
private final Function function;
/**
* Current logger.
*/
private final Logger logger;
/**
* "Builder" that takes function and return function decorated by logger.
*
* @param function function to decorate.
* @param input type
* @param output type
* @return function with logger.
*/
public static Function of(Function function) {
checkNotNull(function, "Function to decorate cannot be null");
return new DecoratorLoggerInfoFunc(function);
}
/**
* Initialize logger!
*
* @param function original function.
*/
private DecoratorLoggerInfoFunc(Function function) {
this.function = function;
this.logger = LoggerFactory.getLogger(function.getClass());
}
/**
* Flow:
*
* Call original function
* Log input and output
* Return output of original function
*
*
* @param input
* @return
*/
@Override
public O apply(I input) {
O output = function.apply(input);
logger.info("Input is {} Output is {}", input, output);
return output;
}
}Is this code a good way to solve my problem? Is there a better way to do this?
Solution
The concept seems fine to me. The problem is that you will still need to decide whether to decorate, or not decorate the function, and that is done outside the function. That makes it a once-per-create decision, which is OK, but you may still end up with a lot of conditions in your code:
The actual apply method is not very robust though. I would include logging of any potential exceptions that are not declared to be thrown on the function itself...:
Function f = logFunction() ? new DecoratorLoggerInfoFunc(f) : f;The actual apply method is not very robust though. I would include logging of any potential exceptions that are not declared to be thrown on the function itself...:
public O apply(I input) {
try {
O output = function.apply(input);
logger.info("Input is {} Output is {}", input, output);
return output;
} catch (RuntimeException e) {
logger.warn("Exception running with input {}", input, e);
throw e;
}
}Code Snippets
Function f = logFunction() ? new DecoratorLoggerInfoFunc(f) : f;public O apply(I input) {
try {
O output = function.apply(input);
logger.info("Input is {} Output is {}", input, output);
return output;
} catch (RuntimeException e) {
logger.warn("Exception running with input {}", input, e);
throw e;
}
}Context
StackExchange Code Review Q#64232, answer score: 5
Revisions (0)
No revisions yet.