Python-istek modülünden gelen tüm istekleri günlüğe kaydedin


101

Python İsteklerini kullanıyorum . Bazı OAuthetkinliklerde hata ayıklamam gerekiyor ve bunun için gerçekleştirilen tüm istekleri günlüğe kaydetmesini istiyorum. Bu bilgileri ile alabilirim ngrep, ancak ne yazık ki https bağlantılarını grep etmek mümkün değil (bunlar için gerekli OAuth)

Erişen tüm URL'lerin (+ parametrelerin) günlük kaydını nasıl etkinleştirebilirim Requests?


@Yohann'ın yanıtı, gönderdiğiniz başlıklar da dahil olmak üzere daha fazla günlük çıktısının nasıl alınacağını gösterir. Bu, Martijn'inki yerine kabul edilen yanıt olmalıdır; bu, sonunda wireshark aracılığıyla aldığınız ve bunun yerine bir isteği elle özelleştirdiğiniz başlıkları göstermez.
nealmcb

Yanıtlar:


98

Temel urllib3kitaplık, tüm yeni bağlantıları ve URL'leri loggingmodülle birlikte günlüğe kaydeder , ancak POSTgövdeleri kaydetmez. İçin GETistekleri bu yeterli olmalıdır:

import logging

logging.basicConfig(level=logging.DEBUG)

size en ayrıntılı günlük kaydı seçeneğini sunar; Günlük kaydı seviyelerinin ve hedeflerinin nasıl yapılandırılacağı hakkında daha fazla ayrıntı için günlük kaydı NASIL belgesine bakın .

Kısa demo:

>>> 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'ün tam sürümüne bağlı olarak, aşağıdaki mesajlar günlüğe kaydedilir:

  • INFO: Yönlendirmeler
  • WARN: Bağlantı havuzu dolu (bu olursa bağlantı havuzu boyutunu sık sık artırın)
  • WARN: Başlıklar ayrıştırılamadı (geçersiz biçime sahip yanıt başlıkları)
  • WARN: Bağlantı yeniden deneniyor
  • WARN: Sertifika beklenen ana bilgisayar adıyla eşleşmedi
  • WARN: Parçalı bir yanıtı işlerken hem İçerik Uzunluğu hem de Aktarım Kodlaması ile yanıt alındı
  • DEBUG: Yeni bağlantılar (HTTP veya HTTPS)
  • DEBUG: Bırakılan bağlantılar
  • DEBUG: Bağlantı ayrıntıları: yöntem, yol, HTTP sürümü, durum kodu ve yanıt uzunluğu
  • DEBUG: Sayım artışlarını yeniden dene

Bu, başlıkları veya gövdeleri içermez. grunt-work yapmak urllib3için http.client.HTTPConnectionsınıfı kullanır , ancak bu sınıf günlüğe kaydetmeyi desteklemez, normalde yalnızca stdout'a yazdırmak üzere yapılandırılabilir . Ancak, printbu modüle alternatif bir ad ekleyerek tüm hata ayıklama bilgilerini günlüğe gönderecek şekilde düzenleyebilirsiniz :

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

Çağrı httpclient_logging_patch(), http.clientbağlantıların tüm hata ayıklama bilgilerini standart bir kaydediciye vermesine neden olur ve bu nedenle şunlar tarafından alınır 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
Garip bir şekilde access_token, OAuth isteğinde görmüyorum . Linkedin yetkisiz talepten şikayetçi ve kullandığım kütüphanenin ( rauthen üstünde requests) bu jetonu taleple birlikte gönderip göndermediğini doğrulamak istiyorum . Bunu bir sorgu parametresi olarak görmeyi bekliyordum, ancak istek başlıklarında olabilir mi? urllib3Başlıkları da göstermeye nasıl zorlayabilirim ? Ve istek gövdesi? Sırf basitleştirmek için: TAM isteği nasıl görebilirim ?
blueFast

Korkarım bunu yama yapmadan yapamazsınız. Bu tür sorunları teşhis etmenin en yaygın yolu bir proxy veya paket kaydedicidir (tüm istekleri ve yanıtları kendim yakalamak için wireshark kullanıyorum). Yine de konuyla ilgili yeni bir soru sormuşsunuz.
Martijn Pieters

1
Elbette şu anda wireshark ile hata ayıklama yapıyorum ama bir sorunum var: http yaparsam paket içeriklerinin tamamını görüyorum, ancak Linkedin https kullanmayı söylediği için Linkedin beklenen 401'i döndürüyor. Ancak https ile de çalışmıyor ve TLS katmanını wireshark ile inceleyemediğim için hata ayıklayamıyorum.
blueFast

1
@nealmcb: gah, evet, global bir sınıf özniteliği ayarlamak gerçekten de hata ayıklamayı etkinleştirir httplib. Bunun loggingyerine kütüphanenin kullanılmasını diliyorum ; hata ayıklama çıktısı, seçtiğiniz bir günlük hedefine yönlendirmenize izin vermek yerine doğrudan stdout'a yazılır.
Martijn Pieters


113

httplib( requestsurllib3httplib) düzeyinde hata ayıklamayı etkinleştirmeniz gerekir .

Hem geçiş yapmak ( ..._on()ve ..._off()) hem de geçici olarak açmak için bazı işlevler şunlardır:

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()

Demo kullanımı:

>>> 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]>

BAŞLIKLAR ve VERİLER de dahil olmak üzere TALEP ve BAŞLIKLAR ile ancak VERİ olmadan YANIT'ı göreceksiniz. Eksik olan tek şey, kaydedilmemiş olan yanıt olacaktır.

Kaynak


httplib.HTTPConnection.debuglevel = 1Üstbilgileri almak için kullanma konusundaki fikir için teşekkür ederiz - mükemmel! Ama sanırım aynı sonuçları logging.basicConfig(level=logging.DEBUG)diğer 5 satırınızın yerine kullanarak alıyorum . Bir şey mi kaçırıyorum? Sanırım bu, istenirse, urllib3'e karşı kök için farklı kayıt seviyeleri belirlemenin bir yolu olabilir.
nealmcb

Çözümünüzün başlığına sahip değilsiniz.
Yohann

7
httplib.HTTPConnection.debuglevel = 2POST gövdesinin yazdırılmasına da izin verir.
Mandible79

1
httplib.HTTPConnection.debuglevel = 1yeter @ Mandible79 $ curl https://raw.githubusercontent.com/python/cpython/master/Lib/http/client.py |grep debuglevelher zamandebuglevel > 0
Yohann

3
Günlüğe kaydedilen içeriğin standart çıktıya gönderilmesini önlemek için bir yol var mı?
yucer

49

Python 3+ kullananlar için

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

Günlük dosyasıyla çalışmasını nasıl sağlayabilirim? Sadece işe yarıyor gibi görünüyor stdout. Buradaki sorun örneği: stackoverflow.com/q/58738195/1090360
JackTheKnife

17

Python günlük sisteminin ( import logging) düşük seviyeli hata ayıklama günlük mesajları göndermesini sağlamaya çalışırken , aşağıdakilerin verildiğini keşfetmek beni şaşırttı:

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

yalnızca urllib3Python loggingsistemini kullanan :

  • requests Hayır
  • http.client.HTTPConnection Hayır
  • urllib3 Evet

Elbette, aşağıdaki HTTPConnectionayarlarla hata ayıklama mesajlarını ayıklayabilirsiniz :

HTTPConnection.debuglevel = 1

ancak bu çıktılar yalnızca printifade yoluyla yayınlanır . Bunu kanıtlamak için, Python 3.7 client.pykaynak kodunu açmanız ve yazdırma ifadelerini kendiniz görüntülemeniz yeterlidir (teşekkürler @Yohann):

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

Muhtemelen stdout'u bir şekilde yeniden yönlendirmek, stdout'u kayıt sistemine kaydedebilir ve potansiyel olarak örneğin bir günlük dosyasına yakalayabilir.

' urllib3' Değil ' requests.packages.urllib3' seçin

urllib3Python 3 loggingsistemi aracılığıyla hata ayıklama bilgilerini yakalamak için, internetteki pek çok tavsiyenin aksine ve @MikeSmith'in belirttiği gibi, araya girme konusunda pek şansınız olmayacak:

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

bunun yerine yapmanız gerekenler:

log = logging.getLogger('urllib3')

urllib3Bir günlük dosyasına hata ayıklama

İşte urllib3Python loggingsistemini kullanarak çalışmaları bir günlük dosyasına kaydeden bazı kodlar :

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/')

sonuç:

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

HTTPConnection.debuglevelPrint () deyimlerini etkinleştirme

Eğer ayarlarsan HTTPConnection.debuglevel = 1

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

ek sulu düşük seviyeli bilginin baskı ifadesi çıktısını alacaksınız :

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: ...

Bu çıktının printPython loggingsistemini değil, kullandığını ve bu nedenle geleneksel bir loggingakış veya dosya işleyicisi kullanılarak yakalanamayacağını unutmayın (ancak çıktıyı bir dosyaya yeniden yönlendirerek yakalamak mümkün olabilir) .

Yukarıdaki ikisini birleştirin - konsola olası tüm günlük kaydını en üst düzeye çıkarın

Olası tüm günlük kaydını en üst düzeye çıkarmak için, bununla konsol / stdout çıktısına karar vermelisiniz:

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/')

tüm çıktı aralığını verir:

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
Baskı ayrıntılarını kaydediciye yönlendirmeye ne dersiniz?
yucer

yucer yazdırma ayrıntılarını kaydediciye ulaştırmada başarılı oldu mu?
Erika Dsouza

4

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 .

requestsolay kancalarını destekler (2.23 itibariyle aslında yalnızca responsekanca 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:reqres

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ı stderraş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, loggingkablo ü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:

Chronologer ekran görüntüsü


2

Python 3.4 kullanıyorum, 2.19.1 istekler:

'urllib3', şimdi alınacak günlükçüdür (artık 'request.packages.urllib3' değil). Http.client.HTTPConnection.debuglevel ayarlanmadan da temel günlük kaydı yapılacaktır


1
Daha fazla
Jamie Lindsey

0

logger_config.yamlGünlüğe kaydetmemi yapılandırmak için bir dosya kullanıyorum ve bu günlüklerin görünmesini sağlamak için tek yapmam disable_existing_loggers: Falsegereken, sonuna bir a eklemekti .

Günlük kaydı kurulumum oldukça kapsamlı ve kafa karıştırıcı, bu yüzden burada açıklamanın iyi bir yolunu bile bilmiyorum, ancak birisi günlük kaydını yapılandırmak için bir YAML dosyası da kullanıyorsa, bu yardımcı olabilir.

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


0

Sadece bu cevabı geliştiriyorum

Benim için şu şekilde çalıştı:

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')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.