Detect Log File Rotation (While Watching Log File for Modification)

Detect log file rotation (while watching log file for modification)

Using e4c5's answer I ended up with this code, which also solves the issue of calling readline() multiple times per second.

During the first invocation it skips to the end of the file and waits for modifications. When the file is moved, it reopens the file and reads the entire content, then starts to wait.

import os
import time
import traceback
import threading
import inotify.adapters

logfile = b'/var/log/auth.log'
#logfile = b'logfile.log'

##################################################################

def process(line, history=False):
if history:
print '=', line.strip('\n')
else:
print '>', line.strip('\n')

##################################################################

from_beginning = False
notifier = inotify.adapters.Inotify()
while True:
try:
#------------------------- check
if not os.path.exists(logfile):
print 'logfile does not exist'
time.sleep(1)
continue
print 'opening and starting to watch', logfile
#------------------------- open
file = open(logfile, 'r')
if from_beginning:
for line in file.readlines():
process(line, history=True)
else:
file.seek(0,2)
from_beginning = True
#------------------------- watch
notifier.add_watch(logfile)
try:
for event in notifier.event_gen():
if event is not None:
(header, type_names, watch_path, filename) = event
if set(type_names) & set(['IN_MOVE_SELF']): # moved
print 'logfile moved'
notifier.remove_watch(logfile)
file.close()
time.sleep(1)
break
elif set(type_names) & set(['IN_MODIFY']): # modified
for line in file.readlines():
process(line, history=False)
except (KeyboardInterrupt, SystemExit):
raise
except:
notifier.remove_watch(logfile)
file.close()
time.sleep(1)
#-------------------------
except (KeyboardInterrupt, SystemExit):
break
except inotify.calls.InotifyError:
time.sleep(1)
except IOError:
time.sleep(1)
except:
traceback.print_exc()
time.sleep(1)

##################################################################

Reading from rotating log files in logstash

The attribute path is an array and thus you can specify multiple files as follows:

input {
file{
path => [ "/var/log/syslog.log", "/var/log/syslog1.log"]
}
}

You can also use * notation for name or directory as follows:

input {
file{
path => [ "/var/log/syslog.log", "/var/log/syslog1.log", "/var/log/*.log", "/var/*/*.log"]
}
}

When you specify path as /var/*/*.log it does a recursive search to get all files with .log extension.

Reference Documentation

boost::log is it possible rotate file every time applicaion run?

You probably want not to rotate the file on startup (which means to close the current file and open a new one) but rather to generate a file name that doesn't clash with the files that were left by the previous runs of your application.

Two things need to be done for this. First, you have to configure the file collector, which will receive rotated log files and optionally manage them. File collector operates on one target directory, where all the rotated files are stored. You can specify that directory by adding target named parameter to your add_file_log call; this will create a file collector for your sink. Note that the target directory can be the same as the one your sink creates the file in - it will simply mean that moving the rotated log file to the target directory is a no-op.

Second, on your application startup, the scan_for_files method needs to be called on the sink backend. This will cause the file collector scan the target directory for log files that could have been left from the previous runs. If the file name pattern includes a file counter, the call can also detect the next counter value, which is what you want. The add_file_log function will do this automatically for you, if you configured the file collector (i.e. added the target named parameter), but if you create the sink manually, you will have to call it yourself.

Managing rotated files, including the scan_for_files functionality, is documented here.

Boost.Log: custom action on rotation of files

As far as I understand Boost.Log cannot be configured that the actual log file always has a fixed file name and only the archived files have suffixes. Is this correct?

Yes, the file name is generated by the sink backend when the file is first opened for writing. When the file is rotated, that file name is preserved.

Is there a possibility to add an custom action to each rotation event?

There are file open and close handlers. These callbacks receive a file stream, not the file name. But you can obtain the current file name from the sink backend by calling get_current_file_name.

As an idea, you may want to create a custom sink that will monitor errors in logs and add it to the core just like the file sink. If you set the same filter as the one in the file sink, only with a severity check that only passes error log records, that monitor sink will receive errors that are also logged by the file sink. Guidelines for creating custom sinks are described here.



Related Topics



Leave a reply



Submit