Spring Boot Applications logs exposed over REST end point.

Spring Boot Applications logs exposed over REST end point.

How you can access logs of spring boot application over REST endpoint without login to Kubernetes cluster, Splunk, ELK, or not any tool but by using application REST endpoint. If you are a spring boot developer then you have heard about the actuator endpoint. When you learn about or ask anyone about actuator endpoint we generally heard about health endpoint or some info endpoint but it's more than this.

In this article, I would like to discuss how to expose the application logs through the REST endpoint in Spring Boot. Application Logs play an important role in your application monitoring and provide you the insights into the runtime details of your application.

Spring Boot Actuator endpoints:

An actuator is a manufacturing term that refers to a mechanical device for moving or controlling something. Actuators can generate a large amount of motion from a small change.

Spring Boot Actuator is a module of the Spring Boot Framework. It uses HTTP endpoints to expose operational information about any running application. Spring Boot includes a number of additional features to help you monitor and manage your application when you push it to production. You can choose to manage and monitor your application by using HTTP endpoints or with JMX. Auditing, health, and metrics gathering can also be automatically applied to your application.

This is the production-ready feature.

The simplest way to enable the features is to add a dependency to the spring-boot-starter-actuator ‘Starter’.

When exposing your logs through the endpoint, please ensure you are not logging any sensitive /confidential details into the logs. Even though this is a production-ready feature but this is not best practice in enterprises, you can use this one to debug applications in development or other lower environments. It is not recommended to expose the logs through the endpoint unless you do not have any other way of looking into the logs from your application.

Implementation:

Let us create a spring boot application using a spring initializer. (start.spring.io)

After initializing the project, please include below log4j2 dependencies. Please note that you can use log back as well that comes by default with spring-boot-starter-web, but here I am using log4j based on my experience.

implementation 'org.apache.logging.log4j:log4j-api:2.17.2'
implementation 'org.apache.logging.log4j:log4j-core:2.17.2'

After adding the above dependencies your build.gradle file will look like this.

plugins {
    id 'org.springframework.boot' version '3.0.0-M4'
    id 'io.spring.dependency-management' version '1.0.12.RELEASE'
    id 'java'
}

group = 'com.teechwasti'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
}

dependencies {
    implementation 'org.apache.logging.log4j:log4j-api:2.17.2'
    implementation 'org.apache.logging.log4j:log4j-core:2.17.2'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

Log4j Configurations:

Once your application code is ready, create some REST endpoint or something so that you are able to see more logs for verification. After coding changes are done let us create the log4j configuration file and do the configurations below.

Below configuration ensures the file is rolled for every 2 minute.

<?xml version="1.0" encoding="UTF-8"?>
<!-- Extra logging related to initialization of Log4j.
 Set to debug or trace if log4j initialization is failing. -->
<Configuration status="warn">
    <properties>
        <property name="LOGS" value="./logs"/>
    </properties>
    <Appenders>
        <!-- Console appender configuration -->
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
        </Console>
        <!--                     filePattern="${LOGS}/spring-boot-logger-%d{yyyy-MM-dd}.log"-->
        <RollingFile name="fileLogger"
                     fileName="${LOGS}/spring-boot-logger.log"
                     filePattern="${LOGS}/spring-boot-logger-%d{yyyy-MM-dd-HH-mm}-%i.log">
            <PatternLayout pattern="%d [%t] %-5p {%F:%L} %x - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
            </Policies>
            <DefaultRolloverStrategy>
                <Delete basePath="${LOGS}" maxDepth="10">
                    <IfLastModified age="2m"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
    </Appenders>
    <Loggers>
        <!-- Root logger referring to console appender -->
        <Root level="info" additivity="false">
            <AppenderRef ref="console"/>
            <appenderRef ref="fileLogger"/>
        </Root>
    </Loggers>
</Configuration>

Let us say if you wan to change your strategy to rollover file for everyday instead of 2 minutes so you can use below configuration.

Rollover strategy depends on the filePattern you defined as part of the RollingFile configuration and TimeBasedTriggeringPolicy. This is the configuration to rollover the file every day and delete the files that are older than 2 days.

<RollingFile name="fileLogger"
             fileName="${LOGS}/spring-boot-logger.log"
             filePattern="${LOGS}/spring-boot-logger-%d{yyyy-MM-dd}-%i.log">
    <PatternLayout pattern="%d [%t] %-5p {%F:%L} %x - %m%n"/>
    <Policies>
        <TimeBasedTriggeringPolicy interval="1"/>
    </Policies>
    <DefaultRolloverStrategy>
        <Delete basePath="${LOGS}" maxDepth="10">
            <IfLastModified age="2d"/>
        </Delete>
    </DefaultRolloverStrategy>
</RollingFile>

Enable actuator for logs:

Now let us enable the actuator endpoint and expose log file over REST endpoint, there are different ways for this but I have used below configurations.

server.port= 9010
logging.file.path=./logs/spring-boot-logger.log

management.endpoints.web.exposure.include=health,info,logfile

Controller:

Hello world rest end point to make sure that some logs are there.

@RestController
public class HelloController {

    private static final Logger LOGGER = LogManager.getLogger(HelloController.class);

    @GetMapping("/hello")
    public ResponseEntity<String> logDetails() {
        LOGGER.info("Demo log message. Logged at: " + new Date().toString());
        return ResponseEntity.ok("Message Logged");
    }
}

You are ready to verify our configurations. once you build and access the ‘logfile’ endpoint, you would be presented with the below details.

Run the application and hit first localhost:9010/hello and then access application logs on localhost:9010/actuator/logfile. It will look like the below screenshot.

image.png

Source Code:

git clone https://github.com/maheshwarLigade/spring-boot-examples.git
cd sbactuatorlogrestapi 
gradle build

Conclusion:

This article will help you to understand how you can expose the logs using the REST endpoint and access it. It's a simple and easy way to debug the application but this is not recommended for production because there are certain security and regulatory concerns.

More such articles:

https://medium.com/techwasti

https://www.youtube.com/channel/UCiTaHm1AYqMS4F4L9zyO7qA

https://www.techwasti.com/

==========================**=========================

If this article adds any value for you then please clap and comment.

Let’s connect on Stackoverflow, LinkedIn, & Twitter.

Did you find this article valuable?

Support techwasti by becoming a sponsor. Any amount is appreciated!