0
0
Fork 0
mirror of https://github.com/alerta/alerta.git synced 2025-02-19 11:43:52 +00:00
alerta_alerta/alerta/syslog/daemon.py

242 lines
8.4 KiB
Python
Raw Permalink Normal View History

2013-02-21 17:23:40 +00:00
import sys
import socket
import select
import re
2013-04-09 18:19:47 +00:00
from alerta.common import config, syslog
2013-02-21 17:23:40 +00:00
from alerta.common import log as logging
from alerta.common.daemon import Daemon
2013-04-09 18:32:54 +00:00
from alerta.common.alert import Alert
from alerta.common.heartbeat import Heartbeat
2013-04-09 18:19:47 +00:00
from alerta.common.dedup import DeDup
from alerta.common.mq import Messaging, MessageHandler
2013-08-08 16:38:32 +00:00
from alerta.common.graphite import StatsD
2013-02-21 17:23:40 +00:00
2014-01-31 15:44:56 +00:00
Version = '2.1.0'
2013-03-03 10:48:32 +00:00
2013-02-21 17:23:40 +00:00
LOG = logging.getLogger(__name__)
CONF = config.CONF
class SyslogMessage(MessageHandler):
def __init__(self, mq):
self.mq = mq
MessageHandler.__init__(self)
def on_disconnected(self):
self.mq.reconnect()
2013-02-21 17:23:40 +00:00
class SyslogDaemon(Daemon):
syslog_opts = {
'syslog_udp_port': 514,
'syslog_tcp_port': 514,
}
def __init__(self, prog, **kwargs):
2013-10-21 15:21:27 +00:00
config.register_opts(SyslogDaemon.syslog_opts)
Daemon.__init__(self, prog, kwargs)
2013-02-21 17:23:40 +00:00
def run(self):
self.running = True
LOG.info('Starting UDP listener...')
# Set up syslog UDP listener
try:
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.bind(('', CONF.syslog_udp_port))
except socket.error, e:
LOG.error('Syslog UDP error: %s', e)
sys.exit(2)
LOG.info('Listening on syslog port %s/udp' % CONF.syslog_udp_port)
LOG.info('Starting TCP listener...')
# Set up syslog TCP listener
try:
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp.bind(('', CONF.syslog_tcp_port))
tcp.listen(5)
except socket.error, e:
LOG.error('Syslog TCP error: %s', e)
sys.exit(2)
LOG.info('Listening on syslog port %s/tcp' % CONF.syslog_tcp_port)
2013-08-08 16:38:32 +00:00
self.statsd = StatsD() # graphite metrics
2013-02-21 17:23:40 +00:00
# Connect to message queue
self.mq = Messaging()
self.mq.connect(callback=SyslogMessage(self.mq))
2013-02-21 17:23:40 +00:00
2013-04-07 20:00:07 +00:00
self.dedup = DeDup(by_value=True)
count = 0
2013-02-21 17:23:40 +00:00
while not self.shuttingdown:
try:
LOG.debug('Waiting for syslog messages...')
2013-03-07 12:59:14 +00:00
ip, op, rdy = select.select([udp, tcp], [], [], CONF.loop_every)
2013-03-04 14:39:21 +00:00
if ip:
for i in ip:
if i == udp:
2013-06-19 23:40:46 +00:00
data, addr = udp.recvfrom(4096)
2013-06-25 15:36:23 +00:00
data = unicode(data, 'utf-8', errors='ignore')
2013-06-19 23:40:46 +00:00
LOG.debug('Syslog UDP data received from %s: %s', addr, data)
2013-03-04 14:39:21 +00:00
if i == tcp:
client, addr = tcp.accept()
data = client.recv(4096)
2013-06-25 15:36:23 +00:00
data = unicode(data, 'utf-8', errors='ignore')
2013-03-04 14:39:21 +00:00
client.close()
2013-06-19 23:40:46 +00:00
LOG.debug('Syslog TCP data received from %s: %s', addr, data)
2013-03-04 14:39:21 +00:00
2013-06-19 23:40:46 +00:00
syslogAlerts = self.parse_syslog(addr[0], data)
2013-04-04 15:28:10 +00:00
for syslogAlert in syslogAlerts:
2013-04-07 20:00:07 +00:00
if self.dedup.is_send(syslogAlert):
self.mq.send(syslogAlert)
2013-08-08 16:38:32 +00:00
self.statsd.metric_send('alert.syslog.alerts.total', 1)
count += 1
2013-03-26 13:06:16 +00:00
if not ip or count % 5 == 0:
2013-03-04 14:39:21 +00:00
LOG.debug('Send heartbeat...')
heartbeat = Heartbeat(version=Version)
self.mq.send(heartbeat)
2013-03-01 23:43:56 +00:00
except (KeyboardInterrupt, SystemExit):
2013-02-21 17:23:40 +00:00
self.shuttingdown = True
LOG.info('Shutdown request received...')
self.running = False
LOG.info('Disconnecting from message broker...')
self.mq.disconnect()
def parse_syslog(self, addr, data):
2013-02-21 17:23:40 +00:00
LOG.debug('Parsing syslog message...')
2013-04-04 15:28:10 +00:00
syslogAlerts = list()
2013-02-21 17:23:40 +00:00
2013-06-19 23:40:46 +00:00
event = None
resource = None
2013-03-01 15:25:44 +00:00
for msg in data.split('\n'):
2013-04-04 15:28:10 +00:00
# NOTE: if syslog msgs aren't being split on newlines and #012 appears instead then
# try adding "$EscapeControlCharactersOnReceive off" to rsyslog.conf
if not msg or 'last message repeated' in msg:
2013-03-12 16:26:23 +00:00
continue
2013-03-01 15:25:44 +00:00
if re.match('<\d+>1', msg):
# Parse RFC 5424 compliant message
m = re.match(r'<(\d+)>1 (\S+) (\S+) (\S+) (\S+) (\S+) (.*)', msg)
if m:
PRI = int(m.group(1))
ISOTIMESTAMP = m.group(2)
HOSTNAME = m.group(3)
APPNAME = m.group(4)
PROCID = m.group(5)
MSGID = m.group(6)
TAG = '%s[%s] %s' % (APPNAME, PROCID, MSGID)
MSG = m.group(7)
LOG.info("Parsed RFC 5424 message OK")
else:
2013-06-19 23:40:46 +00:00
LOG.error("Could not parse RFC 5424 syslog message: %s", msg)
2013-04-04 15:28:10 +00:00
continue
2013-02-21 17:23:40 +00:00
2013-06-19 23:40:46 +00:00
elif re.match(r'<(\d{1,3})>\S{3}\s', msg):
2013-03-01 15:25:44 +00:00
# Parse RFC 3164 compliant message
m = re.match(r'<(\d{1,3})>\S{3}\s{1,2}\d?\d \d{2}:\d{2}:\d{2} (\S+)( (\S+):)? (.*)', msg)
if m:
PRI = int(m.group(1))
HOSTNAME = m.group(2)
TAG = m.group(4)
MSG = m.group(5)
LOG.info("Parsed RFC 3164 message OK")
else:
2013-06-19 23:40:46 +00:00
LOG.error("Could not parse RFC 3164 syslog message: %s", msg)
continue
elif re.match('<\d+>.*%[A-Z0-9_-]+', msg):
# Parse Cisco Syslog message
m = re.match('<(\d+)>.*(%([A-Z0-9_-]+)):? (.*)', msg)
if m:
LOG.debug(m.groups())
PRI = int(m.group(1))
CISCO_SYSLOG = m.group(2)
try:
CISCO_FACILITY, CISCO_SEVERITY, CISCO_MNEMONIC = m.group(3).split('-')
except ValueError, e:
LOG.error('Could not parse Cisco syslog - %s: %s', e, m.group(3))
CISCO_FACILITY = CISCO_SEVERITY = CISCO_MNEMONIC = 'na'
2013-06-19 23:40:46 +00:00
TAG = CISCO_MNEMONIC
MSG = m.group(4)
event = CISCO_SYSLOG
# replace IP address with a hostname, if necessary
try:
socket.inet_aton(addr)
(resource, _, _) = socket.gethostbyaddr(addr)
except (socket.error, socket.herror):
resource = addr
resource = '%s:%s' % (resource, CISCO_FACILITY)
2013-06-19 23:40:46 +00:00
else:
LOG.error("Could not parse Cisco syslog message: %s", msg)
2013-04-04 15:28:10 +00:00
continue
2013-03-01 15:25:44 +00:00
facility, level = syslog.decode_priority(PRI)
# Defaults
2013-06-19 23:40:46 +00:00
event = event or '%s%s' % (facility.capitalize(), level.capitalize())
resource = resource or '%s%s' % (HOSTNAME, ':' + TAG if TAG else '')
2013-03-08 11:13:02 +00:00
severity = syslog.priority_to_code(level)
group = 'Syslog'
2013-03-11 22:37:52 +00:00
value = level
2013-03-08 11:13:02 +00:00
text = MSG
2013-03-01 15:25:44 +00:00
environment = ['INFRA']
2013-03-08 11:13:02 +00:00
service = ['Platform']
2014-01-31 16:33:41 +00:00
tags = {'syslogPriority': '%s.%s' % (facility, level)}
2013-03-08 11:13:02 +00:00
correlate = list()
timeout = None
threshold_info = None
summary = None
2013-03-12 13:13:56 +00:00
raw_data = msg
2013-02-21 17:23:40 +00:00
2013-03-01 15:25:44 +00:00
syslogAlert = Alert(
resource=resource,
event=event,
correlate=correlate,
group=group,
value=value,
severity=severity,
environment=environment,
service=service,
text=text,
event_type='syslogAlert',
tags=tags,
2013-03-08 11:13:02 +00:00
timeout=timeout,
threshold_info=threshold_info,
summary=summary,
2013-03-12 13:13:56 +00:00
raw_data=raw_data,
2013-03-01 15:25:44 +00:00
)
2013-03-08 11:13:02 +00:00
suppress = syslogAlert.transform_alert(facility=facility, level=level)
if suppress:
LOG.info('Suppressing %s.%s alert', facility, level)
LOG.debug('%s', syslogAlert)
2013-04-04 15:28:10 +00:00
continue
if syslogAlert.get_type() == 'Heartbeat':
2013-06-25 09:07:49 +00:00
syslogAlert = Heartbeat(origin=syslogAlert.origin, version='n/a', timeout=syslogAlert.timeout)
2013-04-04 15:28:10 +00:00
syslogAlerts.append(syslogAlert)
2013-03-08 11:13:02 +00:00
2013-04-04 15:28:10 +00:00
return syslogAlerts