1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
"""Provide a way to emit logs to an HTTP endpoint"""
import logging
import json
import traceback
import urllib.request
from datetime import datetime
class SilentHTTPHandler(logging.Handler):
"""A logging handler that emits logs to an HTTP endpoint silently.
This handler converts log records to JSON and sends them via POST
to a specified HTTP endpoint. Failures are suppressed to avoid
interfering with the main application.
"""
def __init__(self, endpoint, timeout=0.1):
super().__init__()
self.endpoint = endpoint
self.timeout = timeout
def emit(self, record):
try:
payload = {
"timestamp": datetime.utcfromtimestamp(record.created).isoformat(),
"level": record.levelname.lower(),
"logger": record.name,
"message": record.getMessage(),
}
for attr in ("remote_addr", "user_agent", "extra"):
if hasattr(record, attr):
payload.update({attr: getattr(record, attr)})
if record.exc_info:
payload["exception"] = "".join(
traceback.format_exception(*record.exc_info)
)
# fire-and-forget
self._send(payload)
except Exception:
# absolute silence
pass
def _send(self, payload):
try:
req = urllib.request.Request(
url=self.endpoint,
data=json.dumps(payload).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req, timeout=5) as resp:
resp.read() # ignore body
except Exception:
pass
|