Έλεγχος για rotation log αρχείου
Giorgos Keramidas
keramida at ceid.upatras.gr
Wed Sep 16 11:11:34 EEST 2009
On Wed, 16 Sep 2009 10:35:03 +0300, George Notaras <gnot at g-loaded.eu> wrote:
> Πού θα βασιστεί ένας έλεγχος για το αν ένα logfile έχει υποστεί
> rotation; Τι ακριβώς συμβαίνει στο αρχείο κατά το rotation;
>
> Θέλω να κάνω κάτι σαν το "tail -f" σε python, το οποίο όμως να
> ανιχνεύει το rotation και θέλω να σιγουρευτώ για κάποια πράγματα.
Ανάλογα το _πως_ γίνεται το rotation μπορεί να συμβούν ένα από δύο
πράγματα:
α) Το log rotation πρόγραμμα αποφασίζει ότι το 'foo' πρέπει να γίνει
rotate σε 'foo.1' και αντιγράφει το 'foo' σε 'foo.1', μηδενίζοντας
το αρχείο 'foo' με truncate().
β) Το rotation πρόγραμμα αποφασίζει ότι το 'foo' πρέπει να γίνει
rotate σε 'foo.1', οπότε κάνει rename() το 'foo' σε 'foo.1' και
δημιουργεί ένα νέο κενό 'foo'.
Στην πρώτη περίπτωση αν έχεις ανοιχτό ένα file descriptor (fd), το οποίο
αναφέρεται στο αρχείο 'foo', κατά τη διάρκεια του truncate() το δικό σου
fd θα συνεχίζει να αναφέρεται στο ίδιο i-node αλλά θα έχει αλλάξει το
μέγεθος του αρχείου (το οποίο μπορείς να ελέγξεις με stat()).
Στη δεύτερη περίπτωση θα έχει αλλάξει τόσο το μέγεθος όσο και το i-node
του αρχείου (αφού το παλιό i-node θα αναφέρεται πλέον στο 'foo.1').
Οπότε αυτό που μπορείς να κάνεις είναι κάτι αντίστοιχο με αυτό που κάνει
η tail κι όταν βλέπεις ότι η os.read() επιστρέφει μηδέν bytes (οπότε
έπιασες το τρέχον EOF indicator), να προσπαθείς μέσω os.stat() να
καταλάβεις αν άλλαξε το μέγεθος ή το i-node από το log file.
bash:
$ echo foo > foo
python:
>>> >>> import os
>>> fd = os.open('foo', 0)
>>> fd
3
>>> os.read(fd, 4096)
'foo\n'
>>> os.read(fd, 4096)
''
>>> os.fstat(fd)
posix.stat_result(st_mode=33204, st_ino=30974882L, st_dev=151060225L,
st_nlink=1, st_uid=1000, st_gid=1000, st_size=4L,
st_atime=1253087963, st_mtime=1253087938, st_ctime=1253087938)
Οπότε τώρα έχουμε πιάσει το EOF (το len() του αποτελέσματος της
os.read() είναι μηδέν) και το i-node από το τρέχον 'foo' file είναι:
>>> print "%ld" % os.fstat(fd)[1]
30974882
Αν στο μεταξύ πας δίπλα στο bash και μετονομάσεις το 'foo' σε 'foo.1'
για να εξομοιώσεις ένα rotation:
bash:
$ mv foo foo.1
$ touch foo
python:
>>> print "%ld" % os.stat('foo')[1]
30974886
Οπότε εγώ θα σου πρότεινα να ξεκινήσεις με κάτι σαν αυτό:
>>> def statinfo(st):
... f = {}
... for (tag, pos) in (('device', 2), ('inode', 1), ('size', 6)):
... f[tag] = st[pos]
... return f
...
>>> def fdinfo(fd):
... return statinfo(os.fstat(fd))
...
>>> def finfo(path):
... return statinfo(os.stat(path))
...
>>> finfo('foo')
{'device': 151060225L, 'inode': 30974886L, 'size': 0L}
>>> fdinfo(fd)
{'device': 151060225L, 'inode': 30974882L, 'size': 4L}
Αν προσέξεις τις διαφορές σε inode και size του finfo('foo') και του
fdinfo(fd) θα δεις ότι είναι πια εύκολο να καταλάβεις ότι έχει αλλάξει
το αρχείο στο δίσκο και πρέπει να το κάνεις reopen.
Αν έχει αλλάξει το i-node έγινε rename, οπότε μπορείς να συνεχίσεις από
το offset 0 ξανανοίγοντας το αρχείο.
Αν έχει το ίδιο i-node αλλά διαφορετικό μέγεθος, μάλλον έγινε truncate
in place. Σε αυτή την περίπτωση έχεις την επιλογή είτε να αρχίσεις από
την αρχή πάλι ή να περιμένεις μέχρι να ξεπεράσει σε μέγεθος το offset
που είχες διαβάσει τελευταία φορά.
More information about the Linux-greek-users
mailing list