M aiosyslogd/config.py +6 -3
@@ 30,7 30,8 @@ def _create_default_config(path: str) ->
with open(path, "w") as f:
toml.dump(DEFAULT_CONFIG, f)
print(
- f"Default configuration file created. Please review '{path}' and restart the server if needed."
+ f"Default configuration file created. Please review '{path}' "
+ "and restart the server if needed."
)
return DEFAULT_CONFIG
@@ 42,8 43,10 @@ def load_config() -> Dict[str, Any]:
It first checks for the 'AIOSYSLOGD_CONFIG' environment variable for a custom path.
If the variable is not set, it falls back to 'aiosyslogd.toml' in the current directory.
- - If a custom path is specified and the file doesn't exist, the server will exit with an error.
- - If the default file ('aiosyslogd.toml') doesn't exist, it will be created automatically.
+ - If a custom path is specified and the file doesn't exist,
+ the server will exit with an error.
+ - If the default file ('aiosyslogd.toml') doesn't exist,
+ it will be created automatically.
"""
config_path_from_env: str | None = os.environ.get("AIOSYSLOGD_CONFIG")
M aiosyslogd/rfc5424.py +16 -11
@@ 3,6 3,10 @@ from datetime import datetime, UTC
from typing import Dict
import re
+# --- RFC 5424 and RFC 3164 Syslog Message Patterns ---
+# These patterns are compiled here to avoid repeated compilation.
+
+# Pattern for RFC 5424: <PRI>VER TS HOST APP PID MSGID SD MSG
RFC5424_PATTERN: re.Pattern[str] = re.compile(
r"<(?P<pri>\d+)>"
r"(?P<ver>\d+)\s"
@@ 16,23 20,24 @@ RFC5424_PATTERN: re.Pattern[str] = re.co
re.DOTALL,
)
+# Pattern for RFC 3164: <PRI>MMM DD HH:MM:SS HOSTNAME TAG[PID]: MSG
+# Made the colon after the tag optional and adjusted tag capture.
+RFC3164_PATTERN: re.Pattern[str] = re.compile(
+ r"<(?P<pri>\d{1,3})>"
+ r"(?P<mon>\w{3})\s+(?P<day>\d{1,2})\s+(?P<hr>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})"
+ r"\s+(?P<host>[\w\-\.]+)"
+ r"\s+(?P<tag>\S+?)(:|\s-)?\s" # Flexible tag/separator matching
+ r"(?P<msg>.*)",
+ re.DOTALL,
+)
+
def convert_rfc3164_to_rfc5424(message: str, debug_mode: bool = False) -> str:
"""
Converts a best-effort RFC 3164 syslog message to an RFC 5424 message.
This version is more flexible to handle formats like FortiGate's.
"""
- # Pattern for RFC 3164: <PRI>MMM DD HH:MM:SS HOSTNAME TAG[PID]: MSG
- # Made the colon after the tag optional and adjusted tag capture.
- pattern: re.Pattern[str] = re.compile(
- r"<(?P<pri>\d{1,3})>"
- r"(?P<mon>\w{3})\s+(?P<day>\d{1,2})\s+(?P<hr>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})"
- r"\s+(?P<host>[\w\-\.]+)"
- r"\s+(?P<tag>\S+?)(:|\s-)?\s" # Flexible tag/separator matching
- r"(?P<msg>.*)",
- re.DOTALL,
- )
- match: re.Match[str] | None = pattern.match(message)
+ match: re.Match[str] | None = RFC3164_PATTERN.match(message)
if not match:
if debug_mode:
M aiosyslogd/server.py +13 -9
@@ 63,9 63,8 @@ class SyslogUDPServer(asyncio.DatagramPr
server = cls(host, port)
print(f"aiosyslogd starting on UDP {host}:{port}...")
if SQL_WRITE:
- print(
- f"SQLite writing ENABLED to '{SQLITE_DB_PATH}'. Batch size: {BATCH_SIZE}, Timeout: {BATCH_TIMEOUT}s"
- )
+ print(f"SQLite writing ENABLED to '{SQLITE_DB_PATH}.")
+ print(f"Batch size: {BATCH_SIZE}, Timeout: {BATCH_TIMEOUT}s")
await server.connect_to_sqlite()
if DEBUG:
print("Debug mode is ON.")
@@ 237,25 236,30 @@ class SyslogUDPServer(asyncio.DatagramPr
async with self.db.cursor() as cursor:
await cursor.execute(
- f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}'"
+ "SELECT name FROM sqlite_master "
+ f"WHERE type='table' AND name='{table_name}'"
)
if await cursor.fetchone() is None:
if DEBUG:
print(
- f"Creating new tables for {year_month}: {table_name}, {fts_table_name}"
+ "Creating new tables for "
+ f"{year_month}: {table_name}, {fts_table_name}"
)
await self.db.execute(
f"""CREATE TABLE {table_name} (
- ID INTEGER PRIMARY KEY AUTOINCREMENT, Facility INTEGER, Priority INTEGER,
- FromHost TEXT, InfoUnitID INTEGER, ReceivedAt TIMESTAMP, DeviceReportedTime TIMESTAMP,
+ ID INTEGER PRIMARY KEY AUTOINCREMENT, Facility INTEGER,
+ Priority INTEGER, FromHost TEXT, InfoUnitID INTEGER,
+ ReceivedAt TIMESTAMP, DeviceReportedTime TIMESTAMP,
SysLogTag TEXT, ProcessID TEXT, Message TEXT
)"""
)
await self.db.execute(
- f"CREATE INDEX idx_ReceivedAt_{year_month} ON {table_name} (ReceivedAt)"
+ f"CREATE INDEX idx_ReceivedAt_{year_month} "
+ f"ON {table_name} (ReceivedAt)"
)
await self.db.execute(
- f"CREATE VIRTUAL TABLE {fts_table_name} USING fts5(Message, content='{table_name}', content_rowid='ID')"
+ f"CREATE VIRTUAL TABLE {fts_table_name} "
+ f"USING fts5(Message, content='{table_name}', content_rowid='ID')"
)
await self.db.commit()
return table_name
M pyproject.toml +1 -1
@@ 1,6 1,6 @@
[project]
name = "aiosyslogd"
-version = "0.1.2"
+version = "0.1.3"
description = "Asynchronous Syslog server using asyncio, with an optional uvloop integration and SQLite backend."
authors = [
{name = "Chaiwat Suttipongsakul",email = "cwt@bashell.com"}