Logging also deserves same love and care as other functional requirement

Deepti Mittal
3 min readDec 5, 2020
Right logs can help automate deubugging in production
Photo by C M on Unsplash

In any application logs are first tool to analyse production issues and are best friend for the person in production support.

In today’s world logs are helpful in data analytics and figuring out usage patterns as well hence logging has become business requirement as well and not just functional.

Having logs statements while developing functionality can help in deciding right levels of logs so should be baked in from start in codebase.

Its difficult to decide right balance in logging because as a support person I would like to know every small detail possible to debug the issues but too much logs end up consuming lots of resources and can slow down application as well.

Logging levels

To have balanced logging there are 5 logging levels defined which handles both of below logging requirements:

Application is all ok and has been doing what needs to be done.

Application needs help immediately and can show you what all has gone wrong with it right now to get started with RCA.

Here is how you decide on correct logging levels:

FATAL: This is raised when application is about to abort which can result in a big business loss or can cause some kind of corruption. Support person should be notified immediately about it.

ERROR: Serious issue with error and it cannot complete the operation any further. Something like not able to reach DB or file server, or data corruption. This will also require immediate attention.

WARN: This is more like warning from application about some situation which is not usual. Something like retry connection because it did not happen first time. This will require someone to do RCA later if not immediate.

DEBUG: These logs will have granular technical information like data details, diagnostic information. These logs should help developers to debug issues.

TRACE: At this level, you’re basically looking to capture every detail you possibly can about the application’s behaviour. This is likely to consume lot of resources in production and is seriously diagnostic.

INFO: These logs are to tell you that things are going as expected in application. Business logs can also come at this level.

Log messages in field value format

Tools like Splunk and ELK stack can be very helpful to take action or build dashboards based on logs. This can be easily achieved if we have logs in JSON format or any other format where individual fields can be accessed to raise alarms or to make dashboards.

Defining a POJO in Java and then using Jackson object mapper can be useful to achive the same. For example is my POJO is like:

import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class LogMetrics {
String name;
String DOB;
int group;
int minBonus;
long maxBonus;
}

I can convert that easily in string using object Mapper as below:

import com.fasterxml.jackson.databind.ObjectMapper;public String addLog(LogMetrics logMetrics) {
ObjectMapper Obj = new ObjectMapper();
try {
log.info(Obj.writeValueAsString(logMetrics));
} catch (IOException e) {
log.error(e.getMessage());
}
return "";
}

This will convert the object to JSON format string and log it.

Test for logging

Testing log statements in unit testing is something which most people don’t think about. I feel it should not be ignored as logging is very important technical and business requirement.

Its not very difficult to achieve either and Here is example to do in Java with logback.

class LoggerTester {
LogMetrics logMetrics;
ListAppender<ILoggingEvent> listAppender;
Logger logger;
@BeforeEach
void beforeEach() {
listAppender = new ListAppender<>();
logger = (Logger) LoggerFactory.getLogger(LogMetrics.class.getName());
listAppender.start();
logger.addAppender(listAppender);
}
@AfterEach
void afterEach() {
logger.detachAndStopAllAppenders();
}
@Test
void testLog() {
// perform operation for logging

List<ILoggingEvent> logsList = listAppender.list;

assertEquals("expected log message", logsList.get(0).getMessage());
assertEquals(Level.INFO, logsList.get(0).getLevel());
// in case of multiple log statements
assertEquals("expected log message", logsList.get(1).getMessage());
assertEquals(Level.INFO, logsList.get(1).getLevel());
}
}

So unit testing log statements are not very tedious and I would recommend that to have with usual unit test cases.

I hope it helps you to understand what should be right balance in logging, format and how to test that like any other requirement.

--

--

Deepti Mittal

I am working as software engineer in Bangalore for over a decade. Love to solve core technical problem and then blog about it.