@logtape/file 1.0.0-dev.246 → 1.0.0-dev.248
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/deno.json +1 -1
- package/dist/filesink.base.cjs +347 -52
- package/dist/filesink.base.d.cts +65 -3
- package/dist/filesink.base.d.cts.map +1 -1
- package/dist/filesink.base.d.ts +65 -3
- package/dist/filesink.base.d.ts.map +1 -1
- package/dist/filesink.base.js +347 -52
- package/dist/filesink.base.js.map +1 -1
- package/dist/filesink.deno.cjs +26 -23
- package/dist/filesink.deno.d.cts +17 -4
- package/dist/filesink.deno.d.cts.map +1 -1
- package/dist/filesink.deno.d.ts +17 -4
- package/dist/filesink.deno.d.ts.map +1 -1
- package/dist/filesink.deno.js +26 -24
- package/dist/filesink.deno.js.map +1 -1
- package/dist/filesink.node.cjs +33 -23
- package/dist/filesink.node.d.cts +17 -4
- package/dist/filesink.node.d.cts.map +1 -1
- package/dist/filesink.node.d.ts +17 -4
- package/dist/filesink.node.d.ts.map +1 -1
- package/dist/filesink.node.js +33 -24
- package/dist/filesink.node.js.map +1 -1
- package/dist/mod.cjs +3 -1
- package/dist/mod.d.cts +2 -1
- package/dist/mod.d.ts +2 -1
- package/dist/mod.js +2 -1
- package/dist/streamfilesink.cjs +84 -0
- package/dist/streamfilesink.d.cts +95 -0
- package/dist/streamfilesink.d.cts.map +1 -0
- package/dist/streamfilesink.d.ts +95 -0
- package/dist/streamfilesink.d.ts.map +1 -0
- package/dist/streamfilesink.js +84 -0
- package/dist/streamfilesink.js.map +1 -0
- package/filesink.base.ts +618 -37
- package/filesink.deno.ts +57 -4
- package/filesink.jsr.ts +32 -7
- package/filesink.node.ts +58 -4
- package/filesink.test.ts +120 -0
- package/mod.ts +2 -0
- package/package.json +4 -2
- package/streamfilesink.test.ts +336 -0
- package/streamfilesink.ts +136 -0
- package/tsdown.config.ts +2 -2
package/filesink.deno.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Sink } from "@logtape/logtape";
|
|
2
2
|
import {
|
|
3
|
+
type AsyncRotatingFileSinkDriver,
|
|
3
4
|
type FileSinkOptions,
|
|
4
5
|
getBaseFileSink,
|
|
5
6
|
getBaseRotatingFileSink,
|
|
@@ -17,6 +18,13 @@ export const denoDriver: RotatingFileSinkDriver<Deno.FsFile> = {
|
|
|
17
18
|
writeSync(fd, chunk) {
|
|
18
19
|
fd.writeSync(chunk);
|
|
19
20
|
},
|
|
21
|
+
writeManySync(fd: Deno.FsFile, chunks: Uint8Array[]): void {
|
|
22
|
+
// Deno doesn't have writev, but we can optimize by writing all chunks
|
|
23
|
+
// then doing a single sync operation
|
|
24
|
+
for (const chunk of chunks) {
|
|
25
|
+
fd.writeSync(chunk);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
20
28
|
flushSync(fd) {
|
|
21
29
|
fd.syncSync();
|
|
22
30
|
},
|
|
@@ -27,6 +35,27 @@ export const denoDriver: RotatingFileSinkDriver<Deno.FsFile> = {
|
|
|
27
35
|
renameSync: globalThis?.Deno.renameSync,
|
|
28
36
|
};
|
|
29
37
|
|
|
38
|
+
/**
|
|
39
|
+
* A Deno-specific async file sink driver.
|
|
40
|
+
* @since 1.0.0
|
|
41
|
+
*/
|
|
42
|
+
export const denoAsyncDriver: AsyncRotatingFileSinkDriver<Deno.FsFile> = {
|
|
43
|
+
...denoDriver,
|
|
44
|
+
async writeMany(fd: Deno.FsFile, chunks: Uint8Array[]): Promise<void> {
|
|
45
|
+
// Deno doesn't have async writev, but we can write all chunks
|
|
46
|
+
// then do a single async sync
|
|
47
|
+
for (const chunk of chunks) {
|
|
48
|
+
await fd.write(chunk);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
async flush(fd) {
|
|
52
|
+
await fd.sync();
|
|
53
|
+
},
|
|
54
|
+
close(fd) {
|
|
55
|
+
return Promise.resolve(fd.close());
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
30
59
|
/**
|
|
31
60
|
* Get a file sink.
|
|
32
61
|
*
|
|
@@ -35,12 +64,24 @@ export const denoDriver: RotatingFileSinkDriver<Deno.FsFile> = {
|
|
|
35
64
|
* @param path A path to the file to write to.
|
|
36
65
|
* @param options The options for the sink.
|
|
37
66
|
* @returns A sink that writes to the file. The sink is also a disposable
|
|
38
|
-
* object that closes the file when disposed.
|
|
67
|
+
* object that closes the file when disposed. If `nonBlocking` is enabled,
|
|
68
|
+
* returns a sink that also implements {@link AsyncDisposable}.
|
|
39
69
|
*/
|
|
70
|
+
export function getFileSink(
|
|
71
|
+
path: string,
|
|
72
|
+
options?: FileSinkOptions,
|
|
73
|
+
): Sink & Disposable;
|
|
74
|
+
export function getFileSink(
|
|
75
|
+
path: string,
|
|
76
|
+
options: FileSinkOptions & { nonBlocking: true },
|
|
77
|
+
): Sink & AsyncDisposable;
|
|
40
78
|
export function getFileSink(
|
|
41
79
|
path: string,
|
|
42
80
|
options: FileSinkOptions = {},
|
|
43
|
-
): Sink & Disposable {
|
|
81
|
+
): Sink & (Disposable | AsyncDisposable) {
|
|
82
|
+
if (options.nonBlocking) {
|
|
83
|
+
return getBaseFileSink(path, { ...options, ...denoAsyncDriver });
|
|
84
|
+
}
|
|
44
85
|
return getBaseFileSink(path, { ...options, ...denoDriver });
|
|
45
86
|
}
|
|
46
87
|
|
|
@@ -57,12 +98,24 @@ export function getFileSink(
|
|
|
57
98
|
* @param path A path to the file to write to.
|
|
58
99
|
* @param options The options for the sink and the file driver.
|
|
59
100
|
* @returns A sink that writes to the file. The sink is also a disposable
|
|
60
|
-
* object that closes the file when disposed.
|
|
101
|
+
* object that closes the file when disposed. If `nonBlocking` is enabled,
|
|
102
|
+
* returns a sink that also implements {@link AsyncDisposable}.
|
|
61
103
|
*/
|
|
104
|
+
export function getRotatingFileSink(
|
|
105
|
+
path: string,
|
|
106
|
+
options?: RotatingFileSinkOptions,
|
|
107
|
+
): Sink & Disposable;
|
|
108
|
+
export function getRotatingFileSink(
|
|
109
|
+
path: string,
|
|
110
|
+
options: RotatingFileSinkOptions & { nonBlocking: true },
|
|
111
|
+
): Sink & AsyncDisposable;
|
|
62
112
|
export function getRotatingFileSink(
|
|
63
113
|
path: string,
|
|
64
114
|
options: RotatingFileSinkOptions = {},
|
|
65
|
-
): Sink & Disposable {
|
|
115
|
+
): Sink & (Disposable | AsyncDisposable) {
|
|
116
|
+
if (options.nonBlocking) {
|
|
117
|
+
return getBaseRotatingFileSink(path, { ...options, ...denoAsyncDriver });
|
|
118
|
+
}
|
|
66
119
|
return getBaseRotatingFileSink(path, { ...options, ...denoDriver });
|
|
67
120
|
}
|
|
68
121
|
|
package/filesink.jsr.ts
CHANGED
|
@@ -4,7 +4,10 @@ import type {
|
|
|
4
4
|
RotatingFileSinkOptions,
|
|
5
5
|
} from "./filesink.base.ts";
|
|
6
6
|
|
|
7
|
-
const filesink: Omit<
|
|
7
|
+
const filesink: Omit<
|
|
8
|
+
typeof import("./filesink.deno.ts"),
|
|
9
|
+
"denoDriver" | "denoAsyncDriver"
|
|
10
|
+
> =
|
|
8
11
|
// dnt-shim-ignore
|
|
9
12
|
await ("Deno" in globalThis
|
|
10
13
|
? import("./filesink.deno.ts")
|
|
@@ -18,13 +21,24 @@ const filesink: Omit<typeof import("./filesink.deno.ts"), "denoDriver"> =
|
|
|
18
21
|
* @param path A path to the file to write to.
|
|
19
22
|
* @param options The options for the sink.
|
|
20
23
|
* @returns A sink that writes to the file. The sink is also a disposable
|
|
21
|
-
* object that closes the file when disposed.
|
|
24
|
+
* object that closes the file when disposed. If `nonBlocking` is enabled,
|
|
25
|
+
* returns a sink that also implements {@link AsyncDisposable}.
|
|
22
26
|
*/
|
|
27
|
+
export function getFileSink(
|
|
28
|
+
path: string,
|
|
29
|
+
options?: FileSinkOptions,
|
|
30
|
+
): Sink & Disposable;
|
|
31
|
+
export function getFileSink(
|
|
32
|
+
path: string,
|
|
33
|
+
options: FileSinkOptions & { nonBlocking: true },
|
|
34
|
+
): Sink & AsyncDisposable;
|
|
23
35
|
export function getFileSink(
|
|
24
36
|
path: string,
|
|
25
37
|
options: FileSinkOptions = {},
|
|
26
|
-
): Sink & Disposable {
|
|
27
|
-
return filesink.getFileSink(path, options)
|
|
38
|
+
): Sink & (Disposable | AsyncDisposable) {
|
|
39
|
+
return filesink.getFileSink(path, options) as
|
|
40
|
+
& Sink
|
|
41
|
+
& (Disposable | AsyncDisposable);
|
|
28
42
|
}
|
|
29
43
|
|
|
30
44
|
/**
|
|
@@ -40,13 +54,24 @@ export function getFileSink(
|
|
|
40
54
|
* @param path A path to the file to write to.
|
|
41
55
|
* @param options The options for the sink and the file driver.
|
|
42
56
|
* @returns A sink that writes to the file. The sink is also a disposable
|
|
43
|
-
* object that closes the file when disposed.
|
|
57
|
+
* object that closes the file when disposed. If `nonBlocking` is enabled,
|
|
58
|
+
* returns a sink that also implements {@link AsyncDisposable}.
|
|
44
59
|
*/
|
|
60
|
+
export function getRotatingFileSink(
|
|
61
|
+
path: string,
|
|
62
|
+
options?: RotatingFileSinkOptions,
|
|
63
|
+
): Sink & Disposable;
|
|
64
|
+
export function getRotatingFileSink(
|
|
65
|
+
path: string,
|
|
66
|
+
options: RotatingFileSinkOptions & { nonBlocking: true },
|
|
67
|
+
): Sink & AsyncDisposable;
|
|
45
68
|
export function getRotatingFileSink(
|
|
46
69
|
path: string,
|
|
47
70
|
options: RotatingFileSinkOptions = {},
|
|
48
|
-
): Sink & Disposable {
|
|
49
|
-
return filesink.getRotatingFileSink(path, options)
|
|
71
|
+
): Sink & (Disposable | AsyncDisposable) {
|
|
72
|
+
return filesink.getRotatingFileSink(path, options) as
|
|
73
|
+
& Sink
|
|
74
|
+
& (Disposable | AsyncDisposable);
|
|
50
75
|
}
|
|
51
76
|
|
|
52
77
|
// cSpell: ignore filesink
|
package/filesink.node.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Sink } from "@logtape/logtape";
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import { promisify } from "node:util";
|
|
3
4
|
import {
|
|
5
|
+
type AsyncRotatingFileSinkDriver,
|
|
4
6
|
type FileSinkOptions,
|
|
5
7
|
getBaseFileSink,
|
|
6
8
|
getBaseRotatingFileSink,
|
|
@@ -16,12 +18,40 @@ export const nodeDriver: RotatingFileSinkDriver<number | void> = {
|
|
|
16
18
|
return fs.openSync(path, "a");
|
|
17
19
|
},
|
|
18
20
|
writeSync: fs.writeSync,
|
|
21
|
+
writeManySync(fd: number, chunks: Uint8Array[]): void {
|
|
22
|
+
if (chunks.length === 0) return;
|
|
23
|
+
if (chunks.length === 1) {
|
|
24
|
+
fs.writeSync(fd, chunks[0]);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Use writev for multiple chunks
|
|
28
|
+
fs.writevSync(fd, chunks);
|
|
29
|
+
},
|
|
19
30
|
flushSync: fs.fsyncSync,
|
|
20
31
|
closeSync: fs.closeSync,
|
|
21
32
|
statSync: fs.statSync,
|
|
22
33
|
renameSync: fs.renameSync,
|
|
23
34
|
};
|
|
24
35
|
|
|
36
|
+
/**
|
|
37
|
+
* A Node.js-specific async file sink driver.
|
|
38
|
+
* @since 1.0.0
|
|
39
|
+
*/
|
|
40
|
+
export const nodeAsyncDriver: AsyncRotatingFileSinkDriver<number | void> = {
|
|
41
|
+
...nodeDriver,
|
|
42
|
+
async writeMany(fd: number, chunks: Uint8Array[]): Promise<void> {
|
|
43
|
+
if (chunks.length === 0) return;
|
|
44
|
+
if (chunks.length === 1) {
|
|
45
|
+
await promisify(fs.write)(fd, chunks[0]);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Use async writev for multiple chunks
|
|
49
|
+
await promisify(fs.writev)(fd, chunks);
|
|
50
|
+
},
|
|
51
|
+
flush: promisify(fs.fsync),
|
|
52
|
+
close: promisify(fs.close),
|
|
53
|
+
};
|
|
54
|
+
|
|
25
55
|
/**
|
|
26
56
|
* Get a file sink.
|
|
27
57
|
*
|
|
@@ -30,12 +60,24 @@ export const nodeDriver: RotatingFileSinkDriver<number | void> = {
|
|
|
30
60
|
* @param path A path to the file to write to.
|
|
31
61
|
* @param options The options for the sink.
|
|
32
62
|
* @returns A sink that writes to the file. The sink is also a disposable
|
|
33
|
-
* object that closes the file when disposed.
|
|
63
|
+
* object that closes the file when disposed. If `nonBlocking` is enabled,
|
|
64
|
+
* returns a sink that also implements {@link AsyncDisposable}.
|
|
34
65
|
*/
|
|
66
|
+
export function getFileSink(
|
|
67
|
+
path: string,
|
|
68
|
+
options?: FileSinkOptions,
|
|
69
|
+
): Sink & Disposable;
|
|
70
|
+
export function getFileSink(
|
|
71
|
+
path: string,
|
|
72
|
+
options: FileSinkOptions & { nonBlocking: true },
|
|
73
|
+
): Sink & AsyncDisposable;
|
|
35
74
|
export function getFileSink(
|
|
36
75
|
path: string,
|
|
37
76
|
options: FileSinkOptions = {},
|
|
38
|
-
): Sink & Disposable {
|
|
77
|
+
): Sink & (Disposable | AsyncDisposable) {
|
|
78
|
+
if (options.nonBlocking) {
|
|
79
|
+
return getBaseFileSink(path, { ...options, ...nodeAsyncDriver });
|
|
80
|
+
}
|
|
39
81
|
return getBaseFileSink(path, { ...options, ...nodeDriver });
|
|
40
82
|
}
|
|
41
83
|
|
|
@@ -52,12 +94,24 @@ export function getFileSink(
|
|
|
52
94
|
* @param path A path to the file to write to.
|
|
53
95
|
* @param options The options for the sink and the file driver.
|
|
54
96
|
* @returns A sink that writes to the file. The sink is also a disposable
|
|
55
|
-
* object that closes the file when disposed.
|
|
97
|
+
* object that closes the file when disposed. If `nonBlocking` is enabled,
|
|
98
|
+
* returns a sink that also implements {@link AsyncDisposable}.
|
|
56
99
|
*/
|
|
100
|
+
export function getRotatingFileSink(
|
|
101
|
+
path: string,
|
|
102
|
+
options?: RotatingFileSinkOptions,
|
|
103
|
+
): Sink & Disposable;
|
|
104
|
+
export function getRotatingFileSink(
|
|
105
|
+
path: string,
|
|
106
|
+
options: RotatingFileSinkOptions & { nonBlocking: true },
|
|
107
|
+
): Sink & AsyncDisposable;
|
|
57
108
|
export function getRotatingFileSink(
|
|
58
109
|
path: string,
|
|
59
110
|
options: RotatingFileSinkOptions = {},
|
|
60
|
-
): Sink & Disposable {
|
|
111
|
+
): Sink & (Disposable | AsyncDisposable) {
|
|
112
|
+
if (options.nonBlocking) {
|
|
113
|
+
return getBaseRotatingFileSink(path, { ...options, ...nodeAsyncDriver });
|
|
114
|
+
}
|
|
61
115
|
return getBaseRotatingFileSink(path, { ...options, ...nodeDriver });
|
|
62
116
|
}
|
|
63
117
|
|
package/filesink.test.ts
CHANGED
|
@@ -2,8 +2,10 @@ import { getFileSink, getRotatingFileSink } from "#filesink";
|
|
|
2
2
|
import { suite } from "@alinea/suite";
|
|
3
3
|
import { isDeno } from "@david/which-runtime";
|
|
4
4
|
import type { Sink } from "@logtape/logtape";
|
|
5
|
+
import { assert } from "@std/assert/assert";
|
|
5
6
|
import { assertEquals } from "@std/assert/equals";
|
|
6
7
|
import { assertThrows } from "@std/assert/throws";
|
|
8
|
+
import { delay } from "@std/async/delay";
|
|
7
9
|
import { join } from "@std/path/join";
|
|
8
10
|
import fs from "node:fs";
|
|
9
11
|
import { tmpdir } from "node:os";
|
|
@@ -691,4 +693,122 @@ test("getBaseFileSink() with flushInterval disabled", () => {
|
|
|
691
693
|
assertEquals(content.includes("Hello, 123 & 456!"), true);
|
|
692
694
|
});
|
|
693
695
|
|
|
696
|
+
test("getFileSink() with nonBlocking mode", async () => {
|
|
697
|
+
const path = makeTempFileSync();
|
|
698
|
+
const sink = getFileSink(path, {
|
|
699
|
+
nonBlocking: true,
|
|
700
|
+
bufferSize: 50, // Small buffer to trigger flush by size
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// Check that it returns AsyncDisposable
|
|
704
|
+
assert(typeof sink === "function");
|
|
705
|
+
assert(Symbol.asyncDispose in sink);
|
|
706
|
+
|
|
707
|
+
// Add enough records to trigger buffer flush
|
|
708
|
+
sink(debug);
|
|
709
|
+
sink(info);
|
|
710
|
+
|
|
711
|
+
// Wait for async flush to complete
|
|
712
|
+
await delay(50);
|
|
713
|
+
const content = fs.readFileSync(path, { encoding: "utf-8" });
|
|
714
|
+
assert(content.includes("Hello, 123 & 456!"));
|
|
715
|
+
|
|
716
|
+
await (sink as Sink & AsyncDisposable)[Symbol.asyncDispose]();
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
test("getRotatingFileSink() with nonBlocking mode", async () => {
|
|
720
|
+
const path = makeTempFileSync();
|
|
721
|
+
const sink = getRotatingFileSink(path, {
|
|
722
|
+
maxSize: 200,
|
|
723
|
+
nonBlocking: true,
|
|
724
|
+
bufferSize: 1000, // Large buffer to prevent immediate flush
|
|
725
|
+
flushInterval: 50, // Short interval for testing
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
// Check that it returns AsyncDisposable
|
|
729
|
+
assert(typeof sink === "function");
|
|
730
|
+
assert(Symbol.asyncDispose in sink);
|
|
731
|
+
|
|
732
|
+
// Add records with current timestamp
|
|
733
|
+
const record1 = { ...debug, timestamp: Date.now() };
|
|
734
|
+
const record2 = { ...info, timestamp: Date.now() };
|
|
735
|
+
sink(record1);
|
|
736
|
+
sink(record2);
|
|
737
|
+
assertEquals(fs.readFileSync(path, { encoding: "utf-8" }), ""); // Not written yet
|
|
738
|
+
|
|
739
|
+
// Wait for flush interval to pass
|
|
740
|
+
await delay(100);
|
|
741
|
+
const content = fs.readFileSync(path, { encoding: "utf-8" });
|
|
742
|
+
assert(content.includes("Hello, 123 & 456!"));
|
|
743
|
+
|
|
744
|
+
await (sink as Sink & AsyncDisposable)[Symbol.asyncDispose]();
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
test("getFileSink() with nonBlocking high-volume logging", async () => {
|
|
748
|
+
const path = makeTempFileSync();
|
|
749
|
+
const sink = getFileSink(path, {
|
|
750
|
+
nonBlocking: true,
|
|
751
|
+
bufferSize: 50, // Small buffer to trigger flush
|
|
752
|
+
flushInterval: 0, // Disable time-based flushing for this test
|
|
753
|
+
}) as unknown as Sink & AsyncDisposable;
|
|
754
|
+
|
|
755
|
+
// Add enough records to trigger buffer flush (50 chars per record roughly)
|
|
756
|
+
let totalChars = 0;
|
|
757
|
+
let recordCount = 0;
|
|
758
|
+
while (totalChars < 100) { // Exceed buffer size
|
|
759
|
+
sink(debug);
|
|
760
|
+
totalChars += 67; // Approximate length of each debug record
|
|
761
|
+
recordCount++;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Wait for async flush to complete
|
|
765
|
+
await delay(50);
|
|
766
|
+
const content = fs.readFileSync(path, { encoding: "utf-8" });
|
|
767
|
+
|
|
768
|
+
// Should have some records written by now
|
|
769
|
+
const writtenCount = (content.match(/Hello, 123 & 456!/g) || []).length;
|
|
770
|
+
assert(
|
|
771
|
+
writtenCount > 0,
|
|
772
|
+
`Expected some records to be written, but got ${writtenCount}`,
|
|
773
|
+
);
|
|
774
|
+
|
|
775
|
+
await sink[Symbol.asyncDispose]();
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
test("getRotatingFileSink() with nonBlocking rotation", async () => {
|
|
779
|
+
const path = makeTempFileSync();
|
|
780
|
+
const sink = getRotatingFileSink(path, {
|
|
781
|
+
maxSize: 150, // Small size to trigger rotation
|
|
782
|
+
nonBlocking: true,
|
|
783
|
+
bufferSize: 100,
|
|
784
|
+
flushInterval: 10,
|
|
785
|
+
}) as unknown as Sink & AsyncDisposable;
|
|
786
|
+
|
|
787
|
+
// Add enough records to trigger rotation
|
|
788
|
+
sink(debug);
|
|
789
|
+
sink(info);
|
|
790
|
+
sink(warning);
|
|
791
|
+
sink(error);
|
|
792
|
+
|
|
793
|
+
// Wait for all flushes and rotation to complete
|
|
794
|
+
await delay(200);
|
|
795
|
+
|
|
796
|
+
// Check that rotation occurred
|
|
797
|
+
const mainContent = fs.readFileSync(path, { encoding: "utf-8" });
|
|
798
|
+
let rotatedContent = "";
|
|
799
|
+
try {
|
|
800
|
+
rotatedContent = fs.readFileSync(`${path}.1`, { encoding: "utf-8" });
|
|
801
|
+
} catch {
|
|
802
|
+
// No rotation occurred
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const allContent = mainContent + rotatedContent;
|
|
806
|
+
|
|
807
|
+
// Should have all 4 records somewhere
|
|
808
|
+
const recordCount = (allContent.match(/Hello, 123 & 456!/g) || []).length;
|
|
809
|
+
assertEquals(recordCount, 4);
|
|
810
|
+
|
|
811
|
+
await sink[Symbol.asyncDispose]();
|
|
812
|
+
});
|
|
813
|
+
|
|
694
814
|
// cSpell: ignore filesink
|
package/mod.ts
CHANGED
|
@@ -4,4 +4,6 @@ export type {
|
|
|
4
4
|
RotatingFileSinkDriver,
|
|
5
5
|
RotatingFileSinkOptions,
|
|
6
6
|
} from "./filesink.base.ts";
|
|
7
|
+
export type { StreamFileSinkOptions } from "./streamfilesink.ts";
|
|
7
8
|
export { getFileSink, getRotatingFileSink } from "#filesink";
|
|
9
|
+
export { getStreamFileSink } from "./streamfilesink.ts";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logtape/file",
|
|
3
|
-
"version": "1.0.0-dev.
|
|
3
|
+
"version": "1.0.0-dev.248+f96c618d",
|
|
4
4
|
"description": "File sink and rotating file sink for LogTape",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"logging",
|
|
@@ -55,13 +55,15 @@
|
|
|
55
55
|
"require": "./dist/filesink.node.cjs"
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
+
"sideEffects": false,
|
|
58
59
|
"peerDependencies": {
|
|
59
|
-
"@logtape/logtape": "1.0.0-dev.
|
|
60
|
+
"@logtape/logtape": "1.0.0-dev.248+f96c618d"
|
|
60
61
|
},
|
|
61
62
|
"devDependencies": {
|
|
62
63
|
"@alinea/suite": "^0.6.3",
|
|
63
64
|
"@david/which-runtime": "npm:@jsr/david__which-runtime@^0.2.1",
|
|
64
65
|
"@std/assert": "npm:@jsr/std__assert@^1.0.13",
|
|
66
|
+
"@std/async": "npm:@jsr/std__async@^1.0.13",
|
|
65
67
|
"@std/path": "npm:@jsr/std__path@^1.1.0",
|
|
66
68
|
"tsdown": "^0.12.7",
|
|
67
69
|
"typescript": "^5.8.3"
|