Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow file to be a function #60

Merged
merged 1 commit into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ You can specify any of [Sonic-Boom options](https://github.com/pinojs/sonic-boom
Number will be appened to this file name.
When the parent folder already contains numbered files, numbering will continue based on the highest number.
If this path does not exist, the logger with throw an error unless you set `mkdir` to `true`.
`file` may also be a function that returns a string.

* `size?`: the maximum size of a given log file.
Can be combined with frequency.
Expand Down
15 changes: 10 additions & 5 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,19 @@ function getNext (frequency) {
return getNextCustom(frequency)
}

function buildFileName (fileName, lastNumber = 1, extension) {
if (!fileName) {
function getFileName (fileVal) {
if (!fileVal) {
throw new Error('No file name provided')
}
return `${fileName}.${lastNumber}${extension ?? ''}`
return typeof fileVal === 'function' ? fileVal() : fileVal
}

async function detectLastNumber (fileName, time = null) {
function buildFileName (fileVal, lastNumber = 1, extension) {
return `${getFileName(fileVal)}.${lastNumber}${extension ?? ''}`
}

async function detectLastNumber (fileVal, time = null) {
const fileName = getFileName(fileVal)
try {
const numbers = await readFileTrailingNumbers(dirname(fileName), time)
return numbers.sort((a, b) => b - a)[0]
Expand Down Expand Up @@ -102,4 +107,4 @@ async function isMatchingTime (filePath, time) {
return birthtimeMs >= time
}

module.exports = { buildFileName, detectLastNumber, parseFrequency, getNext, parseSize }
module.exports = { buildFileName, detectLastNumber, parseFrequency, getNext, parseSize, getFileName }
11 changes: 9 additions & 2 deletions pino-roll.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
const SonicBoom = require('sonic-boom')
const { buildFileName, detectLastNumber, parseSize, parseFrequency, getNext } = require('./lib/utils')

/**
* A function that returns a string path to the base file name
*
* @typedef {function} LogFilePath
* @returns {string}
*/

/**
* @typedef {object} Options
*
* @property {string} file - Absolute or relative path to the log file.
* @property {string|LogFilePath} file - Absolute or relative path to the log file.
* Your application needs the write right on the parent folder.
* Number will be appened to this file name.
* Number will be appended to this file name.
* When the parent folder already contains numbered files, numbering will continue based on the highest number.
* If this path does not exist, the logger with throw an error unless you set `mkdir` to `true`.
*
Expand Down
12 changes: 11 additions & 1 deletion test/lib/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { writeFile, rm, stat } = require('fs/promises')
const { join } = require('path')
const { test } = require('tap')

const { buildFileName, detectLastNumber, getNext, parseFrequency, parseSize } = require('../../lib/utils')
const { buildFileName, detectLastNumber, getNext, parseFrequency, parseSize, getFileName } = require('../../lib/utils')
const { cleanAndCreateFolder, sleep } = require('../utils')

test('parseSize()', async ({ equal, throws }) => {
Expand Down Expand Up @@ -54,10 +54,18 @@ test('getNext()', async ({ same, throws }) => {
same(getNext(custom), Date.now() + custom, 'supports custom frequency and does not return start')
})

test('getFileName()', async ({ equal, throws }) => {
const strFunc = () => 'my-func'
throws(getFileName, 'throws on empty input')
equal(getFileName('my-file'), 'my-file', 'returns string when string given')
equal(getFileName(strFunc), 'my-func', 'invokes function when function given')
})

test('buildFileName()', async ({ equal, throws }) => {
const ext = '.json'
throws(buildFileName, 'throws on empty input')
equal(buildFileName('my-file'), 'my-file.1', 'appends 1 by default')
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')
})

Expand All @@ -67,11 +75,13 @@ test('detectLastNumber()', async ({ test, beforeEach }) => {

test('given existing files', async ({ equal }) => {
const fileName = join(folder, 'file.5')
const fileNameFunc = () => fileName
await writeFile(join(folder, 'file.1'), '')
await writeFile(join(folder, 'file.5'), '')
await writeFile(join(folder, 'file.10'), '')
await writeFile(join(folder, 'file.7'), '')
equal(await detectLastNumber(fileName), 10, 'detects highest existing number')
equal(await detectLastNumber(fileNameFunc), 10, 'detects highest existing number when given func')
})

test('given existing files and a time', async ({ equal }) => {
Expand Down
18 changes: 17 additions & 1 deletion test/pino-roll.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use strict'

const { once } = require('events')
const { stat, readFile, writeFile } = require('fs/promises')
const { stat, readFile, writeFile, readdir } = require('fs/promises')
const { join } = require('path')
const { test, beforeEach } = require('tap')
const { format } = require('date-fns')

const { buildStream, cleanAndCreateFolder, sleep } = require('./utils')

Expand Down Expand Up @@ -35,6 +36,21 @@ test('rotate file based on time', async ({ ok, notOk, rejects }) => {
rejects(stat(`${file}.4`), 'no other files created')
})

test('rotate file based on time and parse filename func', async ({ ok, notOk, rejects }) => {
const file = join(logFolder, 'log')
const fileFunc = () => `${file}-${format(new Date(), 'HH-mm-ss-SSS')}`
const stream = await buildStream({ frequency: 100, file: fileFunc })
stream.write('logged message #1\n')
stream.write('logged message #2\n')
await sleep(110)
stream.write('logged message #3\n')
stream.write('logged message #4\n')
await sleep(110)
stream.end()
const files = await readdir(logFolder)
ok(files.length === 3, 'created three files')
})

test('rotate file based on size', async ({ ok, rejects }) => {
const file = join(logFolder, 'log')
const size = 20
Expand Down
Loading