การมีสคริปต์หรือแม้แต่ระบบย่อยของแอปพลิเคชันสำหรับการดีบักโปรโตคอลเครือข่ายคุณต้องการดูว่าคู่ของคำขอตอบสนองคืออะไรกันแน่รวมถึง URL ที่มีประสิทธิภาพส่วนหัวน้ำหนักบรรทุกและสถานะ และโดยทั่วไปแล้วจะใช้ไม่ได้กับคำขอแต่ละรายการในทุกที่ ในขณะเดียวกันก็มีข้อพิจารณาด้านประสิทธิภาพที่แนะนำให้ใช้แบบเดี่ยว (หรือมีความเชี่ยวชาญเพียงไม่กี่อย่าง) requests.Sessionดังนั้นสิ่งต่อไปนี้ถือว่าเป็นไปตามคำแนะนำ
requestsรองรับสิ่งที่เรียกว่าevent hooks (ณ 2.23 มีเพียงresponsehook เท่านั้น) requests.requestมันเป็นพื้นฟังเหตุการณ์และเหตุการณ์ถูกปล่อยออกมาก่อนที่จะกลับจากการควบคุม ขณะนี้ทั้งคำขอและการตอบกลับได้รับการกำหนดอย่างสมบูรณ์ดังนั้นจึงสามารถบันทึก
import logging
import requests
logger = logging.getLogger('httplogger')
def logRoundtrip(response, *args, **kwargs):
    extra = {'req': response.request, 'res': response}
    logger.debug('HTTP roundtrip', extra=extra)
session = requests.Session()
session.hooks['response'].append(logRoundtrip)
นั่นคือวิธีบันทึกการเดินทางไปกลับ HTTP ทั้งหมดของเซสชัน 
การจัดรูปแบบบันทึกบันทึกการเดินทางไปกลับ HTTP
เพื่อให้การบันทึกด้านบนเป็นประโยชน์อาจมีตัวจัดรูปแบบการบันทึกเฉพาะที่เข้าใจreqและresเพิ่มเติมเกี่ยวกับบันทึกการบันทึก จะมีลักษณะดังนี้:
import textwrap
class HttpFormatter(logging.Formatter):   
    def _formatHeaders(self, d):
        return '\n'.join(f'{k}: {v}' for k, v in d.items())
    def formatMessage(self, record):
        result = super().formatMessage(record)
        if record.name == 'httplogger':
            result += textwrap.dedent('''
                ---------------- request ----------------
                {req.method} {req.url}
                {reqhdrs}
                {req.body}
                ---------------- response ----------------
                {res.status_code} {res.reason} {res.url}
                {reshdrs}
                {res.text}
            ''').format(
                req=record.req,
                res=record.res,
                reqhdrs=self._formatHeaders(record.req.headers),
                reshdrs=self._formatHeaders(record.res.headers),
            )
        return result
formatter = HttpFormatter('{asctime} {levelname} {name} {message}', style='{')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logging.basicConfig(level=logging.DEBUG, handlers=[handler])
ตอนนี้ถ้าคุณทำคำขอบางอย่างโดยใช้sessionเช่น:
session.get('https://httpbin.org/user-agent')
session.get('https://httpbin.org/status/200')
ผลลัพธ์ที่stderrจะมีลักษณะดังนี้
2020-05-14 22:10:13,224 DEBUG urllib3.connectionpool Starting new HTTPS connection (1): httpbin.org:443
2020-05-14 22:10:13,695 DEBUG urllib3.connectionpool https://httpbin.org:443 "GET /user-agent HTTP/1.1" 200 45
2020-05-14 22:10:13,698 DEBUG httplogger HTTP roundtrip
---------------- request ----------------
GET https://httpbin.org/user-agent
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK https://httpbin.org/user-agent
Date: Thu, 14 May 2020 20:10:13 GMT
Content-Type: application/json
Content-Length: 45
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
  "user-agent": "python-requests/2.23.0"
}
2020-05-14 22:10:13,814 DEBUG urllib3.connectionpool https://httpbin.org:443 "GET /status/200 HTTP/1.1" 200 0
2020-05-14 22:10:13,818 DEBUG httplogger HTTP roundtrip
---------------- request ----------------
GET https://httpbin.org/status/200
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK https://httpbin.org/status/200
Date: Thu, 14 May 2020 20:10:13 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
วิธี GUI
เมื่อคุณมีคำถามจำนวนมากการมี UI ที่เรียบง่ายและวิธีการกรองเรกคอร์ดก็มีประโยชน์ ฉันจะแสดงให้ใช้Chronologerสำหรับสิ่งนั้น (ซึ่งฉันเป็นผู้เขียน)
ขั้นแรกให้เขียนเบ็ดใหม่เพื่อสร้างเร็กคอร์ดที่loggingสามารถต่ออนุกรมกันได้เมื่อส่งผ่านสาย จะมีลักษณะดังนี้:
def logRoundtrip(response, *args, **kwargs): 
    extra = {
        'req': {
            'method': response.request.method,
            'url': response.request.url,
            'headers': response.request.headers,
            'body': response.request.body,
        }, 
        'res': {
            'code': response.status_code,
            'reason': response.reason,
            'url': response.url,
            'headers': response.headers,
            'body': response.text
        },
    }
    logger.debug('HTTP roundtrip', extra=extra)
session = requests.Session()
session.hooks['response'].append(logRoundtrip)
ประการที่สองการกำหนดค่าการบันทึกจะต้องปรับให้เข้ากับการใช้งานlogging.handlers.HTTPHandler(ซึ่ง Chronologer เข้าใจดี)
import logging.handlers
chrono = logging.handlers.HTTPHandler(
  'localhost:8080', '/api/v1/record', 'POST', credentials=('logger', ''))
handlers = [logging.StreamHandler(), chrono]
logging.basicConfig(level=logging.DEBUG, handlers=handlers)
สุดท้ายเรียกใช้อินสแตนซ์ Chronologer เช่นใช้ Docker:
docker run --rm -it -p 8080:8080 -v /tmp/db \
    -e CHRONOLOGER_STORAGE_DSN=sqlite:////tmp/db/chrono.sqlite \
    -e CHRONOLOGER_SECRET=example \
    -e CHRONOLOGER_ROLES="basic-reader query-reader writer" \
    saaj/chronologer \
    python -m chronologer -e production serve -u www-data -g www-data -m
และเรียกใช้คำขออีกครั้ง:
session.get('https://httpbin.org/user-agent')
session.get('https://httpbin.org/status/200')
ตัวจัดการสตรีมจะผลิต:
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): httpbin.org:443
DEBUG:urllib3.connectionpool:https://httpbin.org:443 "GET /user-agent HTTP/1.1" 200 45
DEBUG:httplogger:HTTP roundtrip
DEBUG:urllib3.connectionpool:https://httpbin.org:443 "GET /status/200 HTTP/1.1" 200 0
DEBUG:httplogger:HTTP roundtrip
ตอนนี้ถ้าคุณเปิดhttp: // localhost: 8080 / (ใช้ "logger" สำหรับชื่อผู้ใช้และรหัสผ่านที่ว่างเปล่าสำหรับป๊อปอัปการตรวจสอบสิทธิ์พื้นฐาน) และคลิกปุ่ม "เปิด" คุณจะเห็นสิ่งต่างๆเช่น:
