Comparing version 2.0.0 to 2.1.0
@@ -5,2 +5,3 @@ 'use strict' | ||
const { dirname, join } = require('path') | ||
const { format } = require('date-fns') | ||
@@ -84,4 +85,5 @@ function parseSize (size) { | ||
function buildFileName (fileVal, lastNumber = 1, extension) { | ||
return `${getFileName(fileVal)}.${lastNumber}${extension ?? ''}` | ||
function buildFileName (fileVal, date, lastNumber = 1, extension) { | ||
const dateStr = date ? `.${date}` : '' | ||
return `${getFileName(fileVal)}${dateStr}.${lastNumber}${extension ?? ''}` | ||
} | ||
@@ -165,2 +167,20 @@ | ||
function validateDateFormat (formatStr) { | ||
const invalidChars = /[/\\?%*:|"<>]/g | ||
if (invalidChars.test(formatStr)) { | ||
throw new Error(`${formatStr} contains invalid characters`) | ||
} | ||
return true | ||
} | ||
function parseDate (formatStr, frequencySpec, parseStart = false) { | ||
if (!(formatStr && (frequencySpec?.frequency === 'daily' || frequencySpec?.frequency === 'hourly'))) return null | ||
try { | ||
return format(parseStart ? frequencySpec.start : frequencySpec.next, formatStr) | ||
} catch (error) { | ||
throw new Error(`${formatStr} must be a valid date format`) | ||
} | ||
} | ||
module.exports = { | ||
@@ -178,3 +198,5 @@ buildFileName, | ||
getFileSize, | ||
validateLimitOptions | ||
validateLimitOptions, | ||
parseDate, | ||
validateDateFormat | ||
} |
{ | ||
"name": "pino-roll", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "A Pino transport that automatically rolls your log files", | ||
@@ -26,6 +26,6 @@ "main": "pino-roll.js", | ||
"dependencies": { | ||
"date-fns": "^4.1.0", | ||
"sonic-boom": "^4.0.1" | ||
}, | ||
"devDependencies": { | ||
"date-fns": "^3.6.0", | ||
"husky": "^9.0.11", | ||
@@ -32,0 +32,0 @@ "pino": "^9.2.0", |
@@ -13,3 +13,5 @@ 'use strict' | ||
getFileSize, | ||
validateLimitOptions | ||
validateLimitOptions, | ||
parseDate, | ||
validateDateFormat | ||
} = require('./lib/utils') | ||
@@ -50,2 +52,5 @@ | ||
* @property {LimitOptions} limit? - strategy used to remove oldest files when rotating them. | ||
* | ||
* @property {string} dateFormat? - When specified, appends the current date/time to the file name in the provided format. | ||
* Supports date formats from `date-fns` (see: https://date-fns.org/v4.1.0/docs/format), such as 'yyyy-MM-dd' and 'yyyy-MM-dd-hh'. | ||
*/ | ||
@@ -77,10 +82,13 @@ | ||
symlink, | ||
dateFormat, | ||
...opts | ||
} = {}) { | ||
validateLimitOptions(limit) | ||
validateDateFormat(dateFormat) | ||
const frequencySpec = parseFrequency(frequency) | ||
let date = parseDate(dateFormat, frequencySpec, true) | ||
let number = await detectLastNumber(file, frequencySpec?.start) | ||
let fileName = buildFileName(file, number, extension) | ||
let fileName = buildFileName(file, date, number, extension) | ||
const createdFileNames = [fileName] | ||
@@ -109,3 +117,3 @@ let currentSize = await getFileSize(fileName) | ||
currentSize = 0 | ||
fileName = buildFileName(file, ++number, extension) | ||
fileName = buildFileName(file, date, ++number, extension) | ||
// delay to let the destination finish its write | ||
@@ -131,3 +139,4 @@ destination.once('drain', roll) | ||
rollTimeout = setTimeout(() => { | ||
fileName = buildFileName(file, ++number, extension) | ||
date = parseDate(dateFormat, frequencySpec) | ||
fileName = buildFileName(file, date, ++number, extension) | ||
roll() | ||
@@ -134,0 +143,0 @@ frequencySpec.next = getNext(frequency) |
@@ -68,2 +68,9 @@ # pino-roll | ||
* `dateFormat?`: the format for appending the current date/time to the file name. | ||
When specified, appends the date/time in the provided format to the log file name. | ||
Supports date formats from `date-fns` (see: [date-fns format documentation](https://date-fns.org/v4.1.0/docs/format)). | ||
For example: | ||
Daily: `'yyyy-MM-dd'` → `error.2024-09-24.log` | ||
Hourly: `'yyyy-MM-dd-hh'` → `error.2024-09-24-05.log` | ||
Please not that `limit` only considers **created log files**. It will not consider any pre-existing files. | ||
@@ -70,0 +77,0 @@ Therefore, starting your logger with a limit will never tries deleting older log files, created during previous executions. |
@@ -7,2 +7,3 @@ 'use strict' | ||
const { test } = require('tap') | ||
const { format } = require('date-fns') | ||
@@ -20,3 +21,5 @@ const { | ||
getFileName, | ||
validateLimitOptions | ||
validateLimitOptions, | ||
validateDateFormat, | ||
parseDate | ||
} = require('../../lib/utils') | ||
@@ -83,5 +86,28 @@ const { cleanAndCreateFolder, sleep } = require('../utils') | ||
equal(buildFileName(() => 'my-func'), 'my-func.1', 'appends 1 by default') | ||
equal(buildFileName('my-file', 5, ext), 'my-file.5.json', 'appends number and extension') | ||
equal(buildFileName('my-file', null, 5, ext), 'my-file.5.json', 'appends number and extension') | ||
equal(buildFileName('my-file', '2024-09-26'), 'my-file.2024-09-26.1', 'appends date') | ||
equal(buildFileName('my-file', '2024-09-26-07'), 'my-file.2024-09-26-07.1', 'appends date and hour') | ||
equal(buildFileName('my-file', '2024-09-26', 5), 'my-file.2024-09-26.5', 'appends date and number') | ||
equal(buildFileName('my-file', '2024-09-26', 5, ext), 'my-file.2024-09-26.5.json', 'appends date, number and extension') | ||
}) | ||
test('validateDateFormat()', async ({ equal, throws }) => { | ||
equal(validateDateFormat('2024-09-26'), true, 'returns null on valid date format') | ||
equal(validateDateFormat('2024-09-26-10'), true, 'returns null on valid date time format') | ||
throws(() => validateDateFormat('2024:09:26'), 'throws on invalid date format with semicolon') | ||
throws(() => validateDateFormat('2024*09*26'), 'throws on invalid date format with asterisk') | ||
throws(() => validateDateFormat('2024<09>26'), 'throws on invalid date format with <>') | ||
}) | ||
test('parseDate()', async ({ equal, throws }) => { | ||
const today = new Date() | ||
const frequencySpec = { frequency: 'hourly', start: startOfHour(today).getTime(), next: startOfHour(addHours(today, 1)).getTime() } | ||
equal(parseDate(null, frequencySpec), null, 'returns null on empty format') | ||
equal(parseDate('yyyy-MM-dd', { frequency: 100 }), null, 'returns null on custom frequency') | ||
equal(parseDate('yyyy-MM-dd-hh', frequencySpec, true), format(frequencySpec.start, 'yyyy-MM-dd-hh'), 'parse start date time') | ||
equal(parseDate('yyyy-MM-dd-hh', frequencySpec), format(frequencySpec.next, 'yyyy-MM-dd-hh'), 'parse next date time') | ||
throws(() => parseDate('yyyy-MM-dd-hhU', frequencySpec), 'throws on invalid date format with character U') | ||
throws(() => parseDate('yyyy-MM-dd-hhJ', frequencySpec), 'throws on invalid date format with character J') | ||
}) | ||
test('getFileSize()', async ({ test, beforeEach }) => { | ||
@@ -88,0 +114,0 @@ const folder = join('logs', 'utils') |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40175
5
13
869
81
2
5
+ Addeddate-fns@^4.1.0
+ Addeddate-fns@4.1.0(transitive)