0

I would like to read syslog messages from my java application. I will be looking into file /var/log/messages. That file can be huge. I would like to have a thread:

  1. Which will constantly check if some new data has appeared in that file
  2. Will execute specific actions if specific lines has been found

What is the best(efficient) way to realize step 1. How can I constantly read just new lines from the file?

Kara
  • 6,115
  • 16
  • 50
  • 57
user2913139
  • 557
  • 2
  • 5
  • 13

1 Answers1

0

Launch a Thread and Get your file's instance for the first time that you are trying to check the changes for. This would be your starting point. Now Use the Java Diff Utility to check if your file got any new lines appended or any sort of changes that took place in your file.

Let's call this instance of the file currentFile

You can use this utility to keep checking for new data.

https://code.google.com/p/java-diff-utils/

Diff Utils library is an OpenSource library for performing the comparison operations between texts: computing diffs, applying patches, generating unified diffs or parsing them, generating diff output for easy future displaying (like side-by-side view) and so on.

Here is a Sample code to check for changes

import difflib.*;

public class BasicJavaApp_Task1 {
        // Helper method for get the file content
        private static List<String> fileToLines(String filename) {
                List<String> lines = new LinkedList<String>();
                String line = "";
                try {
                        BufferedReader in = new BufferedReader(new FileReader(filename));
                        while ((line = in.readLine()) != null) {
                                lines.add(line);
                        }
                } catch (IOException e) {
                        e.printStackTrace();
                }
                return lines;
        }

        public static void main(String[] args) {
                List<String> original = fileToLines("originalFile.txt");
                List<String> revised  = fileToLines("revisedFile.txt");

                // Compute diff. Get the Patch object. Patch is the container for computed deltas.
                Patch patch = DiffUtils.diff(original, revised);

                for (Delta delta: patch.getDeltas()) {
                        System.out.println(delta);
                }
        }
}

You can use the Delta to check for your particular data that you are looking for.

Now it is up to you, to decide what is the frequency that you want the comparisons to happen with. Like Every 1000ms, or 10000ms and so on.

Also make sure After Every Comparison You should update your currentFile

For Step 2: In order to send Callbacks You can do the following

Use a ScheduleExecutorService

ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
void registerCallback() {
  ses.schedule(new MyCommand(), 30, TimeUnit.SECONDS);
}

It returns a Future which can be used to cancel the execution if you want to, or to obtain a value returned by MyCommand.

Should you want to schedule a command that will keep repeating on a timely fashion, you could use other scheduling methods: scheduleAtFixedRate and scheduleWithFixedDelay.

If you need to reschedule on some condition only, or with different rates or intervals, one technique I've used is to pass the ScheduledExecutorService to your command (ie, new MyCommand(ses)) and let it rescheduled itself or a new command with the appropriate delay:

class MyCommand implements Runnable {
  private final ScheduledExecutorService ses;
  MyCommand(ScheduledExecutorService ses) { this.ses = ses; }
  private boolean shouldReschedule() { ... }
  private int getRescheduleTimeoutMs() { ... }
  @Override void run() {
    // do work
    ...
    // reschedule if needed
    if (shouldReschedule()) {
      // reschedule this command:
      ses.schedule(this, getRescheduleTimeoutMs(), TimeUnit.MILLISECONDS);
      // or else a new one:
      ses.schedule(new MyCommand(ses), ...);
    }
  }
}
droidchef
  • 2,237
  • 1
  • 18
  • 34
  • This doesn't answer the OP's question. – TheLostMind Aug 21 '14 at 11:48
  • @TheLostMind Did the details help a bit? – droidchef Aug 21 '14 at 11:57
  • I was thinking about something simple - without additional libs. Is there any option to: 1. Save the last position (byte number) read 2. register callback function which will be called back when new data appears in the file (similar like signals in Linux ?) ? – user2913139 Aug 21 '14 at 11:57
  • Well this library does the heavy lifting of Comparison Algorithms in an efficient manner. And yeah You can register a Handler or Something to post Callbacks to the Thread where you want to perform actions if you find something in the file. – droidchef Aug 21 '14 at 11:59
  • Ishan: could you give me any hint how to register that callback function when new data to a file is appended ? What class should i use for that ? – user2913139 Aug 21 '14 at 12:01
  • Ishan: thank you for that hints. But i can see problems with both steps. 1. syslogs message logs are rotating, i would need to add a lot of logic to check rotated log. Also i would need to copy whole (posisbly very big) file after every check. 2. You have presented Thread - but how can i call the method after the file has a new data (instead of calling it periodically) ? Maybe there are other solutions ? – user2913139 Aug 21 '14 at 12:42
  • Well stackoverflow is to help you with your code. We can just give you a direction to think in and not the exact code all the time. Maybe you can try something and then post problems with code snippets. Otherwise I think this should be the accepted answer. Hint is all we can give if there is no code posted in the question. Thanks – droidchef Aug 21 '14 at 12:44
  • Actually i do not need any help with code itself - rather help with general solution/architecture (just class/library/solution name would be enough). When programming on Unix i could do it effectively: register signal/callback when file has a new data and read only a new data. I am sure there must be something similar for java. I really do appreciate your help here - but i need to find more optimal solution (copying/reading whole file will make my app very slow). – user2913139 Aug 21 '14 at 14:06
  • ok, found solution here: http://stackoverflow.com/questions/14822302/is-it-possible-to-get-output-of-tail-f-command-to-java-programme – user2913139 Aug 21 '14 at 19:33