@pori15/logixlysia 6.0.1 → 6.0.3

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.
@@ -1,122 +1,122 @@
1
- import { promises as fs } from 'node:fs'
2
- import { promisify } from 'node:util'
3
- import { gzip } from 'node:zlib'
4
- import type { LogRotationConfig } from '../interfaces'
5
- import {
6
- getRotatedFiles,
7
- parseRetention,
8
- parseSize,
9
- shouldRotateBySize
10
- } from '../utils/rotation'
11
-
12
- const gzipAsync = promisify(gzip)
13
-
14
- const pad2 = (value: number): string => String(value).padStart(2, '0')
15
-
16
- export const getRotatedFileName = (filePath: string, date: Date): string => {
17
- const yyyy = date.getFullYear()
18
- const mm = pad2(date.getMonth() + 1)
19
- const dd = pad2(date.getDate())
20
- const HH = pad2(date.getHours())
21
- const MM = pad2(date.getMinutes())
22
- const ss = pad2(date.getSeconds())
23
- return `${filePath}.${yyyy}-${mm}-${dd}-${HH}-${MM}-${ss}`
24
- }
25
-
26
- export const rotateFile = async (filePath: string): Promise<string> => {
27
- try {
28
- const stat = await fs.stat(filePath)
29
- if (stat.size === 0) {
30
- return ''
31
- }
32
- } catch {
33
- return ''
34
- }
35
-
36
- const rotated = getRotatedFileName(filePath, new Date())
37
- await fs.rename(filePath, rotated)
38
- return rotated
39
- }
40
-
41
- export const compressFile = async (filePath: string): Promise<void> => {
42
- const content = await fs.readFile(filePath)
43
- const compressed = await gzipAsync(content)
44
- await fs.writeFile(`${filePath}.gz`, compressed)
45
- await fs.rm(filePath, { force: true })
46
- }
47
-
48
- export const shouldRotate = async (
49
- filePath: string,
50
- config: LogRotationConfig
51
- ): Promise<boolean> => {
52
- if (config.maxSize === undefined) {
53
- return false
54
- }
55
- const maxSize = parseSize(config.maxSize)
56
- return await shouldRotateBySize(filePath, maxSize)
57
- }
58
-
59
- const cleanupByCount = async (
60
- filePath: string,
61
- maxFiles: number
62
- ): Promise<void> => {
63
- const rotated = await getRotatedFiles(filePath)
64
- if (rotated.length <= maxFiles) {
65
- return
66
- }
67
-
68
- const stats = await Promise.all(
69
- rotated.map(async p => ({ path: p, stat: await fs.stat(p) }))
70
- )
71
-
72
- stats.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
73
- const toDelete = stats.slice(maxFiles)
74
- await Promise.all(toDelete.map(({ path }) => fs.rm(path, { force: true })))
75
- }
76
-
77
- const cleanupByTime = async (
78
- filePath: string,
79
- maxAgeMs: number
80
- ): Promise<void> => {
81
- const rotated = await getRotatedFiles(filePath)
82
- if (rotated.length === 0) {
83
- return
84
- }
85
-
86
- const now = Date.now()
87
- const stats = await Promise.all(
88
- rotated.map(async p => ({ path: p, stat: await fs.stat(p) }))
89
- )
90
-
91
- const toDelete = stats.filter(({ stat }) => now - stat.mtimeMs > maxAgeMs)
92
- await Promise.all(toDelete.map(({ path }) => fs.rm(path, { force: true })))
93
- }
94
-
95
- export const performRotation = async (
96
- filePath: string,
97
- config: LogRotationConfig
98
- ): Promise<void> => {
99
- const rotated = await rotateFile(filePath)
100
- if (!rotated) {
101
- return
102
- }
103
-
104
- const shouldCompress = config.compress === true
105
- if (shouldCompress) {
106
- const algo = config.compression ?? 'gzip'
107
- if (algo === 'gzip') {
108
- await compressFile(rotated)
109
- }
110
- }
111
-
112
- if (config.maxFiles !== undefined) {
113
- const retention = parseRetention(config.maxFiles)
114
- if (retention.type === 'count') {
115
- await cleanupByCount(filePath, retention.value)
116
- } else {
117
- await cleanupByTime(filePath, retention.value)
118
- }
119
- }
120
-
121
- // Optional interval-based rotation cleanup (create interval directories / naming) is not required by tests.
122
- }
1
+ import { promises as fs } from 'node:fs'
2
+ import { promisify } from 'node:util'
3
+ import { gzip } from 'node:zlib'
4
+ import type { LogRotationConfig } from '../interfaces'
5
+ import {
6
+ getRotatedFiles,
7
+ parseRetention,
8
+ parseSize,
9
+ shouldRotateBySize
10
+ } from '../utils/rotation'
11
+
12
+ const gzipAsync = promisify(gzip)
13
+
14
+ const pad2 = (value: number): string => String(value).padStart(2, '0')
15
+
16
+ export const getRotatedFileName = (filePath: string, date: Date): string => {
17
+ const yyyy = date.getFullYear()
18
+ const mm = pad2(date.getMonth() + 1)
19
+ const dd = pad2(date.getDate())
20
+ const HH = pad2(date.getHours())
21
+ const MM = pad2(date.getMinutes())
22
+ const ss = pad2(date.getSeconds())
23
+ return `${filePath}.${yyyy}-${mm}-${dd}-${HH}-${MM}-${ss}`
24
+ }
25
+
26
+ export const rotateFile = async (filePath: string): Promise<string> => {
27
+ try {
28
+ const stat = await fs.stat(filePath)
29
+ if (stat.size === 0) {
30
+ return ''
31
+ }
32
+ } catch {
33
+ return ''
34
+ }
35
+
36
+ const rotated = getRotatedFileName(filePath, new Date())
37
+ await fs.rename(filePath, rotated)
38
+ return rotated
39
+ }
40
+
41
+ export const compressFile = async (filePath: string): Promise<void> => {
42
+ const content = await fs.readFile(filePath)
43
+ const compressed = await gzipAsync(content)
44
+ await fs.writeFile(`${filePath}.gz`, compressed)
45
+ await fs.rm(filePath, { force: true })
46
+ }
47
+
48
+ export const shouldRotate = async (
49
+ filePath: string,
50
+ config: LogRotationConfig
51
+ ): Promise<boolean> => {
52
+ if (config.maxSize === undefined) {
53
+ return false
54
+ }
55
+ const maxSize = parseSize(config.maxSize)
56
+ return await shouldRotateBySize(filePath, maxSize)
57
+ }
58
+
59
+ const cleanupByCount = async (
60
+ filePath: string,
61
+ maxFiles: number
62
+ ): Promise<void> => {
63
+ const rotated = await getRotatedFiles(filePath)
64
+ if (rotated.length <= maxFiles) {
65
+ return
66
+ }
67
+
68
+ const stats = await Promise.all(
69
+ rotated.map(async p => ({ path: p, stat: await fs.stat(p) }))
70
+ )
71
+
72
+ stats.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
73
+ const toDelete = stats.slice(maxFiles)
74
+ await Promise.all(toDelete.map(({ path }) => fs.rm(path, { force: true })))
75
+ }
76
+
77
+ const cleanupByTime = async (
78
+ filePath: string,
79
+ maxAgeMs: number
80
+ ): Promise<void> => {
81
+ const rotated = await getRotatedFiles(filePath)
82
+ if (rotated.length === 0) {
83
+ return
84
+ }
85
+
86
+ const now = Date.now()
87
+ const stats = await Promise.all(
88
+ rotated.map(async p => ({ path: p, stat: await fs.stat(p) }))
89
+ )
90
+
91
+ const toDelete = stats.filter(({ stat }) => now - stat.mtimeMs > maxAgeMs)
92
+ await Promise.all(toDelete.map(({ path }) => fs.rm(path, { force: true })))
93
+ }
94
+
95
+ export const performRotation = async (
96
+ filePath: string,
97
+ config: LogRotationConfig
98
+ ): Promise<void> => {
99
+ const rotated = await rotateFile(filePath)
100
+ if (!rotated) {
101
+ return
102
+ }
103
+
104
+ const shouldCompress = config.compress === true
105
+ if (shouldCompress) {
106
+ const algo = config.compression ?? 'gzip'
107
+ if (algo === 'gzip') {
108
+ await compressFile(rotated)
109
+ }
110
+ }
111
+
112
+ if (config.maxFiles !== undefined) {
113
+ const retention = parseRetention(config.maxFiles)
114
+ if (retention.type === 'count') {
115
+ await cleanupByCount(filePath, retention.value)
116
+ } else {
117
+ await cleanupByTime(filePath, retention.value)
118
+ }
119
+ }
120
+
121
+ // Optional interval-based rotation cleanup (create interval directories / naming) is not required by tests.
122
+ }
@@ -1,13 +1,13 @@
1
- export const parseError = (error: unknown): string => {
2
- let message = 'An error occurred'
3
-
4
- if (error instanceof Error) {
5
- message = error.message
6
- } else if (error && typeof error === 'object' && 'message' in error) {
7
- message = error.message as string
8
- } else {
9
- message = String(error)
10
- }
11
-
12
- return message
13
- }
1
+ export const parseError = (error: unknown): string => {
2
+ let message = 'An error occurred'
3
+
4
+ if (error instanceof Error) {
5
+ message = error.message
6
+ } else if (error && typeof error === 'object' && 'message' in error) {
7
+ message = error.message as string
8
+ } else {
9
+ message = String(error)
10
+ }
11
+
12
+ return message
13
+ }