Bir ağ protokolü hata ayıklaması için bir komut dosyasına veya hatta bir uygulamanın bir alt sistemine sahipken, etkili URL'ler, başlıklar, yükler ve durum dahil olmak üzere istek-yanıt çiftlerinin tam olarak ne olduğunu görmek istenir. Ve her yerde bireysel istekleri belgelemek genellikle pratik değildir. Aynı zamanda, tek (veya birkaç uzmanlık) kullanılmasını öneren performans değerlendirmeleri vardır requests.Session
, bu nedenle aşağıdaki önerinin izlendiğini varsayar .
requests
olay kancalarını destekler (2.23 itibariyle aslında yalnızca response
kanca vardır). Temelde bir olay dinleyicisidir ve olay, denetimden geri dönmeden önce yayınlanır requests.request
. Şu anda hem istek hem de yanıt tam olarak tanımlanmıştır, dolayısıyla günlüğe kaydedilebilir.
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)
Bu, temelde bir oturumun tüm HTTP gidiş-dönüşlerinin günlüğe kaydedilmesidir.
HTTP gidiş-dönüş günlük kayıtlarını biçimlendirme
Yukarıdaki günlüğe kaydetmenin yararlı olması için , günlük kayıtlarını anlayan ve bunlarla ilgili ekstralar sağlayan özel bir günlük biçimlendiricisi olabilir . Şöyle görünebilir: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])
Şimdi session
, aşağıdaki gibi bazı isteklerde bulunursanız :
session.get('https://httpbin.org/user-agent')
session.get('https://httpbin.org/status/200')
Çıktı stderr
aşağıdaki gibi görünecektir.
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 yolu
Çok fazla sorunuz olduğunda, basit bir kullanıcı arayüzüne ve kayıtları filtrelemenin bir yoluna sahip olmak kullanışlı olur. Bunun için Chronologer'ı kullanmayı göstereceğim (yazarı benim).
İlk olarak, logging
kablo üzerinden gönderirken serileştirebilen kayıtlar üretmek için kanca yeniden yazılmalıdır . Şöyle görünebilir:
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)
İkinci olarak, günlük kaydı yapılandırmasının kullanıma uyarlanması gerekir logging.handlers.HTTPHandler
(bunu Chronologer anlar).
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)
Son olarak, Chronologer örneğini çalıştırın. örneğin Docker kullanarak:
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
Ve istekleri tekrar çalıştırın:
session.get('https://httpbin.org/user-agent')
session.get('https://httpbin.org/status/200')
Akış işleyicisi şunları üretecektir:
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
Şimdi http: // localhost: 8080 / 'i açarsanız (kullanıcı adı için "logger" ve temel kimlik doğrulama açılır penceresi için boş şifre kullanın) ve "Aç" düğmesini tıklarsanız, aşağıdaki gibi bir şey görmelisiniz: