Έλεγχος για rotation log αρχείου
George Notaras
gnot at g-loaded.eu
Wed Sep 16 14:34:22 EEST 2009
Giorgos Keramidas wrote:
> 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.
>
Αυτό θα λιγοστέψει αφάνταστα τις εκτελέσεις της os.stat(), κάτι που με
προβλημάτιζε πιο πριν.
> 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
> που είχες διαβάσει τελευταία φορά.
>
Αν και η ιδέα του Ρικούδη για το pipe με έβαλε σε σκέψεις, μάλλον θα
προχωρήσω με αυτούς του ελέγχους. Μέχρι τώρα προσπαθούσα χωρίς την
stat(), παρά μόνο με read(), tell() και seek() να ανιχνεύσω το rotation,
κάτι μάλλον αδύνατο.
Ευχαριστώ για την αναλυτική απάντηση. :)
More information about the Linux-greek-users
mailing list