@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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright 2024 Hong Minhee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @logtape/syslog
2
+
3
+ [![JSR](https://jsr.io/badges/@logtape/syslog)](https://jsr.io/@logtape/syslog)
4
+ [![npm](https://img.shields.io/npm/v/@logtape/syslog)](https://www.npmjs.com/package/@logtape/syslog)
5
+
6
+ Syslog sink for [LogTape]. This package provides a syslog sink that sends log messages to a syslog server following the [RFC 5424] specification.
7
+
8
+ ## Features
9
+
10
+ - **RFC 5424 compliant**: Follows the official syslog protocol specification
11
+ - **Multiple transports**: Supports both UDP and TCP protocols
12
+ - **Cross-runtime**: Works on Deno, Node.js, and Bun
13
+ - **Non-blocking**: Asynchronous message sending with proper cleanup
14
+ - **Configurable**: Extensive configuration options for facility, hostname, etc.
15
+ - **Structured logging**: Optional structured data support
16
+ - **Zero dependencies**: No external dependencies
17
+
18
+ ## Installation
19
+
20
+ ::: code-group
21
+
22
+ ```sh [Deno]
23
+ deno add jsr:@logtape/syslog
24
+ ```
25
+
26
+ ```sh [npm]
27
+ npm add @logtape/syslog
28
+ ```
29
+
30
+ ```sh [pnpm]
31
+ pnpm add @logtape/syslog
32
+ ```
33
+
34
+ ```sh [Yarn]
35
+ yarn add @logtape/syslog
36
+ ```
37
+
38
+ ```sh [Bun]
39
+ bun add @logtape/syslog
40
+ ```
41
+
42
+ :::
43
+
44
+ ## Usage
45
+
46
+ ```typescript
47
+ import { configure } from "@logtape/logtape";
48
+ import { getSyslogSink } from "@logtape/syslog";
49
+
50
+ await configure({
51
+ sinks: {
52
+ syslog: getSyslogSink({
53
+ hostname: "syslog.example.com",
54
+ port: 514,
55
+ protocol: "udp",
56
+ facility: "local0",
57
+ appName: "my-app",
58
+ }),
59
+ },
60
+ loggers: [
61
+ { category: [], sinks: ["syslog"], level: "info" },
62
+ ],
63
+ });
64
+ ```
65
+
66
+ ## Configuration Options
67
+
68
+ - **hostname**: Syslog server hostname (default: "localhost")
69
+ - **port**: Syslog server port (default: 514)
70
+ - **protocol**: Transport protocol "udp" or "tcp" (default: "udp")
71
+ - **facility**: Syslog facility (default: "local0")
72
+ - **appName**: Application name in syslog messages (default: "logtape")
73
+ - **syslogHostname**: Hostname field in syslog messages
74
+ - **processId**: Process ID field in syslog messages
75
+ - **timeout**: Connection timeout in milliseconds (default: 5000)
76
+ - **includeStructuredData**: Include LogTape properties as structured data (default: false)
77
+
78
+ ## Facilities
79
+
80
+ Supports all RFC 5424 facilities:
81
+ - System facilities: `kernel`, `user`, `mail`, `daemon`, `security`, `syslog`, `lpr`, `news`, `uucp`, `cron`, `authpriv`, `ftp`, `ntp`, `logaudit`, `logalert`, `clock`
82
+ - Local facilities: `local0` through `local7`
83
+
84
+ ## License
85
+
86
+ MIT License. See [LICENSE](../LICENSE) for details.
87
+
88
+ [LogTape]: https://logtape.org/
89
+ [RFC 5424]: https://tools.ietf.org/rfc/rfc5424.txt
package/deno.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@logtape/syslog",
3
+ "version": "0.12.0-dev.199+b454c29f",
4
+ "license": "MIT",
5
+ "exports": "./mod.ts",
6
+ "exclude": [
7
+ "coverage/",
8
+ "npm/",
9
+ ".dnt-import-map.json"
10
+ ],
11
+ "tasks": {
12
+ "build": "pnpm build",
13
+ "test": "deno test --allow-net --allow-env=TEMP,TMP,TMPDIR,HOSTNAME --allow-sys",
14
+ "test:node": {
15
+ "dependencies": [
16
+ "build"
17
+ ],
18
+ "command": "node --experimental-transform-types --test"
19
+ },
20
+ "test:bun": {
21
+ "dependencies": [
22
+ "build"
23
+ ],
24
+ "command": "bun test"
25
+ },
26
+ "test-all": {
27
+ "dependencies": [
28
+ "test",
29
+ "test:node",
30
+ "test:bun"
31
+ ]
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,30 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+
25
+ Object.defineProperty(exports, '__toESM', {
26
+ enumerable: true,
27
+ get: function () {
28
+ return __toESM;
29
+ }
30
+ });
package/dist/mod.cjs ADDED
@@ -0,0 +1,3 @@
1
+ const require_syslog = require('./syslog.cjs');
2
+
3
+ exports.getSyslogSink = require_syslog.getSyslogSink;
package/dist/mod.d.cts ADDED
@@ -0,0 +1,2 @@
1
+ import { SyslogFacility, SyslogProtocol, SyslogSinkOptions, getSyslogSink } from "./syslog.cjs";
2
+ export { SyslogFacility, SyslogProtocol, SyslogSinkOptions, getSyslogSink };
package/dist/mod.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import { SyslogFacility, SyslogProtocol, SyslogSinkOptions, getSyslogSink } from "./syslog.js";
2
+ export { SyslogFacility, SyslogProtocol, SyslogSinkOptions, getSyslogSink };
package/dist/mod.js ADDED
@@ -0,0 +1,3 @@
1
+ import { getSyslogSink } from "./syslog.js";
2
+
3
+ export { getSyslogSink };
@@ -0,0 +1,468 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ const node_dgram = require_rolldown_runtime.__toESM(require("node:dgram"));
3
+ const node_net = require_rolldown_runtime.__toESM(require("node:net"));
4
+ const node_os = require_rolldown_runtime.__toESM(require("node:os"));
5
+ const node_process = require_rolldown_runtime.__toESM(require("node:process"));
6
+
7
+ //#region syslog.ts
8
+ /**
9
+ * Syslog facility code mapping.
10
+ * @since 0.12.0
11
+ */
12
+ const FACILITY_CODES = {
13
+ kernel: 0,
14
+ user: 1,
15
+ mail: 2,
16
+ daemon: 3,
17
+ security: 4,
18
+ syslog: 5,
19
+ lpr: 6,
20
+ news: 7,
21
+ uucp: 8,
22
+ cron: 9,
23
+ authpriv: 10,
24
+ ftp: 11,
25
+ ntp: 12,
26
+ logaudit: 13,
27
+ logalert: 14,
28
+ clock: 15,
29
+ local0: 16,
30
+ local1: 17,
31
+ local2: 18,
32
+ local3: 19,
33
+ local4: 20,
34
+ local5: 21,
35
+ local6: 22,
36
+ local7: 23
37
+ };
38
+ /**
39
+ * Syslog severity levels as defined in RFC 5424.
40
+ * @since 0.12.0
41
+ */
42
+ const SEVERITY_LEVELS = {
43
+ fatal: 0,
44
+ error: 3,
45
+ warning: 4,
46
+ info: 6,
47
+ debug: 7,
48
+ trace: 7
49
+ };
50
+ /**
51
+ * Calculates the priority value for a syslog message.
52
+ * Priority = Facility * 8 + Severity
53
+ * @since 0.12.0
54
+ */
55
+ function calculatePriority(facility, severity) {
56
+ const facilityCode = FACILITY_CODES[facility];
57
+ return facilityCode * 8 + severity;
58
+ }
59
+ /**
60
+ * Formats a timestamp (number) as RFC 3339 timestamp for syslog.
61
+ * @since 0.12.0
62
+ */
63
+ function formatTimestamp(timestamp) {
64
+ return new Date(timestamp).toISOString();
65
+ }
66
+ /**
67
+ * Escapes special characters in structured data values.
68
+ * @since 0.12.0
69
+ */
70
+ function escapeStructuredDataValue(value) {
71
+ return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/]/g, "\\]");
72
+ }
73
+ /**
74
+ * Formats structured data from log record properties.
75
+ * @since 0.12.0
76
+ */
77
+ function formatStructuredData(record, structuredDataId) {
78
+ if (!record.properties || Object.keys(record.properties).length === 0) return "-";
79
+ const elements = [];
80
+ for (const [key, value] of Object.entries(record.properties)) {
81
+ const escapedValue = escapeStructuredDataValue(String(value));
82
+ elements.push(`${key}="${escapedValue}"`);
83
+ }
84
+ return `[${structuredDataId} ${elements.join(" ")}]`;
85
+ }
86
+ /**
87
+ * Formats a log record as RFC 5424 syslog message.
88
+ * @since 0.12.0
89
+ */
90
+ function formatSyslogMessage(record, options) {
91
+ const severity = SEVERITY_LEVELS[record.level];
92
+ const priority = calculatePriority(options.facility, severity);
93
+ const timestamp = formatTimestamp(record.timestamp);
94
+ const hostname$1 = options.syslogHostname || "-";
95
+ const appName = options.appName || "-";
96
+ const processId = options.processId || "-";
97
+ const msgId = "-";
98
+ let structuredData = "-";
99
+ if (options.includeStructuredData) structuredData = formatStructuredData(record, options.structuredDataId);
100
+ let message = "";
101
+ for (let i = 0; i < record.message.length; i++) if (i % 2 === 0) message += record.message[i];
102
+ else message += JSON.stringify(record.message[i]);
103
+ return `<${priority}>1 ${timestamp} ${hostname$1} ${appName} ${processId} ${msgId} ${structuredData} ${message}`;
104
+ }
105
+ /**
106
+ * Gets the system hostname.
107
+ * @since 0.12.0
108
+ */
109
+ function getSystemHostname() {
110
+ try {
111
+ if (typeof Deno !== "undefined" && Deno.hostname) return Deno.hostname();
112
+ return (0, node_os.hostname)();
113
+ } catch {
114
+ return node_process.default.env.HOSTNAME || "localhost";
115
+ }
116
+ }
117
+ /**
118
+ * Gets the current process ID.
119
+ * @since 0.12.0
120
+ */
121
+ function getProcessId() {
122
+ try {
123
+ if (typeof Deno !== "undefined" && Deno.pid) return Deno.pid.toString();
124
+ return node_process.default.pid.toString();
125
+ } catch {
126
+ return "-";
127
+ }
128
+ }
129
+ /**
130
+ * Deno UDP syslog connection implementation.
131
+ * @since 0.12.0
132
+ */
133
+ var DenoUdpSyslogConnection = class {
134
+ encoder = new TextEncoder();
135
+ constructor(hostname$1, port, timeout) {
136
+ this.hostname = hostname$1;
137
+ this.port = port;
138
+ this.timeout = timeout;
139
+ }
140
+ connect() {}
141
+ send(message) {
142
+ const data = this.encoder.encode(message);
143
+ try {
144
+ const socket = (0, node_dgram.createSocket)("udp4");
145
+ if (this.timeout > 0) return new Promise((resolve, reject) => {
146
+ const timeout = setTimeout(() => {
147
+ socket.close();
148
+ reject(new Error("UDP send timeout"));
149
+ }, this.timeout);
150
+ socket.send(data, this.port, this.hostname, (error) => {
151
+ clearTimeout(timeout);
152
+ socket.close();
153
+ if (error) reject(error);
154
+ else resolve();
155
+ });
156
+ });
157
+ else return new Promise((resolve, reject) => {
158
+ socket.send(data, this.port, this.hostname, (error) => {
159
+ socket.close();
160
+ if (error) reject(error);
161
+ else resolve();
162
+ });
163
+ });
164
+ } catch (error) {
165
+ throw new Error(`Failed to send syslog message: ${error}`);
166
+ }
167
+ }
168
+ close() {}
169
+ };
170
+ /**
171
+ * Node.js UDP syslog connection implementation.
172
+ * @since 0.12.0
173
+ */
174
+ var NodeUdpSyslogConnection = class {
175
+ encoder = new TextEncoder();
176
+ constructor(hostname$1, port, timeout) {
177
+ this.hostname = hostname$1;
178
+ this.port = port;
179
+ this.timeout = timeout;
180
+ }
181
+ connect() {}
182
+ send(message) {
183
+ const data = this.encoder.encode(message);
184
+ try {
185
+ const socket = (0, node_dgram.createSocket)("udp4");
186
+ return new Promise((resolve, reject) => {
187
+ const timeout = setTimeout(() => {
188
+ socket.close();
189
+ reject(new Error("UDP send timeout"));
190
+ }, this.timeout);
191
+ socket.send(data, this.port, this.hostname, (error) => {
192
+ clearTimeout(timeout);
193
+ socket.close();
194
+ if (error) reject(error);
195
+ else resolve();
196
+ });
197
+ });
198
+ } catch (error) {
199
+ throw new Error(`Failed to send syslog message: ${error}`);
200
+ }
201
+ }
202
+ close() {}
203
+ };
204
+ /**
205
+ * Deno TCP syslog connection implementation.
206
+ * @since 0.12.0
207
+ */
208
+ var DenoTcpSyslogConnection = class {
209
+ connection;
210
+ encoder = new TextEncoder();
211
+ constructor(hostname$1, port, timeout) {
212
+ this.hostname = hostname$1;
213
+ this.port = port;
214
+ this.timeout = timeout;
215
+ }
216
+ async connect() {
217
+ try {
218
+ if (this.timeout > 0) {
219
+ const controller = new AbortController();
220
+ const timeoutId = setTimeout(() => {
221
+ controller.abort();
222
+ }, this.timeout);
223
+ try {
224
+ this.connection = await Deno.connect({
225
+ hostname: this.hostname,
226
+ port: this.port,
227
+ transport: "tcp",
228
+ signal: controller.signal
229
+ });
230
+ clearTimeout(timeoutId);
231
+ } catch (error) {
232
+ clearTimeout(timeoutId);
233
+ if (controller.signal.aborted) throw new Error("TCP connection timeout");
234
+ throw error;
235
+ }
236
+ } else this.connection = await Deno.connect({
237
+ hostname: this.hostname,
238
+ port: this.port,
239
+ transport: "tcp"
240
+ });
241
+ } catch (error) {
242
+ throw new Error(`Failed to connect to syslog server: ${error}`);
243
+ }
244
+ }
245
+ async send(message) {
246
+ if (!this.connection) throw new Error("Connection not established");
247
+ const data = this.encoder.encode(message + "\n");
248
+ try {
249
+ if (this.timeout > 0) {
250
+ const writePromise = this.connection.write(data);
251
+ const timeoutPromise = new Promise((_, reject) => {
252
+ setTimeout(() => {
253
+ reject(new Error("TCP send timeout"));
254
+ }, this.timeout);
255
+ });
256
+ await Promise.race([writePromise, timeoutPromise]);
257
+ } else await this.connection.write(data);
258
+ } catch (error) {
259
+ throw new Error(`Failed to send syslog message: ${error}`);
260
+ }
261
+ }
262
+ close() {
263
+ if (this.connection) {
264
+ try {
265
+ this.connection.close();
266
+ } catch {}
267
+ this.connection = void 0;
268
+ }
269
+ }
270
+ };
271
+ /**
272
+ * Node.js TCP syslog connection implementation.
273
+ * @since 0.12.0
274
+ */
275
+ var NodeTcpSyslogConnection = class {
276
+ connection;
277
+ encoder = new TextEncoder();
278
+ constructor(hostname$1, port, timeout) {
279
+ this.hostname = hostname$1;
280
+ this.port = port;
281
+ this.timeout = timeout;
282
+ }
283
+ connect() {
284
+ try {
285
+ return new Promise((resolve, reject) => {
286
+ const socket = new node_net.Socket();
287
+ const timeout = setTimeout(() => {
288
+ socket.destroy();
289
+ reject(new Error("TCP connection timeout"));
290
+ }, this.timeout);
291
+ socket.on("connect", () => {
292
+ clearTimeout(timeout);
293
+ this.connection = socket;
294
+ resolve();
295
+ });
296
+ socket.on("error", (error) => {
297
+ clearTimeout(timeout);
298
+ reject(error);
299
+ });
300
+ socket.connect(this.port, this.hostname);
301
+ });
302
+ } catch (error) {
303
+ throw new Error(`Failed to connect to syslog server: ${error}`);
304
+ }
305
+ }
306
+ send(message) {
307
+ if (!this.connection) throw new Error("Connection not established");
308
+ const data = this.encoder.encode(message + "\n");
309
+ try {
310
+ return new Promise((resolve, reject) => {
311
+ this.connection.write(data, (error) => {
312
+ if (error) reject(error);
313
+ else resolve();
314
+ });
315
+ });
316
+ } catch (error) {
317
+ throw new Error(`Failed to send syslog message: ${error}`);
318
+ }
319
+ }
320
+ close() {
321
+ if (this.connection) {
322
+ try {
323
+ this.connection.end();
324
+ } catch {}
325
+ this.connection = void 0;
326
+ }
327
+ }
328
+ };
329
+ /**
330
+ * Creates a syslog sink that sends log messages to a syslog server using the
331
+ * RFC 5424 syslog protocol format.
332
+ *
333
+ * This sink supports both UDP and TCP protocols for reliable log transmission
334
+ * to centralized logging systems. It automatically formats log records according
335
+ * to RFC 5424 specification, including structured data support for log properties.
336
+ *
337
+ * ## Features
338
+ *
339
+ * - **RFC 5424 Compliance**: Full implementation of the RFC 5424 syslog protocol
340
+ * - **Cross-Runtime Support**: Works with Deno, Node.js, Bun, and browsers
341
+ * - **Multiple Protocols**: Supports both UDP (fire-and-forget) and TCP (reliable) delivery
342
+ * - **Structured Data**: Automatically includes log record properties as RFC 5424 structured data
343
+ * - **Facility Support**: All standard syslog facilities (kern, user, mail, daemon, local0-7, etc.)
344
+ * - **Automatic Escaping**: Proper escaping of special characters in structured data values
345
+ * - **Connection Management**: Automatic connection handling with configurable timeouts
346
+ *
347
+ * ## Protocol Differences
348
+ *
349
+ * - **UDP**: Fast, connectionless delivery suitable for high-throughput logging.
350
+ * Messages may be lost during network issues but has minimal performance impact.
351
+ * - **TCP**: Reliable, connection-based delivery that ensures message delivery.
352
+ * Higher overhead but guarantees that log messages reach the server.
353
+ *
354
+ * @param options Configuration options for the syslog sink
355
+ * @returns A sink function that sends log records to the syslog server, implementing AsyncDisposable for proper cleanup
356
+ *
357
+ * @example Basic usage with default options
358
+ * ```typescript
359
+ * import { configure } from "@logtape/logtape";
360
+ * import { getSyslogSink } from "@logtape/syslog";
361
+ *
362
+ * await configure({
363
+ * sinks: {
364
+ * syslog: getSyslogSink(), // Sends to localhost:514 via UDP
365
+ * },
366
+ * loggers: [
367
+ * { category: [], sinks: ["syslog"], lowestLevel: "info" },
368
+ * ],
369
+ * });
370
+ * ```
371
+ *
372
+ * @example Custom syslog server configuration
373
+ * ```typescript
374
+ * import { configure } from "@logtape/logtape";
375
+ * import { getSyslogSink } from "@logtape/syslog";
376
+ *
377
+ * await configure({
378
+ * sinks: {
379
+ * syslog: getSyslogSink({
380
+ * hostname: "log-server.example.com",
381
+ * port: 1514,
382
+ * protocol: "tcp",
383
+ * facility: "mail",
384
+ * appName: "my-application",
385
+ * timeout: 10000,
386
+ * }),
387
+ * },
388
+ * loggers: [
389
+ * { category: [], sinks: ["syslog"], lowestLevel: "debug" },
390
+ * ],
391
+ * });
392
+ * ```
393
+ *
394
+ * @example Using structured data for log properties
395
+ * ```typescript
396
+ * import { configure, getLogger } from "@logtape/logtape";
397
+ * import { getSyslogSink } from "@logtape/syslog";
398
+ *
399
+ * await configure({
400
+ * sinks: {
401
+ * syslog: getSyslogSink({
402
+ * includeStructuredData: true,
403
+ * structuredDataId: "myapp@12345",
404
+ * }),
405
+ * },
406
+ * loggers: [
407
+ * { category: [], sinks: ["syslog"], lowestLevel: "info" },
408
+ * ],
409
+ * });
410
+ *
411
+ * const logger = getLogger();
412
+ * // This will include userId and action as structured data
413
+ * logger.info("User action completed", { userId: 123, action: "login" });
414
+ * // Results in: <134>1 2024-01-01T12:00:00.000Z hostname myapp 1234 - [myapp@12345 userId="123" action="login"] User action completed
415
+ * ```
416
+ *
417
+ * @since 0.12.0
418
+ * @see {@link https://tools.ietf.org/html/rfc5424} RFC 5424 - The Syslog Protocol
419
+ * @see {@link SyslogSinkOptions} for detailed configuration options
420
+ */
421
+ function getSyslogSink(options = {}) {
422
+ const hostname$1 = options.hostname ?? "localhost";
423
+ const port = options.port ?? 514;
424
+ const protocol = options.protocol ?? "udp";
425
+ const facility = options.facility ?? "local0";
426
+ const appName = options.appName ?? "logtape";
427
+ const syslogHostname = options.syslogHostname ?? getSystemHostname();
428
+ const processId = options.processId ?? getProcessId();
429
+ const timeout = options.timeout ?? 5e3;
430
+ const includeStructuredData = options.includeStructuredData ?? false;
431
+ const structuredDataId = options.structuredDataId ?? "logtape@32473";
432
+ const formatOptions = {
433
+ facility,
434
+ appName,
435
+ syslogHostname,
436
+ processId,
437
+ includeStructuredData,
438
+ structuredDataId
439
+ };
440
+ const connection = (() => {
441
+ if (typeof Deno !== "undefined") return protocol === "tcp" ? new DenoTcpSyslogConnection(hostname$1, port, timeout) : new DenoUdpSyslogConnection(hostname$1, port, timeout);
442
+ else return protocol === "tcp" ? new NodeTcpSyslogConnection(hostname$1, port, timeout) : new NodeUdpSyslogConnection(hostname$1, port, timeout);
443
+ })();
444
+ let isConnected = false;
445
+ let lastPromise = Promise.resolve();
446
+ const sink = (record) => {
447
+ const syslogMessage = formatSyslogMessage(record, formatOptions);
448
+ lastPromise = lastPromise.then(async () => {
449
+ if (!isConnected) {
450
+ await connection.connect();
451
+ isConnected = true;
452
+ }
453
+ await connection.send(syslogMessage);
454
+ }).catch((error) => {
455
+ isConnected = false;
456
+ throw error;
457
+ });
458
+ };
459
+ sink[Symbol.asyncDispose] = async () => {
460
+ await lastPromise.catch(() => {});
461
+ connection.close();
462
+ isConnected = false;
463
+ };
464
+ return sink;
465
+ }
466
+
467
+ //#endregion
468
+ exports.getSyslogSink = getSyslogSink;