@@ 0,0 1,43 @@
+import re
+from datetime import datetime
+from itertools import zip_longest
+
+def convert_rfc5424_to_rfc3164(message):
+ # Extract the required fields from the RFC-5424 message
+ # Example RFC-5424 message: '<189>Jun 20 06:31:32 FortiGate-101F_02 - eventtime=1687242692932574340 ...
+ pattern = r'<(\d+)>(\d+ ){0,1}(\S+ \d+ \d+:\d+:\d+) ([\S\s]+) - ([\S\s]+)'
+ match = re.match(pattern, message)
+
+ if not match:
+ return message
+
+ # Extract the necessary fields
+ priority = match.group(1)
+ version = match.group(2)
+ timestamp = match.group(3)
+ hostname = match.group(4)
+ message = match.group(5)
+
+ # Hostname may contains application name and process id (space separated)
+ hostname, appname, procid = [x or y for x, y in zip_longest(['', '', ''], hostname.split(' '), fillvalue='')]
+ syslog_tag = appname
+ if procid:
+ syslog_tag += '-{}'.format(procid)
+ syslog_tag = syslog_tag or '-' # In case that there is no appname and procid
+
+ # Convert the priority to RFC-3164 format
+ rfc5424_pri = int(priority)
+ facility = rfc5424_pri // 8
+ severity = rfc5424_pri % 8
+ rfc3164_pri = facility * 8 + severity
+
+
+ # Convert the timestamp to RFC-3164 format (MMM DD HH:MM:SS)
+ timestamp_dt = datetime.strptime(timestamp, '%b %d %H:%M:%S')
+ timestamp_rfc3164 = timestamp_dt.strftime('%b %d %H:%M:%S')
+
+ # Rearrange the fields according to RFC-3164 format
+ rfc3164_message = '<{}>{} {} {}: {}'.format(rfc3164_pri, timestamp_rfc3164, hostname, syslog_tag, message)
+
+ return rfc3164_message
+
@@ 6,6 6,8 @@
# Configuration
import os
DEBUG = os.environ.get('DEBUG') == 'True'
+SQL_DUMP = os.environ.get('SQL_DUMP') == 'True'
+SQL_WRITE = os.environ.get('SQL_WRITE') == 'True'
BINDING_IP = os.environ.get('BINDING_IP', '0.0.0.0')
BINDING_PORT = os.environ.get('BINDING_PORT', '5140')
MYSQL_SERVER = os.environ.get('MYSQL_SERVER', '127.0.0.1')
@@ 28,6 30,7 @@ from datetime import datetime
from gevent.server import DatagramServer
from priority import SyslogMatrix
from mysqlx.helpers import escape as pure_python_escape
+from rfc5424 import convert_rfc5424_to_rfc3164
class SyslogUDPHandler(DatagramServer):
@@ 41,30 44,36 @@ class SyslogUDPHandler(DatagramServer):
print(f'Listening on UDP {args[0]}')
def __del__(self):
- self.db.close()
+ if SQL_WRITE:
+ self.db.close()
def setup(self):
- self.db = mysql.connector.connect(
- user=MYSQL_USER,
- password=MYSQL_PASSWORD,
- host=MYSQL_SERVER,
- database=MYSQL_DB
- )
- self.cursor = self.db.cursor()
+ if SQL_WRITE:
+ self.db = mysql.connector.connect(
+ user=MYSQL_USER,
+ password=MYSQL_PASSWORD,
+ host=MYSQL_SERVER,
+ database=MYSQL_DB
+ )
+ self.cursor = self.db.cursor()
def escape(self, msg):
- try:
- return self.db._cmysql.escape_string(msg).decode()
- except AttributeError:
+ if SQL_WRITE:
+ try:
+ return self.db._cmysql.escape_string(msg).decode()
+ except AttributeError:
+ return pure_python_escape(msg)
+ except Exception as e:
+ if DEBUG:
+ print('Cannot escape string')
+ raise(e)
+ else:
return pure_python_escape(msg)
- except Exception as e:
- if DEBUG:
- print('Cannot escape string')
- raise(e)
def handle(self, data, address):
ReceivedAt = datetime.now() # Generated
data = data.decode()
+ data = convert_rfc5424_to_rfc3164(data)
datetime_hostname_program = data[data.find('>')+1:data.find(': ')]
m,d,t = datetime_hostname_program.split()[:3]
formatted_datetime = '%s %s %s %s' % (
@@ 85,7 94,7 @@ class SyslogUDPHandler(DatagramServer):
if abs(time_delta.days) > 1:
pass # Something wrong, just ignore it.
else:
- program = datetime_hostname_program.split()[-1]
+ hostname, program = datetime_hostname_program.split()[-2:]
if '[' in program:
SysLogTag = program[:program.find('[')]
else:
@@ 97,7 106,7 @@ class SyslogUDPHandler(DatagramServer):
Message = data[data.find(': ')+2:]
code = data[data.find('<')+1:data.find('>')]
Facility, Priority = self.syslog_matrix.decode_int(code)
- FromHost = address[0]
+ FromHost = hostname or address[0]
InfoUnitID = 1 # Hardcoded
sql_command = SQL % (
ReceivedAt.strftime('%Y%m'),
@@ 107,29 116,31 @@ class SyslogUDPHandler(DatagramServer):
SysLogTag, ProcessID,
self.escape(Message)
)
- try:
- self.cursor.execute(sql_command)
- except Exception as e:
- if DEBUG:
- print(sql_command)
- print(e)
+
+ if SQL_DUMP:
+ print('\nSQL:', sql_command)
+ if SQL_WRITE:
try:
- self.db.rollback()
- except Exception as ee:
+ self.cursor.execute(sql_command)
+ except Exception as e:
if DEBUG:
- print('Fatal Exception! Restarting Process')
- print(ee)
- self.setup()
- else:
- if DEBUG:
- print(data)
- try:
- self.db.commit()
- except Exception as ee:
- if DEBUG:
- print('Fatal Exception! Restarting Process')
- print(ee)
- self.setup()
+ print(sql_command)
+ print(e)
+ try:
+ self.db.rollback()
+ except Exception as ee:
+ if DEBUG:
+ print('Fatal Exception! Restarting Process')
+ print(ee)
+ self.setup()
+ else:
+ try:
+ self.db.commit()
+ except Exception as ee:
+ if DEBUG:
+ print('Fatal Exception! Restarting Process')
+ print(ee)
+ self.setup()
if __name__ == "__main__":