-
Notifications
You must be signed in to change notification settings - Fork 2
Utils Syslog
GitHub Actions edited this page Sep 18, 2026
·
1 revision
RFC 3164 and RFC 5424 syslog message parser and generator.
The syslog utility provides comprehensive support for syslog message handling:
- RFC 3164: Legacy syslog format parsing
- RFC 5424: Modern syslog with structured data
- Auto-Detection: Automatic format identification
- Name Resolution: Facility and severity name lookup
- Structured Data: Full SD-ID and SD-PARAM support
- Validation: Built-in format checking
deno add @tundralibs/utils-
EMERGENCY = 0- System unusable -
ALERT = 1- Immediate action required -
CRITICAL = 2- Critical conditions -
ERROR = 3- Error conditions -
WARNING = 4- Warning conditions -
NOTICE = 5- Normal but significant -
INFO = 6- Informational -
DEBUG = 7- Debug messages
-
KERN = 0- Kernel messages -
USER = 1- User-level messages -
MAIL = 2- Mail system -
DAEMON = 3- System daemons -
AUTH = 4- Security/authorization -
SYSLOG = 5- Syslog internal -
LPR = 6- Line printer subsystem -
NEWS = 7- Network news -
UUCP = 8- UUCP subsystem -
CRON = 9- Clock daemon -
AUTHPRIV = 10- Security/authorization (private) -
FTP = 11- FTP daemon -
LOCAL0-LOCAL7 = 16-23- Local use
Parses a syslog message string. Auto-detects RFC 3164 and RFC 5424.
Returns: SyslogObject with parsed fields
Generates an RFC 5424 syslog message string. There is no format
parameter — stringify always emits RFC 5424.
import { parse } from '@tundralibs/utils';
const message = '<34>Oct 11 22:14:15 mymachine su: john changed user';
const parsed = parse(message);
console.log(parsed.facilityName); // 'AUTH' (PRI 34 → facility 4)
console.log(parsed.severityName); // 'CRITICAL' (PRI 34 → severity 2)
console.log(parsed.hostname); // 'mymachine'
console.log(parsed.appName); // 'su'
console.log(parsed.message); // 'john changed user'import { parse } from '@tundralibs/utils';
const message =
'<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - [exampleSDID@32473 iut="3" eventSource="Application"] A message';
const parsed = parse(message);
console.log(parsed.timestamp); // Date object
console.log(parsed.hostname); // '192.0.2.1'
console.log(parsed.appName); // 'myproc'
console.log(parsed.processId); // 8710 (a number)
console.log(parsed.structuredData);
// {
// 'exampleSDID@32473': {
// iut: '3',
// eventSource: 'Application'
// }
// }import { parse, SyslogFacilities, SyslogSeverities } from '@tundralibs/utils';
// PRI = facility*8 + severity; using USER (1) so PRI decodes to the
// severity each message's text names: 14 → INFO(6), 11 → ERROR(3), 10 → CRITICAL(2)
const messages = [
'<14>Oct 11 22:14:15 host1 app: info message',
'<11>Oct 11 22:14:16 host2 app: error message',
'<10>Oct 11 22:14:17 host3 app: critical message',
];
const errors = messages
.map(parse)
.filter((msg) => msg.severity <= SyslogSeverities.ERROR);
console.log(errors.length); // 2 (error and critical; INFO is above the ERROR threshold)import {
stringify,
SyslogFacilities,
SyslogSeverities,
} from '@tundralibs/utils';
const message = {
facility: SyslogFacilities.USER,
severity: SyslogSeverities.INFO,
timestamp: new Date('2024-02-04T10:30:00.000Z'),
hostname: 'myserver',
appName: 'myapp',
processId: 12345,
message: 'Application started',
};
const syslogString = stringify(message);
console.log(syslogString);
// <14>1 2024-02-04T10:30:00.000Z myserver myapp 12345 - - Application startedimport { parse, type SyslogObject, SyslogSeverities } from '@tundralibs/utils';
class SyslogAggregator {
private logs: SyslogObject[] = [];
addLog(rawMessage: string) {
const parsed = parse(rawMessage);
this.logs.push(parsed);
}
getErrorLogs() {
return this.logs.filter((log) => log.severity <= SyslogSeverities.ERROR);
}
getLogsByHost(hostname: string) {
return this.logs.filter((log) => log.hostname === hostname);
}
getLogsByApp(appName: string) {
return this.logs.filter((log) => log.appName === appName);
}
}import { parse, SyslogFacilities, type SyslogObject } from '@tundralibs/utils';
declare function alertSecurityTeam(event: SyslogObject): void;
function monitorSecurityEvents(message: string) {
const parsed = parse(message);
if (
parsed.facility === SyslogFacilities.AUTH ||
parsed.facility === SyslogFacilities.AUTHPRIV
) {
if (parsed.message.includes('failed')) {
alertSecurityTeam(parsed);
}
}
}import { parse } from '@tundralibs/utils';
const message =
'<165>1 2024-02-04T10:30:00Z host app 123 - [origin@123 ip="192.168.1.1" user="admin"][meta@456 action="login" status="success"] User logged in';
const parsed = parse(message);
// Access structured data
const origin = parsed.structuredData?.['origin@123'];
console.log(origin?.ip); // "192.168.1.1"
console.log(origin?.user); // "admin"
const meta = parsed.structuredData?.['meta@456'];
console.log(meta?.action); // "login"
console.log(meta?.status); // "success"import { parse } from '@tundralibs/utils';
async function processLogFile(path: string) {
const content = await Deno.readTextFile(path);
const lines = content.split('\n');
const stats = {
total: 0,
byFacility: new Map<string, number>(),
bySeverity: new Map<string, number>(),
};
for (const line of lines) {
if (!line.trim()) continue;
try {
const parsed = parse(line);
stats.total++;
const facility = parsed.facilityName ?? 'UNKNOWN';
const facilityCount = stats.byFacility.get(facility) || 0;
stats.byFacility.set(facility, facilityCount + 1);
const severity = parsed.severityName ?? 'UNKNOWN';
const severityCount = stats.bySeverity.get(severity) || 0;
stats.bySeverity.set(severity, severityCount + 1);
} catch (error) {
console.error('Failed to parse:', line);
}
}
return stats;
}- Validate Input: Always wrap parse() in try-catch
- Use Constants: Use enum values instead of numbers
- Structured Data: Leverage SD for rich context
- Timezone Aware: Handle timestamp timezones properly
<PRI>TIMESTAMP HOSTNAME APP[PID]: MESSAGE
<PRI>VERSION TIMESTAMP HOSTNAME APP PROCID MSGID STRUCTURED-DATA MESSAGE
STRUCTURED-DATA is mandatory: it is either one or more [SD-ELEMENT]s or the
nil value -.
-
Nil structured data (
-):stringifyalways emits theSTRUCTURED-DATAfield — the nil value-when no structured data is present — so compliant receivers do not mistake the first message token for the SD field. On the parse side, a leading nil-SD marker is consumed and never leaks intomessage. -
Brackets in the message: Only structured data at the front of the
SD/MESSAGE portion is parsed as SD. Bracketed text inside the free-text
message (
[ERROR],user [bob], array dumps) is preserved verbatim inmessagerather than being treated as (and stripped as) structured data. -
Injection-safe generation:
stringifyescapes SD parameter values per RFC 5424 §6.3.3 (",\,]) and sanitizes SD-IDs, parameter names, and the header fields (hostname, appName, messageId) to their allowed character sets. Disallowed bytes (SP, CR/LF, other control bytes, DEL) are replaced with_rather than deleted, and a header field left empty by sanitization folds to the nil value-. Because no field can collapse to an empty token, attacker-controlled content cannot break out of a structured-data element, shift header-field parsing, or forge additional records on line-delimited transports.
Priority (PRI) = (Facility × 8) + Severity
import { SyslogFacilities, SyslogSeverities } from '@tundralibs/utils';
const facility = SyslogFacilities.USER;
const severity = SyslogSeverities.INFO;
const priority = (facility * 8) + severity;
// Example: (USER=1 * 8) + INFO=6 = 14