python-requests 모듈의 모든 요청 기록
저는 python Requests를 사용하고 있습니다.디버그해야 합니다.OAuth
활동, 그리고 그것을 위해 저는 수행 중인 모든 요청을 기록하기를 원합니다.는 이 를 저는이정얻수있다니습었을를로 얻을 수 .ngrep
연결을 수 연결에 함).OAuth
)
다음과 같은 모든 URL(+ 매개 변수)의 로깅을 활성화하려면 어떻게 해야 합니까?Requests
에 액세스하고 있습니까?
다음에서 디버깅을 사용하도록 설정해야 합니다.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]>
헤더와 데이터를 포함한 요청과 데이터가 없는 헤더로 응답을 볼 수 있습니다.유일하게 누락된 것은 응답입니다.기록되지 않은 본문.
가 되는 밑에있.urllib3
라이브러리는 모듈과 함께 모든 새 연결 및 URL을 기록하지만 기록하지는 않습니다.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
HTTPS - (HTTP 또는 HTTPS)DEBUG
이 끊겼습니다. 연결이 끊어졌습니다.DEBUG
: method, 버전, 및 response length : 방법, , 상전, 태연코, 응드및길DEBUG
가 증가합니다. 즉, 재시도 횟수가 증가합니다.
여기에는 머리글이나 본문이 포함되지 않습니다. urllib3
를 사용합니다.http.client.HTTPConnection
grunt-work를 수행하는 클래스이지만 해당 클래스는 로깅을 지원하지 않으므로 일반적으로 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
정보를 하기 위한 (연결)를합니다. 즉, 모든 디 버 그 출 기 연 에 의 선 니 됩 택 다 해 서 그 래 결 위 한 하 력 정 로 를 보 거 표 로 준 ▁connect ▁up ▁by ▁picked , 니 다 ▁inform ▁to ▁are 모 ▁logger ions ▁debug ▁output 됩 선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
파이썬 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
Python 로깅 시스템을 가져오려고 할 때 (import logging
메시지를 은 주어진 의 디 다 것 같 보 것 발 고 놀 하 습 랐 견 을 은 과
requests --> urllib3 --> http.client.HTTPConnection
urllib3
는 Python 을 합니다.logging
시스템:
requests
아니요.http.client.HTTPConnection
아니요.urllib3
네.
는 예, 다에서추수있다에서 추출할 수 .HTTPConnection
설정 기준:
HTTPConnection.debuglevel = 1
하지만 이 출력들은 단지 그것을 통해 방출됩니다.print
하기 위해 Python 3.7 Grep을 사용하면 됩니다.client.py
소스 코드와 인쇄문을 직접 확인합니다(감사합니다 @요한).
curl https://raw.githubusercontent.com/python/cpython/3.7/Lib/http/client.py |grep -A1 debuglevel`
stdout을 어떤 식으로든 리디렉션하면 stdout을 로깅 시스템에 적용하고 로그 파일 등에 캡처할 수 있습니다.
를선합니다택다'''를 선택합니다.urllib3
not 거님아로'requests.packages.urllib3
'
캡처하기urllib3
3 Python 는 다음과 .logging
@MikeSmith가 지적했듯이, 시스템은 인터넷에 대한 많은 조언과는 달리, 가로채는 행운이 많지 않을 것입니다.
log = logging.getLogger('requests.packages.urllib3')
대신 다음을 수행해야 합니다.
log = logging.getLogger('urllib3')
디버깅 디urllib3
여기 기록되는 코드가 있습니다.urllib3
Python logging
시스템:
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
를 발행합니다.
설정하는 경우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
시스템, 따라서 전통적인 시스템을 사용하여 캡처할 수 없습니다.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: ...
네트워크 프로토콜 디버깅을 위한 스크립트 또는 애플리케이션의 하위 시스템이 있으므로, 유효 URL, 헤더, 페이로드 및 상태를 포함하여 요청-응답 쌍이 정확히 무엇인지 확인해야 합니다.일반적으로 개별적인 요청을 모든 곳에 적용하는 것은 비현실적입니다.의 전문화된)는▁single▁(▁special▁at▁using▁considerance다▁suggest있▁thatations▁few니ised)or습또▁perform▁are사▁there▁the항(▁same▁time동)를 사용할 것을 제안하는 성능 고려 사항들이 있습니다.requests.Session
따라서 다음은 제안이 따르는 것으로 가정합니다.
requests
이벤트 후크라고 불리는 것을 지원합니다(2.23 기준).response
는 크후)에서 하기 전에 합니다. 기본적으로 이벤트 수신기이며, 이벤트는 에서 제어권을 반환하기 전에 방출됩니다.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)
둘째, 로깅 구성을 사용할 수 있도록 조정해야 합니다(크로놀로거는 이를 이해합니다).
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)
마지막으로 Docker를 사용하여 Chronologer 인스턴스를 실행합니다.
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" 사용)를 열고 "Open" 버튼을 클릭하면 다음과 같은 메시지가 나타납니다.
이 답변을 개선하는 중입니다.
저는 이렇게 생각했습니다.
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')
파이썬 3.4를 사용하고 있습니다. 요청 사항 2.19.1:
'urllib3'이(가) 지금 가져올 로거입니다(더 이상 'urllib3'이 아님).기본 로깅은 http.client를 설정하지 않고 계속 수행됩니다.HTTPConnection.debug 수준
사용 중입니다.logger_config.yaml
로깅을 위해 할 은 를 추가하는 이었습니다.disable_existing_loggers: False
끝까지
내 로깅 설정은 상당히 광범위하고 혼란스러워서 여기서 설명할 수 있는 좋은 방법조차 모르지만 누군가가 YAML 파일을 사용하여 로깅을 구성하고 있다면 도움이 될 수 있습니다.
https://docs.python.org/3/howto/logging.html#configuring-logging
언급URL : https://stackoverflow.com/questions/16337511/log-all-requests-from-the-python-requests-module
'programing' 카테고리의 다른 글
Mongoose로 업데이트된 컬렉션 반환 (0) | 2023.07.17 |
---|---|
도커 합성이 있는 잘못된 문자 만들기 컨테이너 (0) | 2023.07.17 |
pathlib.path에서 지정된 파일이 있는 폴더 이름을 가져오는 방법은 무엇입니까? (0) | 2023.07.17 |
mgo가 삽입된 문서의 ID를 반환하지 않는 이유는 무엇입니까? (0) | 2023.07.17 |
"작업 친화적 동기화 컨텍스트 사용"의 의미는 무엇입니까? (0) | 2023.07.17 |