Έλεγχος για 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