如何寫好Logs

寫好Log對我而言一直是一項重要的技能, 因為它可以讓問題發生時, 讓開發者用最短的時間找到並解決問題… 剛好在Hacker News上看到這篇 Logging in Python like a PRO , 順便紀錄一下這位作者的一些觀點…

好的Log所需具備的特性

* Descriptive
* Contextual
* Reactive

They’re descriptive in the sense that they give you a piece of information, they’re contextual because they give you an overview of the state of things at the moment, and finally, they’re reactive because they allow you to take action only after something happened (even though your logs are sent/consumed real-time, there’s not really something you can do to change what just happened).

https://guicommits.com/how-to-log-in-python-like-a-pro/

簡單來說如果一段log可以具備上述三個特性, 作者就認為可以讓log的讀者能夠更輕鬆的定位問題的發生點, 以及相對應的事件背景 !

Log 的時機點

As a rule of thumb consider logging:

* At the start of relevant operations or flows (e.g. Connection to third-party, etc);

* At any relevant progress (e.g. Authentication successful, got a valid response code, etc);

* At the conclusion of an operation (e.g. EITHER succeeded or failed);

https://guicommits.com/how-to-log-in-python-like-a-pro/

至於說何時要寫Log呢? 作者這邊指出事件的起始點, 相關的處理進度發生時, 以及事件處理完成時都是適合Log的時間點 !!!

Python 下的Logging的一些範例設定

Python上的一些Log設定我就不太熟了, 先紀錄一下之後可以看看….

總結

這篇文章算是簡單的提要了寫Log時的一些大方向, 這樣之後要寫也蠻適合當參考…

Reference:

Python concurrency的進展

在 Hacker News 上看到的資訊,目前有一位開發者最近實作出PoC版本的CPython multi-threading。

而會這麼說,主要是因為目前的Python在multi-thread方面的發展,還是受限於GIL(global interpreter lock)的影響,所以實際上在執行時,只會有一個thread 在運作。

而會有這樣的設計,也是跟GC(Garbage Collection)有比較大的關係,因為Python的GC是採用reference count的原理,當一個物件不再被任何其它物件所使用時,它就會是可以被回收的。而回收的方式就是透過GIL。

To avoid such problems, the GIL only allows one thread to be running in the interpreter (i.e. to actually be running Python code) at a time; that takes away almost all of the advantage of using threads in any sort of compute-intensive code.

A viable solution for Python concurrency [LWN.net]

不過目前這個設計有機會被改進了,即是社群開發者提供的那個 PoC版本CPython,而主要的改進方向是透過改進GC演算法,更詳細的作法可以直接參考這裡

相信這功能如果可以進到CPython之後的版本的話,這一定會大幅強化Python的優勢的,等之後看後續的發展了XD

Reference:

Python Poetry在 VSCode上的設定

筆記一下在VS Code上設定Python的開發環境設定;會寫這篇主要是因為一開始在使用VS Code 時,開啟某個Poetry 管理的Python 專案時,總是無法在編輯器上正確定的讀取到相依的套件。

但使用poetry run python xxx.py時卻又可以正確的執行其專案主程式!

Root Cause

最後,找到問題點主要是在VS Code Python interpreter的設定,也就是說如果我們是使用預設的python 路徑時,VS Code沒辦法正確的找到目前專案的相依套件其安裝的路徑 !

Solution

在知道是Python interpreter的問題後,解決方式就是去設定目前 Python 專案的Python interpreter 為其Poetry所建立的Python virtual env 路徑,主要的設定方式如下:

  1. cmd + shift+p -> Python: Select Interpreter
  2. 指定對應的Poetry Python binary path:

假設目前的poetry專案名稱為 pytest,透過poetry install 後,我的電腦上就會出現類似/Users/xxx/Library/Caches/pypoetry/virtualenvs/pytest-yI9RJA6z-py3.9的資料夾,而我們要指定的interpreter就會是:
/Users/gechen/Library/Caches/pypoetry/virtualenvs/pytest-yI9RJA6z-py3.9/bin/python3.

Reference

Python command line

最近為了想上手Python,所以想說用Python寫個簡易的cli 工具當作目標來當練習;這次就來記錄怎麼一步一步的寫出這個cli程式。
程式的需求,是希望可以設定一個定期備份wordpress 內容的服務,並且在備份完了以後,可以上傳到指定的AWS s3.

Requirements

  • 提供flag 可以讓使用者指定要備份的資料夾
  • 提供flag 可以讓使用者指定要上傳的s3 路徑
  • 備份的資料夾必須先經過壓縮後,才會上傳到s3

Dependencies

  • Python 3+
  • Poetry
  • Pip

Poetry 是目前主流的Python套件管理工具,而這次這個repo主要就是使用poetry來管理其相依的library。

Implementation

Cli flags

Config flags 的部分,主要是透過Click這個套件來實作。這個套件在使用上相當容易上手,透過decorator的方式就可以指定程式在執行時,需要帶入哪些指令。

像是下面這段程式碼,就指定了程式在執行時,需要帶入-s--s3_path 作為s3 的路徑;即使我現在還不是很熟decorator,也可以輕易的讓程式支援flag。

@click.command()
@click.option(
     "-s",
     "--s3_path",
     default="",
     envvar="S3_PATH",
     help="The s3 path for uploading. (e.g. s3://path/to/upload )",
     required=True
 )

Entrypoint

除了讓程式支援flag,我們這邊也需要設定程式在執行時的進入點,通常會是一個自定義的function,其參數會是我們先前所設定的flags。

以下面的程式碼為例,我們指定了cli() 作為我們的這個程式的進入點,並且程式必須有2個參數,分別是inputs3_path。(參數的名稱必須與@click.option中的一致)

def cli(input, s3_path):
     if s3_path.find("s3://") != 0:
         logging.error("incorrect s3 path format")
         exit(1)

if name == "main":
    cli()

Config Poetry cli entrypoint

透過先前的設定,我們已經可以透過一般python 的執行方式(python cli.py)來執行我們的程式了,但為了讓我們的cli程式在執行時可以更像一個執行檔,我們可以透過Poetry來包裝我們的程式,這樣就不需要透過pyhton xxx.py的方式執行了!

Poetry entrypoint function

首先,我們必須先變動我們的程式路徑,並且指定一個可以當進入點的function,這邊我們就可以設定一個新的main(),而其function body就是執行我們先前的cli()

def main():
     cli()

接下來,我們必須在project 根資料夾下,新增一個子資料夾,並且把我們的cli.py移至這個子資料夾下,新的路徑結構為下

backup_to_s3_repo/
  poetry.lock
  pyproject.toml
  README.md
  backup_to_s3/
    __init__.py
    cli.py

Poetry entrypoint configuration

在這邊還需要在設定pyproject.toml,主要是為了讓poetry在執行時,可以用”alias”的方式來執行我們的程式,相關的pyproject.toml的內容如下:

下面的設定,可以讓我們執行poetry run backup_to_s3時,實際上去執行backup_to_s3/cli.py中的main()

[tool.poetry.scripts]
 backup_to_s3 = "backup_to_s3.cli:main"

Build and install

在完成前面所提到的設定之後,我們已經可以透過python backup_to_s3/cli.pypoetry run backup_to_s3來執行我們的程式了;但為了讓我們的程式可以更像一般的系統預設的執行程,我們可以透過下面列出的方式來實作。

Build the poetry project

透過poetry build,poetry 會幫我們把整個poetry project與相關的套件封裝成一個tar.gz 檔,並儲存於dist/資料夾下。

在整個封裝的過程中,poetry會幫我們建立對應的.whlsetup.py檔,以便於我們發佈或分享這個tar.gz 檔。

Install poetry build file by pip

在有了上述的tar.gz檔以後,我們就可以透過pip install的方式,將整個backup_to_s3程式安裝成像系統內建的指令程式了,詳細的指令可以參考下面

pip install dist/backup_to_s3-0.1.0.tar.gz

最後,完整的source code 可以參考這裡:
https://github.com/bamoo456/backup-to-s3

Reference