@logtape/syslog 0.12.0-dev.199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/syslog.js ADDED
@@ -0,0 +1,468 @@
1
+ import { createSocket } from "node:dgram";
2
+ import { Socket } from "node:net";
3
+ import { hostname } from "node:os";
4
+ import process from "node:process";
5
+
6
+ //#region syslog.ts
7
+ /**
8
+ * Syslog facility code mapping.
9
+ * @since 0.12.0
10
+ */
11
+ const FACILITY_CODES = {
12
+ kernel: 0,
13
+ user: 1,
14
+ mail: 2,
15
+ daemon: 3,
16
+ security: 4,
17
+ syslog: 5,
18
+ lpr: 6,
19
+ news: 7,
20
+ uucp: 8,
21
+ cron: 9,
22
+ authpriv: 10,
23
+ ftp: 11,
24
+ ntp: 12,
25
+ logaudit: 13,
26
+ logalert: 14,
27
+ clock: 15,
28
+ local0: 16,
29
+ local1: 17,
30
+ local2: 18,
31
+ local3: 19,
32
+ local4: 20,
33
+ local5: 21,
34
+ local6: 22,
35
+ local7: 23
36
+ };
37
+ /**
38
+ * Syslog severity levels as defined in RFC 5424.
39
+ * @since 0.12.0
40
+ */
41
+ const SEVERITY_LEVELS = {
42
+ fatal: 0,
43
+ error: 3,
44
+ warning: 4,
45
+ info: 6,
46
+ debug: 7,
47
+ trace: 7
48
+ };
49
+ /**
50
+ * Calculates the priority value for a syslog message.
51
+ * Priority = Facility * 8 + Severity
52
+ * @since 0.12.0
53
+ */
54
+ function calculatePriority(facility, severity) {
55
+ const facilityCode = FACILITY_CODES[facility];
56
+ return facilityCode * 8 + severity;
57
+ }
58
+ /**
59
+ * Formats a timestamp (number) as RFC 3339 timestamp for syslog.
60
+ * @since 0.12.0
61
+ */
62
+ function formatTimestamp(timestamp) {
63
+ return new Date(timestamp).toISOString();
64
+ }
65
+ /**
66
+ * Escapes special characters in structured data values.
67
+ * @since 0.12.0
68
+ */
69
+ function escapeStructuredDataValue(value) {
70
+ return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/]/g, "\\]");
71
+ }
72
+ /**
73
+ * Formats structured data from log record properties.
74
+ * @since 0.12.0
75
+ */
76
+ function formatStructuredData(record, structuredDataId) {
77
+ if (!record.properties || Object.keys(record.properties).length === 0) return "-";
78
+ const elements = [];
79
+ for (const [key, value] of Object.entries(record.properties)) {
80
+ const escapedValue = escapeStructuredDataValue(String(value));
81
+ elements.push(`${key}="${escapedValue}"`);
82
+ }
83
+ return `[${structuredDataId} ${elements.join(" ")}]`;
84
+ }
85
+ /**
86
+ * Formats a log record as RFC 5424 syslog message.
87
+ * @since 0.12.0
88
+ */
89
+ function formatSyslogMessage(record, options) {
90
+ const severity = SEVERITY_LEVELS[record.level];
91
+ const priority = calculatePriority(options.facility, severity);
92
+ const timestamp = formatTimestamp(record.timestamp);
93
+ const hostname$1 = options.syslogHostname || "-";
94
+ const appName = options.appName || "-";
95
+ const processId = options.processId || "-";
96
+ const msgId = "-";
97
+ let structuredData = "-";
98
+ if (options.includeStructuredData) structuredData = formatStructuredData(record, options.structuredDataId);
99
+ let message = "";
100
+ for (let i = 0; i < record.message.length; i++) if (i % 2 === 0) message += record.message[i];
101
+ else message += JSON.stringify(record.message[i]);
102
+ return `<${priority}>1 ${timestamp} ${hostname$1} ${appName} ${processId} ${msgId} ${structuredData} ${message}`;
103
+ }
104
+ /**
105
+ * Gets the system hostname.
106
+ * @since 0.12.0
107
+ */
108
+ function getSystemHostname() {
109
+ try {
110
+ if (typeof Deno !== "undefined" && Deno.hostname) return Deno.hostname();
111
+ return hostname();
112
+ } catch {
113
+ return process.env.HOSTNAME || "localhost";
114
+ }
115
+ }
116
+ /**
117
+ * Gets the current process ID.
118
+ * @since 0.12.0
119
+ */
120
+ function getProcessId() {
121
+ try {
122
+ if (typeof Deno !== "undefined" && Deno.pid) return Deno.pid.toString();
123
+ return process.pid.toString();
124
+ } catch {
125
+ return "-";
126
+ }
127
+ }
128
+ /**
129
+ * Deno UDP syslog connection implementation.
130
+ * @since 0.12.0
131
+ */
132
+ var DenoUdpSyslogConnection = class {
133
+ encoder = new TextEncoder();
134
+ constructor(hostname$1, port, timeout) {
135
+ this.hostname = hostname$1;
136
+ this.port = port;
137
+ this.timeout = timeout;
138
+ }
139
+ connect() {}
140
+ send(message) {
141
+ const data = this.encoder.encode(message);
142
+ try {
143
+ const socket = createSocket("udp4");
144
+ if (this.timeout > 0) return new Promise((resolve, reject) => {
145
+ const timeout = setTimeout(() => {
146
+ socket.close();
147
+ reject(new Error("UDP send timeout"));
148
+ }, this.timeout);
149
+ socket.send(data, this.port, this.hostname, (error) => {
150
+ clearTimeout(timeout);
151
+ socket.close();
152
+ if (error) reject(error);
153
+ else resolve();
154
+ });
155
+ });
156
+ else return new Promise((resolve, reject) => {
157
+ socket.send(data, this.port, this.hostname, (error) => {
158
+ socket.close();
159
+ if (error) reject(error);
160
+ else resolve();
161
+ });
162
+ });
163
+ } catch (error) {
164
+ throw new Error(`Failed to send syslog message: ${error}`);
165
+ }
166
+ }
167
+ close() {}
168
+ };
169
+ /**
170
+ * Node.js UDP syslog connection implementation.
171
+ * @since 0.12.0
172
+ */
173
+ var NodeUdpSyslogConnection = class {
174
+ encoder = new TextEncoder();
175
+ constructor(hostname$1, port, timeout) {
176
+ this.hostname = hostname$1;
177
+ this.port = port;
178
+ this.timeout = timeout;
179
+ }
180
+ connect() {}
181
+ send(message) {
182
+ const data = this.encoder.encode(message);
183
+ try {
184
+ const socket = createSocket("udp4");
185
+ return new Promise((resolve, reject) => {
186
+ const timeout = setTimeout(() => {
187
+ socket.close();
188
+ reject(new Error("UDP send timeout"));
189
+ }, this.timeout);
190
+ socket.send(data, this.port, this.hostname, (error) => {
191
+ clearTimeout(timeout);
192
+ socket.close();
193
+ if (error) reject(error);
194
+ else resolve();
195
+ });
196
+ });
197
+ } catch (error) {
198
+ throw new Error(`Failed to send syslog message: ${error}`);
199
+ }
200
+ }
201
+ close() {}
202
+ };
203
+ /**
204
+ * Deno TCP syslog connection implementation.
205
+ * @since 0.12.0
206
+ */
207
+ var DenoTcpSyslogConnection = class {
208
+ connection;
209
+ encoder = new TextEncoder();
210
+ constructor(hostname$1, port, timeout) {
211
+ this.hostname = hostname$1;
212
+ this.port = port;
213
+ this.timeout = timeout;
214
+ }
215
+ async connect() {
216
+ try {
217
+ if (this.timeout > 0) {
218
+ const controller = new AbortController();
219
+ const timeoutId = setTimeout(() => {
220
+ controller.abort();
221
+ }, this.timeout);
222
+ try {
223
+ this.connection = await Deno.connect({
224
+ hostname: this.hostname,
225
+ port: this.port,
226
+ transport: "tcp",
227
+ signal: controller.signal
228
+ });
229
+ clearTimeout(timeoutId);
230
+ } catch (error) {
231
+ clearTimeout(timeoutId);
232
+ if (controller.signal.aborted) throw new Error("TCP connection timeout");
233
+ throw error;
234
+ }
235
+ } else this.connection = await Deno.connect({
236
+ hostname: this.hostname,
237
+ port: this.port,
238
+ transport: "tcp"
239
+ });
240
+ } catch (error) {
241
+ throw new Error(`Failed to connect to syslog server: ${error}`);
242
+ }
243
+ }
244
+ async send(message) {
245
+ if (!this.connection) throw new Error("Connection not established");
246
+ const data = this.encoder.encode(message + "\n");
247
+ try {
248
+ if (this.timeout > 0) {
249
+ const writePromise = this.connection.write(data);
250
+ const timeoutPromise = new Promise((_, reject) => {
251
+ setTimeout(() => {
252
+ reject(new Error("TCP send timeout"));
253
+ }, this.timeout);
254
+ });
255
+ await Promise.race([writePromise, timeoutPromise]);
256
+ } else await this.connection.write(data);
257
+ } catch (error) {
258
+ throw new Error(`Failed to send syslog message: ${error}`);
259
+ }
260
+ }
261
+ close() {
262
+ if (this.connection) {
263
+ try {
264
+ this.connection.close();
265
+ } catch {}
266
+ this.connection = void 0;
267
+ }
268
+ }
269
+ };
270
+ /**
271
+ * Node.js TCP syslog connection implementation.
272
+ * @since 0.12.0
273
+ */
274
+ var NodeTcpSyslogConnection = class {
275
+ connection;
276
+ encoder = new TextEncoder();
277
+ constructor(hostname$1, port, timeout) {
278
+ this.hostname = hostname$1;
279
+ this.port = port;
280
+ this.timeout = timeout;
281
+ }
282
+ connect() {
283
+ try {
284
+ return new Promise((resolve, reject) => {
285
+ const socket = new Socket();
286
+ const timeout = setTimeout(() => {
287
+ socket.destroy();
288
+ reject(new Error("TCP connection timeout"));
289
+ }, this.timeout);
290
+ socket.on("connect", () => {
291
+ clearTimeout(timeout);
292
+ this.connection = socket;
293
+ resolve();
294
+ });
295
+ socket.on("error", (error) => {
296
+ clearTimeout(timeout);
297
+ reject(error);
298
+ });
299
+ socket.connect(this.port, this.hostname);
300
+ });
301
+ } catch (error) {
302
+ throw new Error(`Failed to connect to syslog server: ${error}`);
303
+ }
304
+ }
305
+ send(message) {
306
+ if (!this.connection) throw new Error("Connection not established");
307
+ const data = this.encoder.encode(message + "\n");
308
+ try {
309
+ return new Promise((resolve, reject) => {
310
+ this.connection.write(data, (error) => {
311
+ if (error) reject(error);
312
+ else resolve();
313
+ });
314
+ });
315
+ } catch (error) {
316
+ throw new Error(`Failed to send syslog message: ${error}`);
317
+ }
318
+ }
319
+ close() {
320
+ if (this.connection) {
321
+ try {
322
+ this.connection.end();
323
+ } catch {}
324
+ this.connection = void 0;
325
+ }
326
+ }
327
+ };
328
+ /**
329
+ * Creates a syslog sink that sends log messages to a syslog server using the
330
+ * RFC 5424 syslog protocol format.
331
+ *
332
+ * This sink supports both UDP and TCP protocols for reliable log transmission
333
+ * to centralized logging systems. It automatically formats log records according
334
+ * to RFC 5424 specification, including structured data support for log properties.
335
+ *
336
+ * ## Features
337
+ *
338
+ * - **RFC 5424 Compliance**: Full implementation of the RFC 5424 syslog protocol
339
+ * - **Cross-Runtime Support**: Works with Deno, Node.js, Bun, and browsers
340
+ * - **Multiple Protocols**: Supports both UDP (fire-and-forget) and TCP (reliable) delivery
341
+ * - **Structured Data**: Automatically includes log record properties as RFC 5424 structured data
342
+ * - **Facility Support**: All standard syslog facilities (kern, user, mail, daemon, local0-7, etc.)
343
+ * - **Automatic Escaping**: Proper escaping of special characters in structured data values
344
+ * - **Connection Management**: Automatic connection handling with configurable timeouts
345
+ *
346
+ * ## Protocol Differences
347
+ *
348
+ * - **UDP**: Fast, connectionless delivery suitable for high-throughput logging.
349
+ * Messages may be lost during network issues but has minimal performance impact.
350
+ * - **TCP**: Reliable, connection-based delivery that ensures message delivery.
351
+ * Higher overhead but guarantees that log messages reach the server.
352
+ *
353
+ * @param options Configuration options for the syslog sink
354
+ * @returns A sink function that sends log records to the syslog server, implementing AsyncDisposable for proper cleanup
355
+ *
356
+ * @example Basic usage with default options
357
+ * ```typescript
358
+ * import { configure } from "@logtape/logtape";
359
+ * import { getSyslogSink } from "@logtape/syslog";
360
+ *
361
+ * await configure({
362
+ * sinks: {
363
+ * syslog: getSyslogSink(), // Sends to localhost:514 via UDP
364
+ * },
365
+ * loggers: [
366
+ * { category: [], sinks: ["syslog"], lowestLevel: "info" },
367
+ * ],
368
+ * });
369
+ * ```
370
+ *
371
+ * @example Custom syslog server configuration
372
+ * ```typescript
373
+ * import { configure } from "@logtape/logtape";
374
+ * import { getSyslogSink } from "@logtape/syslog";
375
+ *
376
+ * await configure({
377
+ * sinks: {
378
+ * syslog: getSyslogSink({
379
+ * hostname: "log-server.example.com",
380
+ * port: 1514,
381
+ * protocol: "tcp",
382
+ * facility: "mail",
383
+ * appName: "my-application",
384
+ * timeout: 10000,
385
+ * }),
386
+ * },
387
+ * loggers: [
388
+ * { category: [], sinks: ["syslog"], lowestLevel: "debug" },
389
+ * ],
390
+ * });
391
+ * ```
392
+ *
393
+ * @example Using structured data for log properties
394
+ * ```typescript
395
+ * import { configure, getLogger } from "@logtape/logtape";
396
+ * import { getSyslogSink } from "@logtape/syslog";
397
+ *
398
+ * await configure({
399
+ * sinks: {
400
+ * syslog: getSyslogSink({
401
+ * includeStructuredData: true,
402
+ * structuredDataId: "myapp@12345",
403
+ * }),
404
+ * },
405
+ * loggers: [
406
+ * { category: [], sinks: ["syslog"], lowestLevel: "info" },
407
+ * ],
408
+ * });
409
+ *
410
+ * const logger = getLogger();
411
+ * // This will include userId and action as structured data
412
+ * logger.info("User action completed", { userId: 123, action: "login" });
413
+ * // Results in: <134>1 2024-01-01T12:00:00.000Z hostname myapp 1234 - [myapp@12345 userId="123" action="login"] User action completed
414
+ * ```
415
+ *
416
+ * @since 0.12.0
417
+ * @see {@link https://tools.ietf.org/html/rfc5424} RFC 5424 - The Syslog Protocol
418
+ * @see {@link SyslogSinkOptions} for detailed configuration options
419
+ */
420
+ function getSyslogSink(options = {}) {
421
+ const hostname$1 = options.hostname ?? "localhost";
422
+ const port = options.port ?? 514;
423
+ const protocol = options.protocol ?? "udp";
424
+ const facility = options.facility ?? "local0";
425
+ const appName = options.appName ?? "logtape";
426
+ const syslogHostname = options.syslogHostname ?? getSystemHostname();
427
+ const processId = options.processId ?? getProcessId();
428
+ const timeout = options.timeout ?? 5e3;
429
+ const includeStructuredData = options.includeStructuredData ?? false;
430
+ const structuredDataId = options.structuredDataId ?? "logtape@32473";
431
+ const formatOptions = {
432
+ facility,
433
+ appName,
434
+ syslogHostname,
435
+ processId,
436
+ includeStructuredData,
437
+ structuredDataId
438
+ };
439
+ const connection = (() => {
440
+ if (typeof Deno !== "undefined") return protocol === "tcp" ? new DenoTcpSyslogConnection(hostname$1, port, timeout) : new DenoUdpSyslogConnection(hostname$1, port, timeout);
441
+ else return protocol === "tcp" ? new NodeTcpSyslogConnection(hostname$1, port, timeout) : new NodeUdpSyslogConnection(hostname$1, port, timeout);
442
+ })();
443
+ let isConnected = false;
444
+ let lastPromise = Promise.resolve();
445
+ const sink = (record) => {
446
+ const syslogMessage = formatSyslogMessage(record, formatOptions);
447
+ lastPromise = lastPromise.then(async () => {
448
+ if (!isConnected) {
449
+ await connection.connect();
450
+ isConnected = true;
451
+ }
452
+ await connection.send(syslogMessage);
453
+ }).catch((error) => {
454
+ isConnected = false;
455
+ throw error;
456
+ });
457
+ };
458
+ sink[Symbol.asyncDispose] = async () => {
459
+ await lastPromise.catch(() => {});
460
+ connection.close();
461
+ isConnected = false;
462
+ };
463
+ return sink;
464
+ }
465
+
466
+ //#endregion
467
+ export { getSyslogSink };
468
+ //# sourceMappingURL=syslog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syslog.js","names":["FACILITY_CODES: Record<SyslogFacility, number>","SEVERITY_LEVELS: Record<LogLevel, number>","facility: SyslogFacility","severity: number","timestamp: number","value: string","record: LogRecord","structuredDataId: string","elements: string[]","options: Required<\n Pick<\n SyslogSinkOptions,\n | \"facility\"\n | \"appName\"\n | \"syslogHostname\"\n | \"processId\"\n | \"includeStructuredData\"\n | \"structuredDataId\"\n >\n >","hostname","hostname: string","port: number","timeout: number","message: string","error?: Error | null","options: SyslogSinkOptions","connection: SyslogConnection","sink: Sink & AsyncDisposable"],"sources":["../syslog.ts"],"sourcesContent":["import type { LogLevel, LogRecord, Sink } from \"@logtape/logtape\";\nimport { createSocket } from \"node:dgram\";\nimport { Socket } from \"node:net\";\nimport { hostname } from \"node:os\";\nimport process from \"node:process\";\n\n/**\n * Syslog protocol type.\n * @since 0.12.0\n */\nexport type SyslogProtocol = \"udp\" | \"tcp\";\n\n/**\n * Syslog facility codes as defined in RFC 5424.\n * @since 0.12.0\n */\nexport type SyslogFacility =\n | \"kernel\" // 0 - kernel messages\n | \"user\" // 1 - user-level messages\n | \"mail\" // 2 - mail system\n | \"daemon\" // 3 - system daemons\n | \"security\" // 4 - security/authorization messages\n | \"syslog\" // 5 - messages generated internally by syslogd\n | \"lpr\" // 6 - line printer subsystem\n | \"news\" // 7 - network news subsystem\n | \"uucp\" // 8 - UUCP subsystem\n | \"cron\" // 9 - clock daemon\n | \"authpriv\" // 10 - security/authorization messages\n | \"ftp\" // 11 - FTP daemon\n | \"ntp\" // 12 - NTP subsystem\n | \"logaudit\" // 13 - log audit\n | \"logalert\" // 14 - log alert\n | \"clock\" // 15 - clock daemon\n | \"local0\" // 16 - local use 0\n | \"local1\" // 17 - local use 1\n | \"local2\" // 18 - local use 2\n | \"local3\" // 19 - local use 3\n | \"local4\" // 20 - local use 4\n | \"local5\" // 21 - local use 5\n | \"local6\" // 22 - local use 6\n | \"local7\"; // 23 - local use 7\n\n/**\n * Syslog facility code mapping.\n * @since 0.12.0\n */\nconst FACILITY_CODES: Record<SyslogFacility, number> = {\n kernel: 0,\n user: 1,\n mail: 2,\n daemon: 3,\n security: 4,\n syslog: 5,\n lpr: 6,\n news: 7,\n uucp: 8,\n cron: 9,\n authpriv: 10,\n ftp: 11,\n ntp: 12,\n logaudit: 13,\n logalert: 14,\n clock: 15,\n local0: 16,\n local1: 17,\n local2: 18,\n local3: 19,\n local4: 20,\n local5: 21,\n local6: 22,\n local7: 23,\n};\n\n/**\n * Syslog severity levels as defined in RFC 5424.\n * @since 0.12.0\n */\nconst SEVERITY_LEVELS: Record<LogLevel, number> = {\n fatal: 0, // Emergency: system is unusable\n error: 3, // Error: error conditions\n warning: 4, // Warning: warning conditions\n info: 6, // Informational: informational messages\n debug: 7, // Debug: debug-level messages\n trace: 7, // Debug: debug-level messages (same as debug)\n};\n\n/**\n * Options for the syslog sink.\n * @since 0.12.0\n */\nexport interface SyslogSinkOptions {\n /**\n * The hostname or IP address of the syslog server.\n * @default \"localhost\"\n */\n readonly hostname?: string;\n\n /**\n * The port number of the syslog server.\n * @default 514\n */\n readonly port?: number;\n\n /**\n * The protocol to use for sending syslog messages.\n * @default \"udp\"\n */\n readonly protocol?: SyslogProtocol;\n\n /**\n * The syslog facility to use for all messages.\n * @default \"local0\"\n */\n readonly facility?: SyslogFacility;\n\n /**\n * The application name to include in syslog messages.\n * @default \"logtape\"\n */\n readonly appName?: string;\n\n /**\n * The hostname to include in syslog messages.\n * If not provided, the system hostname will be used.\n */\n readonly syslogHostname?: string;\n\n /**\n * The process ID to include in syslog messages.\n * If not provided, the current process ID will be used.\n */\n readonly processId?: string;\n\n /**\n * Connection timeout in milliseconds.\n * @default 5000\n */\n readonly timeout?: number;\n\n /**\n * Whether to include structured data in syslog messages.\n * @default `false`\n */\n readonly includeStructuredData?: boolean;\n\n /**\n * The structured data ID to use for log properties.\n * Should follow the format \"name@private-enterprise-number\".\n * @default \"logtape@32473\"\n */\n readonly structuredDataId?: string;\n}\n\n/**\n * Calculates the priority value for a syslog message.\n * Priority = Facility * 8 + Severity\n * @since 0.12.0\n */\nfunction calculatePriority(facility: SyslogFacility, severity: number): number {\n const facilityCode = FACILITY_CODES[facility];\n return facilityCode * 8 + severity;\n}\n\n/**\n * Formats a timestamp (number) as RFC 3339 timestamp for syslog.\n * @since 0.12.0\n */\nfunction formatTimestamp(timestamp: number): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * Escapes special characters in structured data values.\n * @since 0.12.0\n */\nfunction escapeStructuredDataValue(value: string): string {\n return value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/]/g, \"\\\\]\");\n}\n\n/**\n * Formats structured data from log record properties.\n * @since 0.12.0\n */\nfunction formatStructuredData(\n record: LogRecord,\n structuredDataId: string,\n): string {\n if (!record.properties || Object.keys(record.properties).length === 0) {\n return \"-\";\n }\n\n const elements: string[] = [];\n for (const [key, value] of Object.entries(record.properties)) {\n const escapedValue = escapeStructuredDataValue(String(value));\n elements.push(`${key}=\"${escapedValue}\"`);\n }\n\n return `[${structuredDataId} ${elements.join(\" \")}]`;\n}\n\n/**\n * Formats a log record as RFC 5424 syslog message.\n * @since 0.12.0\n */\nfunction formatSyslogMessage(\n record: LogRecord,\n options: Required<\n Pick<\n SyslogSinkOptions,\n | \"facility\"\n | \"appName\"\n | \"syslogHostname\"\n | \"processId\"\n | \"includeStructuredData\"\n | \"structuredDataId\"\n >\n >,\n): string {\n const severity = SEVERITY_LEVELS[record.level];\n const priority = calculatePriority(options.facility, severity);\n const timestamp = formatTimestamp(record.timestamp);\n const hostname = options.syslogHostname || \"-\";\n const appName = options.appName || \"-\";\n const processId = options.processId || \"-\";\n const msgId = \"-\"; // Could be enhanced to include message ID\n\n let structuredData = \"-\";\n if (options.includeStructuredData) {\n structuredData = formatStructuredData(record, options.structuredDataId);\n }\n\n // Format the message text\n let message = \"\";\n for (let i = 0; i < record.message.length; i++) {\n if (i % 2 === 0) {\n message += record.message[i];\n } else {\n message += JSON.stringify(record.message[i]);\n }\n }\n\n // RFC 5424 format: <PRI>VERSION TIMESTAMP HOSTNAME APP-NAME PROCID MSGID STRUCTURED-DATA MSG\n return `<${priority}>1 ${timestamp} ${hostname} ${appName} ${processId} ${msgId} ${structuredData} ${message}`;\n}\n\n/**\n * Gets the system hostname.\n * @since 0.12.0\n */\nfunction getSystemHostname(): string {\n try {\n // Try Deno first\n if (typeof Deno !== \"undefined\" && Deno.hostname) {\n return Deno.hostname();\n }\n\n // Try Node.js os.hostname()\n return hostname();\n } catch {\n // Fallback to environment variable or localhost\n return process.env.HOSTNAME || \"localhost\";\n }\n}\n\n/**\n * Gets the current process ID.\n * @since 0.12.0\n */\nfunction getProcessId(): string {\n try {\n // Try Deno first\n if (typeof Deno !== \"undefined\" && Deno.pid) {\n return Deno.pid.toString();\n }\n\n // Try Node.js\n return process.pid.toString();\n } catch {\n return \"-\";\n }\n}\n\n/**\n * Base interface for syslog connections.\n * @since 0.12.0\n */\nexport interface SyslogConnection {\n connect(): void | Promise<void>;\n send(message: string): Promise<void>;\n close(): void;\n}\n\n/**\n * Deno UDP syslog connection implementation.\n * @since 0.12.0\n */\nexport class DenoUdpSyslogConnection implements SyslogConnection {\n private encoder = new TextEncoder();\n\n constructor(\n private hostname: string,\n private port: number,\n private timeout: number,\n ) {}\n\n connect(): void {\n // For UDP, we don't need to establish a persistent connection\n }\n\n send(message: string): Promise<void> {\n const data = this.encoder.encode(message);\n\n try {\n // Deno doesn't have native UDP support, use Node.js APIs\n const socket = createSocket(\"udp4\");\n\n if (this.timeout > 0) {\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n socket.close();\n reject(new Error(\"UDP send timeout\"));\n }, this.timeout);\n\n socket.send(data, this.port, this.hostname, (error) => {\n clearTimeout(timeout);\n socket.close();\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n } else {\n // No timeout\n return new Promise<void>((resolve, reject) => {\n socket.send(data, this.port, this.hostname, (error) => {\n socket.close();\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n }\n } catch (error) {\n throw new Error(`Failed to send syslog message: ${error}`);\n }\n }\n\n close(): void {\n // UDP connections don't need explicit closing\n }\n}\n\n/**\n * Node.js UDP syslog connection implementation.\n * @since 0.12.0\n */\nexport class NodeUdpSyslogConnection implements SyslogConnection {\n private encoder = new TextEncoder();\n\n constructor(\n private hostname: string,\n private port: number,\n private timeout: number,\n ) {}\n\n connect(): void {\n // For UDP, we don't need to establish a persistent connection\n }\n\n send(message: string): Promise<void> {\n const data = this.encoder.encode(message);\n\n try {\n const socket = createSocket(\"udp4\");\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n socket.close();\n reject(new Error(\"UDP send timeout\"));\n }, this.timeout);\n\n socket.send(data, this.port, this.hostname, (error) => {\n clearTimeout(timeout);\n socket.close();\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n } catch (error) {\n throw new Error(`Failed to send syslog message: ${error}`);\n }\n }\n\n close(): void {\n // UDP connections don't need explicit closing\n }\n}\n\n/**\n * Deno TCP syslog connection implementation.\n * @since 0.12.0\n */\nexport class DenoTcpSyslogConnection implements SyslogConnection {\n private connection?: Deno.TcpConn;\n private encoder = new TextEncoder();\n\n constructor(\n private hostname: string,\n private port: number,\n private timeout: number,\n ) {}\n\n async connect(): Promise<void> {\n try {\n if (this.timeout > 0) {\n // Use AbortController for proper timeout handling\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, this.timeout);\n\n try {\n this.connection = await Deno.connect({\n hostname: this.hostname,\n port: this.port,\n transport: \"tcp\",\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n } catch (error) {\n clearTimeout(timeoutId);\n if (controller.signal.aborted) {\n throw new Error(\"TCP connection timeout\");\n }\n throw error;\n }\n } else {\n // No timeout\n this.connection = await Deno.connect({\n hostname: this.hostname,\n port: this.port,\n transport: \"tcp\",\n });\n }\n } catch (error) {\n throw new Error(`Failed to connect to syslog server: ${error}`);\n }\n }\n\n async send(message: string): Promise<void> {\n if (!this.connection) {\n throw new Error(\"Connection not established\");\n }\n\n const data = this.encoder.encode(message + \"\\n\");\n\n try {\n if (this.timeout > 0) {\n // Implement timeout for send using Promise.race\n const writePromise = this.connection.write(data);\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(\"TCP send timeout\"));\n }, this.timeout);\n });\n\n await Promise.race([writePromise, timeoutPromise]);\n } else {\n // No timeout\n await this.connection.write(data);\n }\n } catch (error) {\n throw new Error(`Failed to send syslog message: ${error}`);\n }\n }\n\n close(): void {\n if (this.connection) {\n try {\n this.connection.close();\n } catch {\n // Ignore errors during close\n }\n this.connection = undefined;\n }\n }\n}\n\n/**\n * Node.js TCP syslog connection implementation.\n * @since 0.12.0\n */\nexport class NodeTcpSyslogConnection implements SyslogConnection {\n private connection?: Socket;\n private encoder = new TextEncoder();\n\n constructor(\n private hostname: string,\n private port: number,\n private timeout: number,\n ) {}\n\n connect(): Promise<void> {\n try {\n return new Promise<void>((resolve, reject) => {\n const socket = new Socket();\n\n const timeout = setTimeout(() => {\n socket.destroy();\n reject(new Error(\"TCP connection timeout\"));\n }, this.timeout);\n\n socket.on(\"connect\", () => {\n clearTimeout(timeout);\n this.connection = socket;\n resolve();\n });\n\n socket.on(\"error\", (error) => {\n clearTimeout(timeout);\n reject(error);\n });\n\n socket.connect(this.port, this.hostname);\n });\n } catch (error) {\n throw new Error(`Failed to connect to syslog server: ${error}`);\n }\n }\n\n send(message: string): Promise<void> {\n if (!this.connection) {\n throw new Error(\"Connection not established\");\n }\n\n const data = this.encoder.encode(message + \"\\n\");\n\n try {\n return new Promise<void>((resolve, reject) => {\n this.connection!.write(data, (error?: Error | null) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n } catch (error) {\n throw new Error(`Failed to send syslog message: ${error}`);\n }\n }\n\n close(): void {\n if (this.connection) {\n try {\n this.connection.end();\n } catch {\n // Ignore errors during close\n }\n this.connection = undefined;\n }\n }\n}\n\n/**\n * Creates a syslog sink that sends log messages to a syslog server using the\n * RFC 5424 syslog protocol format.\n *\n * This sink supports both UDP and TCP protocols for reliable log transmission\n * to centralized logging systems. It automatically formats log records according\n * to RFC 5424 specification, including structured data support for log properties.\n *\n * ## Features\n *\n * - **RFC 5424 Compliance**: Full implementation of the RFC 5424 syslog protocol\n * - **Cross-Runtime Support**: Works with Deno, Node.js, Bun, and browsers\n * - **Multiple Protocols**: Supports both UDP (fire-and-forget) and TCP (reliable) delivery\n * - **Structured Data**: Automatically includes log record properties as RFC 5424 structured data\n * - **Facility Support**: All standard syslog facilities (kern, user, mail, daemon, local0-7, etc.)\n * - **Automatic Escaping**: Proper escaping of special characters in structured data values\n * - **Connection Management**: Automatic connection handling with configurable timeouts\n *\n * ## Protocol Differences\n *\n * - **UDP**: Fast, connectionless delivery suitable for high-throughput logging.\n * Messages may be lost during network issues but has minimal performance impact.\n * - **TCP**: Reliable, connection-based delivery that ensures message delivery.\n * Higher overhead but guarantees that log messages reach the server.\n *\n * @param options Configuration options for the syslog sink\n * @returns A sink function that sends log records to the syslog server, implementing AsyncDisposable for proper cleanup\n *\n * @example Basic usage with default options\n * ```typescript\n * import { configure } from \"@logtape/logtape\";\n * import { getSyslogSink } from \"@logtape/syslog\";\n *\n * await configure({\n * sinks: {\n * syslog: getSyslogSink(), // Sends to localhost:514 via UDP\n * },\n * loggers: [\n * { category: [], sinks: [\"syslog\"], lowestLevel: \"info\" },\n * ],\n * });\n * ```\n *\n * @example Custom syslog server configuration\n * ```typescript\n * import { configure } from \"@logtape/logtape\";\n * import { getSyslogSink } from \"@logtape/syslog\";\n *\n * await configure({\n * sinks: {\n * syslog: getSyslogSink({\n * hostname: \"log-server.example.com\",\n * port: 1514,\n * protocol: \"tcp\",\n * facility: \"mail\",\n * appName: \"my-application\",\n * timeout: 10000,\n * }),\n * },\n * loggers: [\n * { category: [], sinks: [\"syslog\"], lowestLevel: \"debug\" },\n * ],\n * });\n * ```\n *\n * @example Using structured data for log properties\n * ```typescript\n * import { configure, getLogger } from \"@logtape/logtape\";\n * import { getSyslogSink } from \"@logtape/syslog\";\n *\n * await configure({\n * sinks: {\n * syslog: getSyslogSink({\n * includeStructuredData: true,\n * structuredDataId: \"myapp@12345\",\n * }),\n * },\n * loggers: [\n * { category: [], sinks: [\"syslog\"], lowestLevel: \"info\" },\n * ],\n * });\n *\n * const logger = getLogger();\n * // This will include userId and action as structured data\n * logger.info(\"User action completed\", { userId: 123, action: \"login\" });\n * // Results in: <134>1 2024-01-01T12:00:00.000Z hostname myapp 1234 - [myapp@12345 userId=\"123\" action=\"login\"] User action completed\n * ```\n *\n * @since 0.12.0\n * @see {@link https://tools.ietf.org/html/rfc5424} RFC 5424 - The Syslog Protocol\n * @see {@link SyslogSinkOptions} for detailed configuration options\n */\nexport function getSyslogSink(\n options: SyslogSinkOptions = {},\n): Sink & AsyncDisposable {\n const hostname = options.hostname ?? \"localhost\";\n const port = options.port ?? 514;\n const protocol = options.protocol ?? \"udp\";\n const facility = options.facility ?? \"local0\";\n const appName = options.appName ?? \"logtape\";\n const syslogHostname = options.syslogHostname ?? getSystemHostname();\n const processId = options.processId ?? getProcessId();\n const timeout = options.timeout ?? 5000;\n const includeStructuredData = options.includeStructuredData ?? false;\n const structuredDataId = options.structuredDataId ?? \"logtape@32473\";\n\n const formatOptions = {\n facility,\n appName,\n syslogHostname,\n processId,\n includeStructuredData,\n structuredDataId,\n };\n\n // Create connection based on protocol and runtime\n const connection: SyslogConnection = (() => {\n if (typeof Deno !== \"undefined\") {\n // Deno runtime\n return protocol === \"tcp\"\n ? new DenoTcpSyslogConnection(hostname, port, timeout)\n : new DenoUdpSyslogConnection(hostname, port, timeout);\n } else {\n // Node.js runtime (and Bun, which uses Node.js APIs)\n return protocol === \"tcp\"\n ? new NodeTcpSyslogConnection(hostname, port, timeout)\n : new NodeUdpSyslogConnection(hostname, port, timeout);\n }\n })();\n\n let isConnected = false;\n let lastPromise = Promise.resolve();\n\n const sink: Sink & AsyncDisposable = (record: LogRecord) => {\n const syslogMessage = formatSyslogMessage(record, formatOptions);\n\n lastPromise = lastPromise\n .then(async () => {\n if (!isConnected) {\n await connection.connect();\n isConnected = true;\n }\n await connection.send(syslogMessage);\n })\n .catch((error) => {\n // If connection fails, try to reconnect on next message\n isConnected = false;\n throw error;\n });\n };\n\n sink[Symbol.asyncDispose] = async () => {\n await lastPromise.catch(() => {}); // Wait for any pending operations\n connection.close();\n isConnected = false;\n };\n\n return sink;\n}\n"],"mappings":"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"}
package/mod.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Syslog sink for LogTape.
3
+ *
4
+ * This module provides a syslog sink that sends log messages to a syslog server
5
+ * following the RFC 5424 specification.
6
+ *
7
+ * @module
8
+ */
9
+
10
+ export type {
11
+ SyslogFacility,
12
+ SyslogProtocol,
13
+ SyslogSinkOptions,
14
+ } from "./syslog.ts";
15
+ export { getSyslogSink } from "./syslog.ts";
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@logtape/syslog",
3
+ "version": "0.12.0-dev.199+b454c29f",
4
+ "description": "Syslog sink for LogTape",
5
+ "keywords": [
6
+ "logging",
7
+ "log",
8
+ "logger",
9
+ "syslog",
10
+ "sink",
11
+ "rfc5424"
12
+ ],
13
+ "license": "MIT",
14
+ "author": {
15
+ "name": "Hong Minhee",
16
+ "email": "hong@minhee.org",
17
+ "url": "https://hongminhee.org/"
18
+ },
19
+ "homepage": "https://logtape.org/",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/dahlia/logtape.git",
23
+ "directory": "syslog/"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/dahlia/logtape/issues"
27
+ },
28
+ "funding": [
29
+ "https://github.com/sponsors/dahlia"
30
+ ],
31
+ "type": "module",
32
+ "module": "./dist/mod.js",
33
+ "main": "./dist/mod.cjs",
34
+ "types": "./dist/mod.d.ts",
35
+ "exports": {
36
+ ".": {
37
+ "import": "./dist/mod.js",
38
+ "require": "./dist/mod.cjs",
39
+ "types": "./dist/mod.d.ts"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "peerDependencies": {
44
+ "@logtape/logtape": "0.12.0-dev.199+b454c29f"
45
+ },
46
+ "devDependencies": {
47
+ "@alinea/suite": "^0.6.3",
48
+ "@david/which-runtime": "npm:@jsr/david__which-runtime@^0.2.1",
49
+ "@std/assert": "npm:@jsr/std__assert@^1.0.13",
50
+ "tsdown": "^0.12.7",
51
+ "typescript": "^5.8.3"
52
+ },
53
+ "scripts": {
54
+ "build": "tsdown",
55
+ "prepublish": "tsdown",
56
+ "test": "tsdown && node --experimental-transform-types --test",
57
+ "test:bun": "tsdown && bun test",
58
+ "test:deno": "deno test --allow-net --allow-env=TEMP,TMP,TMPDIR,HOSTNAME",
59
+ "test-all": "tsdown && node --experimental-transform-types --test && bun test && deno test"
60
+ }
61
+ }