บันทึกคำขอทั้งหมดจากโมดูลคำขอ python


101

ฉันใช้หลามจอง ฉันจำเป็นต้องดีบักOAuthกิจกรรมบางอย่างและฉันต้องการให้มันบันทึกคำขอทั้งหมดที่กำลังดำเนินการ ฉันสามารถรับข้อมูลนี้ได้ngrepแต่น่าเสียดายที่ไม่สามารถเชื่อมต่อ grep https ได้ (ซึ่งจำเป็นสำหรับOAuth)

ฉันจะเปิดใช้งานการบันทึก URL ทั้งหมด (+ พารามิเตอร์) ที่Requestsเข้าถึงได้อย่างไร


การตอบกลับโดย @yohann แสดงวิธีรับเอาต์พุตการบันทึกเพิ่มเติมรวมถึงส่วนหัวที่คุณกำลังส่ง ควรเป็นคำตอบที่ได้รับการยอมรับแทนที่จะเป็นของ Martijn ซึ่งจะไม่แสดงส่วนหัวที่คุณได้รับผ่าน Wi-Fi และกำหนดคำขอด้วยมือแทน
nealmcb

คำตอบ:


98

urllib3ไลบรารีที่อยู่ภายใต้บันทึกการเชื่อมต่อและ URL ใหม่ทั้งหมดด้วยloggingโมดูลแต่ไม่ใช่POSTเนื้อหา สำหรับGETการร้องขอสิ่งนี้ควรเพียงพอ:

import logging

logging.basicConfig(level=logging.DEBUG)

ซึ่งให้ตัวเลือกการบันทึกที่ละเอียดที่สุดแก่คุณ ดูHOWTO การบันทึกสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีกำหนดค่าระดับการบันทึกและปลายทาง

การสาธิตสั้น ๆ :

>>> import requests
>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> r = requests.get('http://httpbin.org/get?foo=bar&baz=python')
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): httpbin.org:80
DEBUG:urllib3.connectionpool:http://httpbin.org:80 "GET /get?foo=bar&baz=python HTTP/1.1" 200 366

ขึ้นอยู่กับเวอร์ชันที่แน่นอนของ urllib3 ข้อความต่อไปนี้จะถูกบันทึก:

  • INFO: เปลี่ยนเส้นทาง
  • WARN: พูลการเชื่อมต่อเต็ม (หากสิ่งนี้เกิดขึ้นมักจะเพิ่มขนาดพูลการเชื่อมต่อ)
  • WARN: ไม่สามารถแยกวิเคราะห์ส่วนหัว (ส่วนหัวการตอบกลับที่มีรูปแบบไม่ถูกต้อง)
  • WARN: กำลังลองเชื่อมต่ออีกครั้ง
  • WARN: ใบรับรองไม่ตรงกับชื่อโฮสต์ที่คาดไว้
  • WARN: ได้รับการตอบกลับพร้อมทั้ง Content-Length และ Transfer-Encoding เมื่อประมวลผลการตอบกลับแบบเป็นกลุ่ม
  • DEBUG: การเชื่อมต่อใหม่ (HTTP หรือ HTTPS)
  • DEBUG: หลุดการเชื่อมต่อ
  • DEBUG: รายละเอียดการเชื่อมต่อ: วิธีการเส้นทางเวอร์ชัน HTTP รหัสสถานะและความยาวการตอบกลับ
  • DEBUG: ลองนับเพิ่มอีกครั้ง

ซึ่งไม่รวมถึงส่วนหัวหรือเนื้อหา urllib3ใช้http.client.HTTPConnectionคลาสเพื่อทำงานหนัก แต่คลาสนั้นไม่รองรับการบันทึกโดยปกติจะสามารถกำหนดค่าให้พิมพ์เป็น stdout เท่านั้น อย่างไรก็ตามคุณสามารถกำหนดให้ส่งข้อมูลการดีบักทั้งหมดไปยังการบันทึกแทนได้โดยแนะนำprintชื่ออื่นในโมดูลนั้น:

import logging
import http.client

httpclient_logger = logging.getLogger("http.client")

def httpclient_logging_patch(level=logging.DEBUG):
    """Enable HTTPConnection debug logging to the logging framework"""

    def httpclient_log(*args):
        httpclient_logger.log(level, " ".join(args))

    # mask the print() built-in in the http.client module to use
    # logging instead
    http.client.print = httpclient_log
    # enable debugging
    http.client.HTTPConnection.debuglevel = 1

การโทรhttpclient_logging_patch()ทำให้เกิดhttp.clientการเชื่อมต่อเพื่อส่งออกข้อมูลการดีบักทั้งหมดไปยังเครื่องบันทึกมาตรฐานดังนั้นจึงถูกเลือกโดยlogging.basicConfig():

>>> httpclient_logging_patch()
>>> r = requests.get('http://httpbin.org/get?foo=bar&baz=python')
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): httpbin.org:80
DEBUG:http.client:send: b'GET /get?foo=bar&baz=python HTTP/1.1\r\nHost: httpbin.org\r\nUser-Agent: python-requests/2.22.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\n\r\n'
DEBUG:http.client:reply: 'HTTP/1.1 200 OK\r\n'
DEBUG:http.client:header: Date: Tue, 04 Feb 2020 13:36:53 GMT
DEBUG:http.client:header: Content-Type: application/json
DEBUG:http.client:header: Content-Length: 366
DEBUG:http.client:header: Connection: keep-alive
DEBUG:http.client:header: Server: gunicorn/19.9.0
DEBUG:http.client:header: Access-Control-Allow-Origin: *
DEBUG:http.client:header: Access-Control-Allow-Credentials: true
DEBUG:urllib3.connectionpool:http://httpbin.org:80 "GET /get?foo=bar&baz=python HTTP/1.1" 200 366

2
น่าแปลกที่ฉันไม่เห็นaccess_tokenคำขอ OAuth ในคำขอ Linkedin กำลังบ่นเกี่ยวกับคำขอที่ไม่ได้รับอนุญาตและฉันต้องการตรวจสอบว่าไลบรารีที่ฉันใช้ ( rauthด้านบนrequests) กำลังส่งโทเค็นนั้นพร้อมกับคำขอหรือไม่ ฉันคาดหวังว่าจะเห็นสิ่งนั้นเป็นพารามิเตอร์การค้นหา แต่อาจอยู่ในส่วนหัวของคำขอ? ฉันจะบังคับurllib3ให้แสดงส่วนหัวด้วยได้อย่างไร และตัวขอ? เพื่อให้ง่าย: ฉันจะดูคำขอแบบเต็มได้อย่างไร
blueFast

คุณไม่สามารถทำได้โดยไม่ต้องปะฉันกลัว วิธีที่ใช้บ่อยที่สุดในการวินิจฉัยปัญหาดังกล่าวคือการใช้พร็อกซีหรือตัวบันทึกแพ็กเก็ต (ฉันใช้ Wirehark เพื่อรวบรวมคำขอและการตอบกลับแบบเต็มด้วยตัวเอง) ฉันเห็นคุณถามคำถามใหม่ในเรื่องนี้ว่า
Martijn Pieters

1
แน่นอนว่าตอนนี้ฉันกำลังดีบักด้วย wirehark แต่ฉันมีปัญหา: ถ้าฉันทำ http ฉันเห็นเนื้อหาแพ็คเก็ตทั้งหมด แต่ Linkedin ส่งคืน 401 ซึ่งคาดว่าจะเป็นเพราะ Linkedin บอกให้ใช้ https แต่ด้วย https มันก็ใช้งานไม่ได้เช่นกันและฉันไม่สามารถดีบักได้เนื่องจากฉันไม่สามารถตรวจสอบเลเยอร์ TLS ด้วย Wirehark ได้
blueFast

1
@nealmcb: ใช่แล้วการตั้งค่าแอตทริบิวต์คลาสส่วนกลางจะเปิดใช้งานการดีบักในhttplib. ฉันหวังว่าห้องสมุดจะใช้loggingแทน; เอาต์พุตดีบักถูกเขียนโดยตรงไปยัง stdout แทนที่จะให้คุณเปลี่ยนเส้นทางไปยังปลายทางของบันทึกที่คุณเลือก
Martijn Pieters


113

แต่คุณต้องเปิดการใช้งานการแก้จุดบกพร่องที่httplibระดับ ( requests→การurllib3→การhttplib)

ต่อไปนี้เป็นฟังก์ชั่นบางอย่างในการสลับ ( ..._on()และ..._off()) หรือเปิดใช้งานชั่วคราว:

import logging
import contextlib
try:
    from http.client import HTTPConnection # py3
except ImportError:
    from httplib import HTTPConnection # py2

def debug_requests_on():
    '''Switches on logging of the requests module.'''
    HTTPConnection.debuglevel = 1

    logging.basicConfig()
    logging.getLogger().setLevel(logging.DEBUG)
    requests_log = logging.getLogger("requests.packages.urllib3")
    requests_log.setLevel(logging.DEBUG)
    requests_log.propagate = True

def debug_requests_off():
    '''Switches off logging of the requests module, might be some side-effects'''
    HTTPConnection.debuglevel = 0

    root_logger = logging.getLogger()
    root_logger.setLevel(logging.WARNING)
    root_logger.handlers = []
    requests_log = logging.getLogger("requests.packages.urllib3")
    requests_log.setLevel(logging.WARNING)
    requests_log.propagate = False

@contextlib.contextmanager
def debug_requests():
    '''Use with 'with'!'''
    debug_requests_on()
    yield
    debug_requests_off()

ใช้สาธิต:

>>> requests.get('http://httpbin.org/')
<Response [200]>

>>> debug_requests_on()
>>> requests.get('http://httpbin.org/')
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): httpbin.org
DEBUG:requests.packages.urllib3.connectionpool:"GET / HTTP/1.1" 200 12150
send: 'GET / HTTP/1.1\r\nHost: httpbin.org\r\nConnection: keep-alive\r\nAccept-
Encoding: gzip, deflate\r\nAccept: */*\r\nUser-Agent: python-requests/2.11.1\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Server: nginx
...
<Response [200]>

>>> debug_requests_off()
>>> requests.get('http://httpbin.org/')
<Response [200]>

>>> with debug_requests():
...     requests.get('http://httpbin.org/')
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): httpbin.org
...
<Response [200]>

คุณจะเห็นคำขอรวมถึง HEADERS และ DATA และการตอบสนองกับ HEADERS แต่ไม่มีข้อมูล สิ่งเดียวที่ขาดหายไปคือการตอบสนองคนที่ไม่ได้บันทึกไว้

ที่มา


ขอบคุณสำหรับข้อมูลเชิงลึกเกี่ยวกับการใช้httplib.HTTPConnection.debuglevel = 1เพื่อรับส่วนหัว - ยอดเยี่ยมมาก! แต่ฉันคิดว่าฉันได้ผลลัพธ์แบบเดียวกันโดยใช้เพียงแค่logging.basicConfig(level=logging.DEBUG)แทนที่ 5 บรรทัดอื่น ๆ ของคุณ ฉันพลาดอะไรไปรึเปล่า? ฉันเดาว่าอาจเป็นวิธีตั้งค่าระดับการบันทึกที่แตกต่างกันสำหรับรูทเทียบกับ urllib3 หากต้องการ
nealmcb

คุณไม่มีส่วนหัวกับโซลูชันของคุณ
Yohann

7
httplib.HTTPConnection.debuglevel = 2จะอนุญาตให้พิมพ์เนื้อหา POST ได้เช่นกัน
Mandible79

1
httplib.HTTPConnection.debuglevel = 1is enough @ Mandible79 $ curl https://raw.githubusercontent.com/python/cpython/master/Lib/http/client.py |grep debuglevelit's alwaysdebuglevel > 0
Yohann

3
Someway เพื่อป้องกันไม่ให้เนื้อหาที่บันทึกไว้ถูกส่งไปยังเอาต์พุตมาตรฐาน?
yucer

49

สำหรับผู้ที่ใช้ python 3+

import requests
import logging
import http.client

http.client.HTTPConnection.debuglevel = 1

logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

ฉันจะทำให้มันทำงานกับล็อกไฟล์ได้อย่างไร ดูเหมือนว่าจะใช้ได้กับstdout. ตัวอย่างปัญหาที่นี่: stackoverflow.com/q/58738195/1090360
JackTheKnife

17

เมื่อพยายามรับระบบบันทึก Python ( import logging) เพื่อส่งข้อความบันทึกการดีบักระดับต่ำฉันรู้สึกประหลาดใจที่พบว่า:

requests --> urllib3 --> http.client.HTTPConnection

ที่urllib3ใช้loggingระบบPython จริงเท่านั้น:

  • requests ไม่
  • http.client.HTTPConnection ไม่
  • urllib3 ใช่

แน่นอนคุณสามารถแยกข้อความดีบักจากHTTPConnectionการตั้งค่า:

HTTPConnection.debuglevel = 1

แต่ผลลัพธ์เหล่านี้ถูกส่งออกมาทางprintคำสั่งเท่านั้น เพื่อพิสูจน์สิ่งนี้เพียงแค่ grep client.pyซอร์สโค้ดPython 3.7 และดูคำสั่งพิมพ์ด้วยตัวคุณเอง (ขอบคุณ @Yohann):

curl https://raw.githubusercontent.com/python/cpython/3.7/Lib/http/client.py |grep -A1 debuglevel` 

สันนิษฐานว่าการเปลี่ยนเส้นทาง stdout ไม่ทางใดก็ทางหนึ่งอาจส่งผลให้รองเท้าฮอร์น stdout เข้าสู่ระบบบันทึกและอาจจับไปที่ไฟล์บันทึก

เลือก ' urllib3' คนตัดไม้ไม่ ' requests.packages.urllib3'

ในการดักจับurllib3ข้อมูลการดีบักผ่านระบบ Python 3 loggingตรงกันข้ามกับคำแนะนำมากมายบนอินเทอร์เน็ตและตามที่ @MikeSmith ชี้ให้เห็นคุณจะไม่มีโชคมากนักในการสกัดกั้น:

log = logging.getLogger('requests.packages.urllib3')

แทนคุณต้อง:

log = logging.getLogger('urllib3')

การดีบักurllib3ไฟล์บันทึก

นี่คือรหัสบางส่วนที่บันทึกการurllib3ทำงานไปยังไฟล์บันทึกโดยใช้loggingระบบPython :

import requests
import logging
from http.client import HTTPConnection  # py3

# log = logging.getLogger('requests.packages.urllib3')  # useless
log = logging.getLogger('urllib3')  # works

log.setLevel(logging.DEBUG)  # needed
fh = logging.FileHandler("requests.log")
log.addHandler(fh)

requests.get('http://httpbin.org/')

ผลลัพธ์:

Starting new HTTP connection (1): httpbin.org:80
http://httpbin.org:80 "GET / HTTP/1.1" 200 3168

การเปิดใช้งานHTTPConnection.debuglevelคำสั่ง print ()

หากคุณตั้งค่า HTTPConnection.debuglevel = 1

from http.client import HTTPConnection  # py3
HTTPConnection.debuglevel = 1
requests.get('http://httpbin.org/')

คุณจะได้รับผลลัพธ์คำสั่งพิมพ์ของข้อมูลระดับต่ำฉ่ำเพิ่มเติม:

send: b'GET / HTTP/1.1\r\nHost: httpbin.org\r\nUser-Agent: python- 
requests/2.22.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Access-Control-Allow-Credentials header: Access-Control-Allow-Origin 
header: Content-Encoding header: Content-Type header: Date header: ...

โปรดจำไว้ว่าเอาต์พุตนี้ใช้printและไม่ใช่loggingระบบPython ดังนั้นจึงไม่สามารถจับภาพโดยใช้loggingสตรีมแบบดั้งเดิมหรือตัวจัดการไฟล์(แม้ว่าอาจเป็นไปได้ที่จะจับเอาต์พุตไปยังไฟล์โดยเปลี่ยนเส้นทาง stdout) (แม้ว่ามันอาจจะเป็นไปได้ที่จะส่งออกไปยังแฟ้มจับภาพโดยการเปลี่ยนทิศ)

รวมสองข้อด้านบน - เพิ่มการบันทึกทั้งหมดที่เป็นไปได้ไปยังคอนโซล

ในการเพิ่มการบันทึกที่เป็นไปได้ทั้งหมดคุณต้องกำหนดเอาต์พุตคอนโซล / stdout ด้วยสิ่งนี้:

import requests
import logging
from http.client import HTTPConnection  # py3

log = logging.getLogger('urllib3')
log.setLevel(logging.DEBUG)

# logging from urllib3 to console
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
log.addHandler(ch)

# print statements from `http.client.HTTPConnection` to console/stdout
HTTPConnection.debuglevel = 1

requests.get('http://httpbin.org/')

ให้เอาต์พุตเต็มรูปแบบ:

Starting new HTTP connection (1): httpbin.org:80
send: b'GET / HTTP/1.1\r\nHost: httpbin.org\r\nUser-Agent: python-requests/2.22.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
http://httpbin.org:80 "GET / HTTP/1.1" 200 3168
header: Access-Control-Allow-Credentials header: Access-Control-Allow-Origin 
header: Content-Encoding header: ...

3
แล้วการเปลี่ยนเส้นทางรายละเอียดการพิมพ์ไปยังคนตัดไม้ล่ะ?
yucer

คุณประสบความสำเร็จในการพิมพ์รายละเอียดไปยังคนตัดไม้หรือไม่?
Erika Dsouza

4

การมีสคริปต์หรือแม้แต่ระบบย่อยของแอปพลิเคชันสำหรับการดีบักโปรโตคอลเครือข่ายคุณต้องการดูว่าคู่ของคำขอตอบสนองคืออะไรกันแน่รวมถึง 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" สำหรับชื่อผู้ใช้และรหัสผ่านที่ว่างเปล่าสำหรับป๊อปอัปการตรวจสอบสิทธิ์พื้นฐาน) และคลิกปุ่ม "เปิด" คุณจะเห็นสิ่งต่างๆเช่น:

ภาพหน้าจอของ Chronologer


2

ฉันใช้ python 3.4 ขอ 2.19.1:

'urllib3' เป็นเครื่องมือตัดไม้ที่จะได้รับในขณะนี้ (ไม่ใช่ 'request.packages.urllib3' อีกต่อไป) การบันทึกพื้นฐานจะยังคงเกิดขึ้นโดยไม่ต้องตั้งค่า http.client.HTTPConnection.debuglevel


1
มันจะดีกว่ามากถ้าคุณอธิบายเพิ่มเติม
Jamie Lindsey

0

ฉันใช้logger_config.yamlไฟล์เพื่อกำหนดค่าการบันทึกของฉันและเพื่อให้บันทึกเหล่านั้นปรากฏขึ้นสิ่งที่ฉันต้องทำก็คือเพิ่ม a disable_existing_loggers: Falseต่อท้ายไฟล์

การตั้งค่าการบันทึกของฉันค่อนข้างกว้างขวางและสับสนดังนั้นฉันจึงไม่รู้วิธีที่ดีในการอธิบายที่นี่ แต่ถ้ามีใครใช้ไฟล์ YAML เพื่อกำหนดค่าการบันทึกด้วยสิ่งนี้อาจช่วยได้

https://docs.python.org/3/howto/logging.html#configuring-logging


0

เพียงแค่ปรับปรุงคำตอบนี้

นี่คือวิธีการทำงานสำหรับฉัน:

import logging
import sys    
import requests
import textwrap
    
root = logging.getLogger('httplogger')


def logRoundtrip(response, *args, **kwargs):
    extra = {'req': response.request, 'res': response}
    root.debug('HTTP roundtrip', extra=extra)
    

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(sys.stdout)
handler.setFormatter(formatter)
root.addHandler(handler)
root.setLevel(logging.DEBUG)


session = requests.Session()
session.hooks['response'].append(logRoundtrip)
session.get('http://httpbin.org')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.