-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updated default logger. Docs (from new readme): - Arrays will be logged line be line - For each line logged: - string, numbers and booleans are logged directly - objects are logged with `JSON.stringify(___, null, 2)` So if the procedure returns `['one', 'two', 'three]` this will be written to stdout: ``` one two three ``` If the procedure returns `[{name: 'one'}, {name: 'two'}, {name: 'three'}]` this will be written to stdout: ``` { "name": "one" } { "name": "two" } { "name": "three" } ``` This is to make it as easy as possible to use with other command line tools like `xargs`, `jq` etc. via bash-piping. If you don't want to rely on this logging, you can always log inside your procedures however you like and avoid returning a value. --------- Co-authored-by: Misha Kaletsky <[email protected]>
- Loading branch information
Showing
6 changed files
with
253 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import {Log, Logger} from './types' | ||
|
||
export const lineByLineLogger = getLoggerTransformer(log => { | ||
/** | ||
* @param args values to log. if `logger.info('a', 1)` is called, `args` will be `['a', 1]` | ||
* @param depth tracks whether the current call recursive. Used to make sure we don't flatten nested arrays | ||
*/ | ||
const wrapper = (args: unknown[], depth: number) => { | ||
if (args.length === 1 && Array.isArray(args[0]) && depth === 0) { | ||
args[0].forEach(item => wrapper([item], 1)) | ||
} else if (args.every(isPrimitive)) { | ||
log(...args) | ||
} else if (args.length === 1) { | ||
log(JSON.stringify(args[0], null, 2)) | ||
} else { | ||
log(JSON.stringify(args, null, 2)) | ||
} | ||
} | ||
|
||
return (...args) => wrapper(args, 0) | ||
}) | ||
|
||
const isPrimitive = (value: unknown): value is string | number | boolean => { | ||
const type = typeof value | ||
return type === 'string' || type === 'number' || type === 'boolean' | ||
} | ||
|
||
/** Takes a function that wraps an individual log function, and returns a function that wraps the `info` and `error` functions for a logger */ | ||
function getLoggerTransformer(transform: (log: Log) => Log) { | ||
return (logger: Logger): Logger => { | ||
const info = logger.info && transform(logger.info) | ||
const error = logger.error && transform(logger.error) | ||
return {info, error} | ||
} | ||
} | ||
|
||
/** | ||
* A logger which uses `console.log` and `console.error` to log in the following way: | ||
* - Primitives are logged directly | ||
* - Arrays are logged item-by-item | ||
* - Objects are logged as JSON | ||
* | ||
* This is useful for logging structured data in a human-readable way, and for piping logs to other tools. | ||
*/ | ||
export const lineByLineConsoleLogger = lineByLineLogger(console) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import {beforeEach, expect, test, vi} from 'vitest' | ||
import {lineByLineLogger} from '../src/logging' | ||
|
||
const info = vi.fn() | ||
const error = vi.fn() | ||
const mocks = {info, error} | ||
const jsonish = lineByLineLogger(mocks) | ||
|
||
beforeEach(() => { | ||
vi.clearAllMocks() | ||
}) | ||
|
||
expect.addSnapshotSerializer({ | ||
test: val => val.mock.calls, | ||
print: (val: any) => val.mock.calls.map((call: unknown[]) => call.join(' ')).join('\n'), | ||
}) | ||
|
||
test('logging', async () => { | ||
jsonish.info!('Hello', 'world') | ||
|
||
expect(info).toMatchInlineSnapshot(`Hello world`) | ||
}) | ||
|
||
test('string array', async () => { | ||
jsonish.info!(['m1', 'm2', 'm3']) | ||
|
||
expect(info).toMatchInlineSnapshot(` | ||
m1 | ||
m2 | ||
m3 | ||
`) | ||
}) | ||
|
||
test('primitives array', async () => { | ||
jsonish.info!(['m1', 'm2', 11, true, 'm3']) | ||
|
||
expect(info).toMatchInlineSnapshot(` | ||
m1 | ||
m2 | ||
11 | ||
true | ||
m3 | ||
`) | ||
}) | ||
|
||
test('array array', async () => { | ||
jsonish.info!([ | ||
['m1', 'm2'], | ||
['m3', 'm4'], | ||
]) | ||
|
||
expect(info).toMatchInlineSnapshot(` | ||
[ | ||
"m1", | ||
"m2" | ||
] | ||
[ | ||
"m3", | ||
"m4" | ||
] | ||
`) | ||
}) | ||
|
||
test('multi primitives', async () => { | ||
jsonish.info!('m1', 11, true, 'm2') | ||
jsonish.info!('m1', 12, false, 'm2') | ||
|
||
expect(info).toMatchInlineSnapshot(` | ||
m1 11 true m2 | ||
m1 12 false m2 | ||
`) | ||
}) | ||
|
||
test('object array', async () => { | ||
jsonish.info!([{name: 'm1'}, {name: 'm2'}, {name: 'm3'}]) | ||
|
||
expect(info).toMatchInlineSnapshot(` | ||
{ | ||
"name": "m1" | ||
} | ||
{ | ||
"name": "m2" | ||
} | ||
{ | ||
"name": "m3" | ||
} | ||
`) | ||
}) |