Skip to content

Instantly share code, notes, and snippets.

@kitos9112
Forked from hectcastro/handlers.py
Created November 22, 2017 13:38
Show Gist options
  • Save kitos9112/f77439d2aa421e0c76226d27de7ff132 to your computer and use it in GitHub Desktop.
Save kitos9112/f77439d2aa421e0c76226d27de7ff132 to your computer and use it in GitHub Desktop.
A Python log handler for Papertrail.
import logging
import socket
class PapertrailHandler(logging.Handler):
"""An RFC 5425 log handler that has been tested to interact
with Papertrail.
"""
# RFC 5424 Severities
LOG_EMERG = 0
LOG_ALERT = 1
LOG_CRIT = 2
LOG_ERR = 3
LOG_WARNING = 4
LOG_NOTICE = 5
LOG_INFO = 6
LOG_DEBUG = 7
# RFC 5424 Facilities
LOG_KERN = 0
LOG_USER = 1
LOG_MAIL = 2
LOG_DAEMON = 3
LOG_AUTH = 4
LOG_SYSLOG = 5
LOG_LPR = 6
LOG_NEWS = 7
LOG_UUCP = 8
LOG_CRON = 9
LOG_AUTHPRIV = 10
LOG_FTP = 11
LOG_NTP = 12
LOG_AUDIT = 13
LOG_ALERT = 14
LOG_AT = 15
LOG_LOCAL0 = 16
LOG_LOCAL1 = 17
LOG_LOCAL2 = 18
LOG_LOCAL3 = 19
LOG_LOCAL4 = 20
LOG_LOCAL5 = 21
LOG_LOCAL6 = 22
LOG_LOCAL7 = 23
priority_names = {
'emerg': LOG_EMERG,
'alert': LOG_ALERT,
'crit': LOG_CRIT,
'err': LOG_ERR,
'warn': LOG_WARNING,
'notice': LOG_NOTICE,
'info': LOG_INFO,
'debug': LOG_DEBUG,
}
facility_names = {
'kern': LOG_KERN,
'user': LOG_USER,
'mail': LOG_MAIL,
'daemon': LOG_DAEMON,
'auth': LOG_AUTH,
'syslog': LOG_SYSLOG,
'lpr': LOG_LPR,
'news': LOG_NEWS,
'uucp': LOG_UUCP,
'cron': LOG_CRON,
'authpriv': LOG_AUTHPRIV,
'ftp': LOG_FTP,
'ntp': LOG_NTP,
'audit': LOG_AUDIT,
'alert': LOG_ALERT,
'at': LOG_AT,
'local0': LOG_LOCAL0,
'local1': LOG_LOCAL1,
'local2': LOG_LOCAL2,
'local3': LOG_LOCAL3,
'local4': LOG_LOCAL4,
'local5': LOG_LOCAL5,
'local6': LOG_LOCAL6,
'local7': LOG_LOCAL7,
}
def __init__(self, address=('localhost', 514), facility=LOG_USER,
socktype=socket.SOCK_STREAM):
"""Initialize the PapertrailHandler
Args:
address (tuple): First element is the host, second is the port
facility (int): Integer representation of the syslog facility
socktype (int): Integer representation of the socket type
"""
logging.Handler.__init__(self)
self.address = address
self.facility = facility
self.socktype = socktype
self.socket = socket.socket(socket.AF_INET, socktype)
if socktype == socket.SOCK_STREAM:
self.socket.connect(address)
def encode_priority(self, facility, priority):
"""Encode the syslog facility and priority. Strings or integers are
accepted. If strings are passed, the facility and priority mappings
are used to convert them to integers.
Args:
facility (str, int): A string or integer syslog facility
priority (str, int): A string or integer syslog priority
"""
if isinstance(facility, str):
facility = self.facility_names[facility]
if isinstance(priority, str):
priority = self.priority_names[priority]
return (facility << 3) | priority
def close(self):
"""Closes the socket."""
self.acquire()
try:
self.socket.close()
logging.Handler.close(self)
finally:
self.release()
def clean_record(self, record):
"""Clean log entry by removing newlines and NUL bytes.
Args:
record (LogRecord): A log record
"""
return self.format(
record).replace('\n', ' ').replace('\r', ' ').replace('\x00', ' ')
def emit(self, record):
"""Emit a formatted record, which is then sent to the syslog server.
If exception information is present, the message is NOT sent to the
server.
Args:
record (str): A log entry
"""
try:
priority = self.encode_priority(self.facility,
self.priority_names.get(
record.levelname.lower(),
'warning'))
message = '<{}>{}\n'.format(priority,
self.clean_record(record))
if self.socktype == socket.SOCK_DGRAM:
self.socket.sendto(message[:1024].encode('utf-8'),
self.address)
else:
self.socket.sendall('{}\n'.format(message).encode('utf-8'))
except Exception:
self.handleError(record)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment