我所熱愛的網際網路,是一個開放、共享的網際網路,而不是現在這樣一個個圍牆越來越高的花園。
當時我沒有立刻回複,于是就有了這篇博文。下面進入正題,如何在不改動一行系統代碼的情況下,實作 python 應用的開啟調試和關閉調試。這篇博文裡我不會給出實作代碼,因為讀者知道了實作原理之後,自己動手實作一下,也許就是幾十分鐘的事情。需要強調的是,這裡的「系統代碼」,其實是「業務系統代碼」的意思,也就是我們維護的應用的代碼。
先理一下需求:
在業務代碼啟動之前,完成對 ptvsd 的調用
對 ptvsd 的調用,不出現在業務系統的代碼中
在 python 中,是否能做到在執行一個 py 檔案之前,先執行一點别的代碼呢?如果可以,那麼我們就能把對 ptvsd 的調用,作為這「一點别的代碼」了。
after these path manipulations, an attempt is made to import a module named sitecustomize, which can perform arbitrary site-specific customizations. it is typically created by a system administrator in the site-packages directory. if this import fails with an importerror exception, it is silently ignored. if python is started without output streams available, as with pythonw.exe on windows (which is used by default to start idle), attempted output from sitecustomize is ignored. any exception other than importerror causes a silent and perhaps mysterious failure of the process.
不要抛異常,以免影響 py 檔案的正常執行
不要輸出任何内容到 stdout,以免影響程式之間的互動
在同一個環境中啟動多個 python 程序的時候,要注意 debug 端口的配置設定,以及端口重複時的容錯和提示
其它我沒想到但是會影響預期行為的點
關于 1,我們可以通過一個巨大的 <code>try catch</code>,把所有異常吞掉,然後輸出異常資訊到日志檔案或者 stderr,這樣子就避免了我們在 sitecustomize.py 裡不小心寫出的 bug 影響到目标 py 檔案的執行。畢竟 debug 開啟不了事小,檔案執行不了事大。
關于 2,我是曾經掉到坑裡的。vs code 的 python 插件,是調用 python 解釋器去實作智能提示功能的,早些時候我修改了 sitecustomize.py,将一些資訊輸出到了 stdout,導緻 vs code 的 python 智能提示全廢了,排查這個問題費了一番功夫。
關于 3,我們可能需要引入一些稍複雜的方法,需要寫幾十行代碼。打個比方,我們要從同一個虛拟環境中啟動兩個伺服器程序,那麼我們需要為這兩個程序配置設定不同的調試端口。一種可行的方式是使用配置,比如用 configparser 解析一個 ini 檔案,從 ini 中讀取到為指定程序名稱配置的調試端口, 以及是否開啟調試等資訊,然後用 psutil 或者類似的類庫,擷取目前程序資訊,和配置資訊做個比對之後,決定目前程序是否需要開啟調試,調試端口号是多少。
然後我們在開發或者內建環境中部署遠端調試的時候,隻需要把這個萬年不變的 sitecustomize.py、根據不同環境稍作修改的 ini 檔案推到目标機器的虛拟環境中就好,python 應用的代碼無需為了遠端調試做任何修改。
基本上就是這樣子了,攤開來說也沒啥稀奇的,無非就是 sitecustomize.py 這個鈎子而已,希望對讀者有所啟發。
happy hacking!