摘要:反之,如果是使用并通過進(jìn)行調(diào)用,那么就應(yīng)當(dāng)進(jìn)行修改如果一個(gè)函數(shù)內(nèi)部有阻塞式的,那么改變這個(gè)函數(shù)是沒有用的,顯然要應(yīng)用改變的對象需要對象下一次被調(diào)用,這個(gè)不難理解但是容易漏想到
后端開發(fā)中有時(shí)會(huì)遇到這種情況:進(jìn)程運(yùn)行中偶現(xiàn),重啟進(jìn)程問題就消失;或者是,進(jìn)程一定要運(yùn)行一段時(shí)間才會(huì)出現(xiàn)問題;又或是,極難復(fù)現(xiàn)的問題出現(xiàn)了,然而已有的log不足以定位
對于這些情況,盡管大部分時(shí)候,我們可以通過在可能的地方加log,然后重啟進(jìn)程等待問題復(fù)現(xiàn),但這樣相對被動(dòng)。我們都知道如果要調(diào)試C/C++程序,gdb attach上進(jìn)程就可以,而python雖然有相似的工具pdb,但它無法附加到一個(gè)進(jìn)程上,必須要用pdb啟動(dòng)進(jìn)程,在實(shí)際環(huán)境中顯然不管用,那么python是否有類似的辦法來改變運(yùn)行中進(jìn)程的代碼呢?這樣我們就可以通過實(shí)時(shí)加log來定位問題,這樣幾乎可以解決python層面的任何問題
可以參考兩篇文章:
https://mozillazg.com/2018/07...
https://mozillazg.com/2017/07...
簡單來說,可以直接用gdb使用類似調(diào)試c程序的方式,但要求python進(jìn)程是使用python-debug這種版本的python,同樣不夠?qū)嵱谩_@里介紹博客中提到的“純gdb”的方式,通過github上一個(gè)開源python包pyrasite,本質(zhì)上是通過gdb的-eval-command和它的PyRun_SimpleString來向進(jìn)程注入代碼。
這個(gè)庫有一些附加功能,可以通過它的文檔去了解。這里只說實(shí)現(xiàn)進(jìn)程注入的核心,是其中一個(gè)很短的文件injector.py,這里去掉了原文件中用于windows平臺(tái)的一段代碼,我們這里只考慮linux,核心代碼如下:
import os import subprocess import platform def inject(pid, filename, verbose=False, gdb_prefix=""): """Executes a file in a running Python process.""" filename = os.path.abspath(filename) gdb_cmds = [ "PyGILState_Ensure()", "PyRun_SimpleString("" "import sys; sys.path.insert(0, "%s"); " "sys.path.insert(0, "%s"); " "exec(open("%s").read())")" % (os.path.dirname(filename), os.path.abspath(os.path.join(os.path.dirname(__file__), "..")), filename), "PyGILState_Release($1)", ] p = subprocess.Popen("%sgdb -p %d -batch %s" % (gdb_prefix, pid, " ".join(["-eval-command="call %s"" % cmd for cmd in gdb_cmds])), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() if verbose: print(out) print(err)
這個(gè)函數(shù)做的事很簡單,不難看懂,所以,我們需要做的就是調(diào)用這個(gè)函數(shù),傳入pid和文件名,文件是一個(gè)你要對這個(gè)進(jìn)程執(zhí)行的python代碼。現(xiàn)在我們運(yùn)行一個(gè)很簡單的python進(jìn)程test.py:
import time def b(): print("b") while 1: b() time.sleep(1)
然后創(chuàng)建一個(gè)文件patch.py:
print("injecting") def newb(): print("new b") b = newb
在injector.py的末尾加上一段,以便接收命令行調(diào)用:
import sys pid = sys.argv[1] filename = sys.argv[2] inject(int(pid), filename)
通過ps aux|grep test.py查看上面進(jìn)程的pid,然后執(zhí)行python injector.py pid patch.py,為方便反復(fù)測試可以這樣:
pid=`ps aux | grep test.py | grep -v grep | awk "{print $2}"`;python injector.py $pid patch.py;echo $pid injected
輸出如下:
至此就實(shí)現(xiàn)了進(jìn)程注入。
注意點(diǎn):
修改類或類方法和函數(shù)同理,改變類的方法時(shí),直接使用類名classA.method = new_method會(huì)將變化應(yīng)用到所有實(shí)例,注意對類方法來說在patch.py中定義時(shí)也要加上self參數(shù)
在patch.py中,我們可以直接對b賦值,因?yàn)槲覀僩db進(jìn)入一個(gè)進(jìn)程后,所在的上下文環(huán)境就是該進(jìn)程的入口模塊,可以通過打印globals()來看到有哪些全局變量,這些就是可以直接訪問的對象。如果是在一個(gè)普通的業(yè)務(wù)進(jìn)程中,必然有大量import,這種情況下你需要import相應(yīng)模塊再對該模塊的函數(shù)或類進(jìn)行修改,如import x.y.z as z; z.b = newb
特別需要注意的是,如果一個(gè)模塊A使用了from B import func,那么如果你想改變A中運(yùn)行的func,需要import A; A.func = newfunc,像這樣改變B是沒有用的:import B; B.func = newfunc,因?yàn)?b>from .. import ..會(huì)將對象復(fù)制一份到本地命名空間。反之,如果A是使用import B并通過B.func進(jìn)行調(diào)用,那么就應(yīng)當(dāng)import B進(jìn)行修改
如果一個(gè)函數(shù)內(nèi)部有阻塞式的while True,那么改變這個(gè)函數(shù)是沒有用的,顯然要應(yīng)用改變的對象需要對象下一次被調(diào)用,這個(gè)不難理解但是容易漏想到
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/43988.html
摘要:在調(diào)試程序的時(shí)候,一般我們只能通過以下幾種方式進(jìn)行調(diào)試程序中已經(jīng)有的日志在代碼中插入但是以上的方法也有不方便的地方,比如對于已經(jīng)在運(yùn)行中的程序,就不可能停止程序后加入調(diào)試代碼和增加新的日志從的項(xiàng)目得到靈感,嘗試對正在運(yùn)行的進(jìn)程插入代碼,在程 在調(diào)試 Python 程序的時(shí)候,一般我們只能通過以下幾種方式進(jìn)行調(diào)試: 程序中已經(jīng)有的日志 在代碼中插入 import pdb; pdb.s...
摘要:背景這幾天一直在查一個(gè)線上程序住的問題這個(gè)程序總是在運(yùn)行分鐘后住通過以下的一些調(diào)試手段發(fā)現(xiàn)是打日志的時(shí)候因?yàn)闈M被了日志是默認(rèn)打到的無論日志級(jí)別而我這個(gè)程序是被另一個(gè)程序調(diào)起的父進(jìn)程沒有接收子進(jìn)程的導(dǎo)致了被打滿在調(diào)試的過程中用到了以下幾種調(diào)試 FROM http://kamushin.github.io/debug/python.html 背景 這幾天一直在查一個(gè)線上程序 hang 住的...
摘要:開源項(xiàng)目起因最近做病毒分析的時(shí)候遇到遠(yuǎn)控馬,需要記錄連接的遠(yuǎn)程地址用火絨劍或者可以看到一部分,但是我想要更全面的信息,于是搗鼓了和。使用比較簡單,但是只能看到的流量,雖然能捕獲所有流量,但沒法過濾特定進(jìn)程的包,而且過濾規(guī)則對我來說太復(fù)雜了。 開源項(xiàng)目QPA 起因最近做病毒分析的時(shí)候遇到遠(yuǎn)控馬,需要記錄連接的遠(yuǎn)程地址!用火絨劍或者ProcessMonitr可以看到一部分,但是我想要更全面...
閱讀 2689·2021-10-12 10:12
閱讀 2335·2021-09-02 15:41
閱讀 2561·2019-08-30 15:55
閱讀 1399·2019-08-30 13:05
閱讀 2430·2019-08-29 11:21
閱讀 3535·2019-08-28 17:53
閱讀 3022·2019-08-26 13:39
閱讀 801·2019-08-26 11:50