Logging parametrized logs while maintaining readability
https://softwareengineering.stackexchange.com/questions/364500
-
26-01-2021 - |
Question
I have a LogFormatter
class which looks like below
@Sl4j
class LogFormatter {
public static String format(String taskType, String taskId, String message) {
return String.format("TaskType: %s, TaskId: %s, Message: %s",
taskType, taskId, message);
}
Mostly there are 4 types of tasks but can grow to more in future. Most classes are dedicated to one of the four task types.
Now every time, I have to get a log line out, I need to call this logFormatter and a typical log line looks like below -
log.info(LogFormatter.format(
"StackOverflowTask",
"StackOverflowId",
"A long long message exceeding 50 characters"));
Each such log line breaks the code readability for the reader. At the least, I would like to keep this log line short enough to a single line.
One of the ways is to somehow let LogFormatter
method call understand the task type to save repetition in every line.
I have two paths to follow -
One is to create separate classes for each task type like
class StackOverflowTaskLogFormatter extends LogFormatter
OR
create separate methods like
public void formatStackOverflowTaskLog()
First solution to me looks better because I can introduce more such classes without modifying existing ones (Open-Closed Principle) and the signature of method format
will remain same. But I am still not content to write so many classes and then many more @Autowired
s in each class, creating class bloatware. Also, I can clearly see that such kind of specialisation also increases class/method length and beats the original intended purpose behind their creation.
I am keen to understand if there are better ways to maintain code readability in above situation.
Solution
Let's say you have an interface that represents a task, and every task in your system implements that interface:
public interface Task {
String getId();
String getType();
}
Now your LogFormatter
can be simplified into taking 2 parameters:
@Sl4j
class LogFormatter {
public static String format(Task task, String message) {
return String.format("Task type: %s, Task Id: %s, Message: %s",
task.getType(), task.getId(), message);
}
}
Your log entry should be a bit more readable since you can simply reference your task object.
Logging from inside the object:
log.info(LogFormatter.format(this, "A long long message exceeding 50 characters"));
Logging from outside the object:
log.info(LogFormatter.format(taskObject, "A long long message exceeding 50 characters"));
Another option is to import your formatting functions statically:
import static LogFormatter.*;
// code follows inside the object...
log.info(format(this, "A long long message exceeding 50 characters"));
Neither of those deviate too far from your current design and work with just about any logging framework.