Navigating the Log Level Symphony: A Tale of Dynamic Logging

Mainak Banerjee
Walmart Global Tech Blog
4 min readSep 20, 2023

In the world of applications, log levels serve as our backstage pass to deciphering the significance of log messages. Imagine a spectrum of log severity, from peacefully snoozing through the on-call night to breaking a personal sprinting record between bedroom and laptop in the living room — log levels hold the key. These levels sift critical insights from informative chitchat, reducing noise and preventing alarm fatigue.

peaceful snooze or moment prior to sprinting for personal best? Image by pch.vector on Freepik

Today, we unravel the secrets of creating a custom switch that dynamically changes the log level during runtime, providing you with control over your logs like never before.

Log Levels Unveiled: The Symphony of Severity

Log levels, the conductors of our log orchestra, are more than just labels. They reveal the importance of each log message, guiding us to handle alarms or grab popcorn. By using log levels smartly, we decode the gravity of each situation and act accordingly. Think of them as filters that sift through the noise, providing critical insights while keeping the commotion at bay.

The Power of Dynamic Log Levels: Reducing Clutter

In a world where logs stream like a waterfall, the ability to toggle log levels becomes a superpower. With a flick of the switch, we gain the ability to fine-tune the verbosity of our logs. Just like a light dimmer, it allows us to adjust the intensity of our log output. This dynamic control means we can produce fine-grained logs for debugging or curb the chatter of superfluous logs, maintaining a neat and tidy log stage.

Looking for order in chaos. Image by storyset on Freepik

Two Paths, One Goal: A Duel of Methods

As we embark on this journey, we find two paths:

  • update the configuration with a restart
  • dynamically change the log level programmatically without a restart.

Both have merits, but the latter piques our curiosity. Imagine a built-in switch in your application that lets you tweak the log level on the fly. No more manual updates and restarts; it’s real-time control at your fingertips.

The Magical Switch: The Technical Choreography

Behold, the custom switch! A controller emerges, wielding the power to accept log level inputs, validate them, and dynamically alter the log levels. With annotations and headers, this controller transforms your application into a symphony of runtime log modulation. Here’s the implementation in Java, Spring, with Lombok annotations

package toggle.log.level.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
* Rest controller for changing log level dynamically based on input
*
* @author Mainak Banerjee
*/
@RestController
@Slf4j
public class LogLevelController {

/**
* @param logLevelHeaderKey String
* @param logLevel String
* @return ResponseEntity
*/
@Operation(summary = "Change log level dynamically based on input")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "Log Level Changed successfully",
content = {@Content(mediaType = "application/json")}),
@ApiResponse(
responseCode = "400",
description = "Invalid header or params supplied",
content = @Content),
@ApiResponse(
responseCode = "500",
description = "Internal Server error",
content = @Content),
})
@GetMapping("/loglevel")
public ResponseEntity<String> setLogLevel(
@Parameter(description = "log level key")
@RequestHeader(name = "logLevelKey", required = false)
String logLevelHeaderKey,
@Parameter(description = "log level parameter")
@RequestParam(name = "logLevel", required = false, defaultValue = "Info")
String logLevel) {
log.info("GET request for changing log level to: {} -- BEGINS", logLevel);
validateRequest(logLevelHeaderKey, logLevel);

try {
Configurator.setAllLevels(log.getName(), Level.valueOf(logLevel));
} catch (IllegalArgumentException ex) {
log.error("{}: Invalid log level passed : {}", "MISSING_OR_INVALID_PARAM", logLevel);

// throw custom exception with message like MISSING_OR_INVALID_PARAMS here
}

log.info("GET request for changing log level to: {} -- ENDS", logLevel);

return ResponseEntity.status(HttpStatus.OK)
.body(MessageFormatter.format("Log level changed to: {}", logLevel).getMessage());
}

private void validateRequest(String logLevelHeaderKey, String logLevel) {
if (StringUtils.isBlank(logLevelHeaderKey) || !"your-secret-key".equals(logLevelHeaderKey)) {

log.error(
"{}: Missing or incorrect value in header : {}",
"MISSING_OR_INVALID_HEADER",
"logLevelKey");

// throw custom exception with message like MISSING_OR_INVALID_HEADERS here
} else if (StringUtils.isBlank(logLevel)) {
log.error(
"{}: Missing or incorrect value in request param : {}",
"MISSING_OR_INVALID_PARAM",
"logLevel");

// throw custom exception with message like MISSING_OR_INVALID_PARAMS here
}
}
}

Balancing Power and Responsibility: Validations and Security

As with all powerful tools, this switch comes with a caveat. Dynamic log level toggling isn’t a mere light switch; it’s a double-edged sword. Opening the door to runtime log manipulation demands caution if misused, can cause unintended issues due to incorrect logging levels. It’s imperative to introduce security mechanisms to authorise and authenticate users altering log levels.

In this example this is achieved by accepting a security key, which will be validated first to ensure the request is authorised.

Curtain Call: A Melody of Log Management

As our journey concludes, we appreciate the synergy between control and caution. The ability to dynamically shape log levels offers a new dimension of log management. Yet, just as a conductor harmonises the orchestra, developers must strike a balance between functionality and security, ensuring a safe encore for every log level tweak.

Final Note: A Symphony of Solutions

In the grand symphony of software development, problems offer a plethora of solutions. As developers, we must compose our choices by considering a symphony of aspects before tuning into the right solution.

--

--

Mainak Banerjee
Walmart Global Tech Blog

Mastery in code, goals on field I've showed. Dreamed Ma Long, now algorithms flowed. Music's my guide, in football I stride. A developer, passions worldwide.