[Python] 使用 fcntl() 取得 zlog 使用的 file lock,避免衝突

[Python] 使用 fcntl() 取得 zlog 使用的 file lock,避免衝突

之前的一個 C 專案程式,用了 zlog 這個 3rd-party 套件來寫記錄檔 (log),

不過因為 zlog 它雖然可以自動 rotate log

(就是 a.log 滿的時候會改名成 a.log.1,再把新的 log 寫到全新的 a.log 裡面),

但 zlog 並沒有壓縮 log 的功能,所以我們是另外用 python 來壓縮 log…

 

上面的作法本來也沒太大問題,

只是偶爾會遇到「Python 正在壓縮 log 時,zlog 也跑來要 rotate log」的問題…

這遇到的時候,正在被壓縮的檔案可能突然被 zlog 改名或移走…

要怎麼解決呢?

 

這時候還是得來看一下 zlog 的原始碼…

原始碼裡面可以看到,zlog 在 rotate log 之前,

會先呼叫 zlog_rotater_trylock() 想要取得一個 file lock,取到之後才會做 log rotate。

而取得 file lock 的方式是用 fcntl():

fcntl(a_rotater->lock_fd, F_SETLK, &fl)

 

有用 file lock 就簡單多了~

我們只要在 python 壓縮 log 之前,也去取得一樣的 file lock,

就能避免兩邊同時做事打架了~

 

下面是改寫後的 python 程式,

首先用 open() 將 zlog 的 lock file 打開,接著用 fcntl() 取得 file lock,

做完檔案壓縮後,再將 file lock 放掉 (寫在 finally 裡確保一定會被執行到):

# Acquire file lock for test_zlog.lock,
#   so that there would be no log rotation
#   while compressing test.log*.
zlog_lock_file = "/tmp/test_zlog.lock"
with open(zlog_lock_file, "w") as f:

    try:
        fcntl.fcntl(f.fileno(), fcntl.F_SETLKW, struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0))

        # Compress test.log.*
        # ......

    finally:
        # Release file lock for test_zlog.lock
        fcntl.fcntl(f.fileno(), fcntl.F_SETLKW, struct.pack('hhllhh', fcntl.F_UNLCK, 0, 0, 0, 0, 0))

 

這樣子改寫之後,zlog 和 python 兩邊就能遵守 file lock,

不再互相打架囉~

 

參考資料:

Python: fcntl — The fcntl and ioctl system calls

Python: struct

File Locking

Linux Programmer’s Manual: fcntl

 

(本頁面已被瀏覽過 1,028 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料