Logs using SpringBoot

Web Socket Config

package com.example.logdemo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/logs").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic/log");
    }
}

Controller

package com.example.logdemo.controller;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

import com.example.logdemo.models.Message;

@Controller
public class FileWatchController {
    @MessageMapping("/logs")
    @SendTo("/topic/log")
    public Message getMessage(Message message) {
        return message;
    }
}

Models

package com.example.logdemo.models;

public class Message {
    String content;
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Service

package com.example.logdemo.service;

import java.io.RandomAccessFile;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class FileWatchService {
    private final static String FILE_NAME="log.txt";
    private final static String READ_MODE="r";
    private final static String DESTINATION="/topic/log";

    private final RandomAccessFile randomAccessFile;
    private long offset;

    @Autowired
    SimpMessagingTemplate messagingTemplate;

    public FileWatchService() throws Exception {
        randomAccessFile = new RandomAccessFile(FILE_NAME, READ_MODE);
        offset = initialOffset();
    }

    @Scheduled(fixedDelay = 100, initialDelay = 3000)
    public void sendUpdates() throws Exception {
        long fileLength = randomAccessFile.length();
        randomAccessFile.seek(offset);

        while (randomAccessFile.getFilePointer() < fileLength) {
            String latestData = randomAccessFile.readLine();
            String payload = "{" + "\"content\":\"" + latestData + "\"" + "}";
            messagingTemplate.convertAndSend(DESTINATION, payload);

        }
        offset = fileLength;
    }
    private long initialOffset() throws Exception {
        long fileLength = randomAccessFile.length();
        if (fileLength == 0) {
            return 0;
        }

        long pos = fileLength - 1;
        int linesFound = 0;

        // Read backwards until we find 10 newlines or reach the start of file
        while (pos > 0 && linesFound < 10) {
            randomAccessFile.seek(pos);
            if (randomAccessFile.read() == '\n') {
                linesFound++;
            }
            pos--;
        }

        // If we're not at the start of the file, move past the last newline
        if (pos > 0) {
            pos += 2; // Move past the newline
        }

        return pos;
    }


}