1# 2# Copyright (C) 2010-2017 Vinay Sajip. See LICENSE.txt for details. 3# 4import logging 5 6class HTTPHandler(logging.Handler): 7 """ 8 A class which sends records to a Web server, using either GET or 9 POST semantics. 10 11 :param host: The Web server to connect to. 12 :param url: The URL to use for the connection. 13 :param method: The HTTP method to use. GET and POST are supported. 14 :param secure: set to True if HTTPS is to be used. 15 :param credentials: Set to a username/password tuple if desired. If 16 set, a Basic authentication header is sent. WARNING: 17 if using credentials, make sure `secure` is `True` 18 to avoid sending usernames and passwords in 19 cleartext over the wire. 20 """ 21 def __init__(self, host, url, method="GET", secure=False, credentials=None): 22 """ 23 Initialize an instance. 24 """ 25 logging.Handler.__init__(self) 26 method = method.upper() 27 if method not in ["GET", "POST"]: 28 raise ValueError("method must be GET or POST") 29 self.host = host 30 self.url = url 31 self.method = method 32 self.secure = secure 33 self.credentials = credentials 34 35 def mapLogRecord(self, record): 36 """ 37 Default implementation of mapping the log record into a dict 38 that is sent as the CGI data. Overwrite in your class. 39 Contributed by Franz Glasner. 40 41 :param record: The record to be mapped. 42 """ 43 return record.__dict__ 44 45 def emit(self, record): 46 """ 47 Emit a record. 48 49 Send the record to the Web server as a percent-encoded dictionary 50 51 :param record: The record to be emitted. 52 """ 53 try: 54 import http.client, urllib.parse 55 host = self.host 56 if self.secure: 57 h = http.client.HTTPSConnection(host) 58 else: 59 h = http.client.HTTPConnection(host) 60 url = self.url 61 data = urllib.parse.urlencode(self.mapLogRecord(record)) 62 if self.method == "GET": 63 if (url.find('?') >= 0): 64 sep = '&' 65 else: 66 sep = '?' 67 url = url + "%c%s" % (sep, data) 68 h.putrequest(self.method, url) 69 # support multiple hosts on one IP address... 70 # need to strip optional :port from host, if present 71 i = host.find(":") 72 if i >= 0: 73 host = host[:i] 74 h.putheader("Host", host) 75 if self.method == "POST": 76 h.putheader("Content-type", 77 "application/x-www-form-urlencoded") 78 h.putheader("Content-length", str(len(data))) 79 if self.credentials: 80 import base64 81 s = ('u%s:%s' % self.credentials).encode('utf-8') 82 s = 'Basic ' + base64.b64encode(s).strip() 83 h.putheader('Authorization', s) 84 h.endheaders(data if self.method == "POST" else None) 85 h.getresponse() #can't do anything with the result 86 except (KeyboardInterrupt, SystemExit): 87 raise 88 except: 89 self.handleError(record) 90