-
-
Notifications
You must be signed in to change notification settings - Fork 8.1k
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
refactor: unify log format with new logger utility #5994
Changes from 24 commits
c1bad8d
4660e46
bc6645c
fe952e4
77784f3
b111968
f0c50ee
2139b66
cfe7700
9ff817d
dd8f609
2508609
1309520
feaa03e
f18d012
c25b60e
46e6c9d
7b1cc11
9e2812c
bb9bebc
a0113a5
c52228b
446aa2c
a7a99fc
e757074
8322a3d
fc4b0ea
0a706c0
577713c
689a5cd
5e54822
496245f
b484675
326962a
55aded0
47e25e7
ac3f1af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# `@docusaurus/logger` | ||
|
||
An encapsulated logger for semantically formatting console messages. | ||
|
||
## APIs | ||
|
||
It exports a single object as default export: `logger`. `logger` has the following properties: | ||
|
||
- All fields of `picocolors`. This includes `yellow`, `createColors`, `isColorSupported`, etc. | ||
- Formatters. These functions have the same signature as the formatters of `picocolors`. Note that their implementations are not guaranteed. You should only care about their semantics. | ||
- `path`: formats a file path or URL. | ||
- `id`: formats an identifier. | ||
- `code`: formats a code snippet. | ||
- `subdue`: subdues the text. | ||
- `num`: formats a number. | ||
- The `interpolate` function. It is a template literal tag. | ||
- Logging functions. All logging functions can both be used as functions (in which it has the same usage as `console.log`) or template literal tags. | ||
- `info`: prints information. | ||
- `warn`: prints a warning that should be payed attention to. | ||
- `error`: prints an error (not necessarily halting the program) that signals significant problems. | ||
- `success`: prints a success message. | ||
|
||
### Using the template literal tag | ||
|
||
The template literal tag evaluates the template and expressions embedded. `interpolate` returns a new string, while other logging functions prints it. Below is a typical usage: | ||
|
||
```js | ||
logger.info`Hello %i${name}! You have %n${money} dollars. Here are the ${ | ||
items.length > 1 ? 'items' : 'item' | ||
} on the shelf: ${items} | ||
To buy anything, enter %c${'buy x'} where %c${'x'} is the item's name; to quit, press %c${'Ctrl + C'}.`; | ||
``` | ||
|
||
An embedded expression is optionally preceded by a flag in the form `%[a-z]+` (a percentage sign followed by a few lowercase letters). If it's not preceded by any flag, it's printed out as-is. Otherwise, it's formatted with one of the formatters: | ||
|
||
- `%p`: `path` | ||
- `%i`: `id` | ||
- `%c`: `code` | ||
- `%s`: `subdue` | ||
- `%n`: `num` | ||
|
||
If the expression is an array, it's formatted by `` `\n- ${array.join('\n- ')}\n` `` (note it automatically gets a leading line end). Each member is formatted by itself and the bullet is not formatted. So you would see the above message printed as: | ||
|
||
![demo](./demo.png) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"name": "@docusaurus/logger", | ||
"version": "2.0.0-beta.9", | ||
"description": "An encapsulated logger for semantically formatting console messages.", | ||
"main": "./lib/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/facebook/docusaurus.git", | ||
"directory": "packages/docusaurus-logger" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/facebook/docusaurus/issues" | ||
}, | ||
"scripts": { | ||
"build": "tsc", | ||
"watch": "tsc --watch" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"license": "MIT", | ||
"dependencies": { | ||
"picocolors": "^1.0.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather keep chalk really, changing this dependency that works has little value (unless you can measure a significant the perf impact?) and only introduce useless risk There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i do agree with you, changing packages when current one is maintained its bad choice chalk is not even removed from dependencies, as its used by underlying libs anyway as for micro benchmarks, adding this interpolation is slower than adding 500 colors to message manually There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's rather about neither performance or bundle size, because as we realized, we neither get rid of Chalk nor save much perf with the template interpolation. But just as I said, picocolors is shinier because: (a) it doesn't pollute the prototype chain (I have such an aversion to Chalk's I'm fine with going back to Chalk. But as we are making a new package anyways, why don't we also choose a new lib that many big OSSes are already adopting? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the goal of this PR is not to change behavior and implementation, it's just to refactor to another logging architecture with less coupling leaking inside our codebase. Please let's focus on what we decided to do: provide a logging abstraction that encapsulate the needs we have.
the goal is 100% do actually not do that, that's the motivation behind this abstraction: not making the underlying leak into our codebase 😅
That can be decided in a separate PR later, but be ready to have a lot of pushback from my side In the meantime I prefer that we separate architecture/refactor changes from implementation details changes, and have many smaller PRs easier to review and agree on, compared to a larger PR that we disagree on many details |
||
}, | ||
"engines": { | ||
"node": ">=14" | ||
}, | ||
"devDependencies": { | ||
"@types/supports-color": "^8.1.1" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import logger from '../index'; | ||
|
||
describe('formatters', () => { | ||
test('path', () => { | ||
expect(logger.path('hey')).toMatchInlineSnapshot(`"[36m[4mhey[24m[39m"`); | ||
}); | ||
test('id', () => { | ||
expect(logger.id('hey')).toMatchInlineSnapshot(`"[34m[1mhey[22m[39m"`); | ||
}); | ||
test('code', () => { | ||
expect(logger.code('hey')).toMatchInlineSnapshot(`"[36m\`hey\`[39m"`); | ||
}); | ||
test('subdue', () => { | ||
expect(logger.subdue('hey')).toMatchInlineSnapshot(`"[90mhey[39m"`); | ||
}); | ||
}); | ||
|
||
describe('interpolate', () => { | ||
test('should format text with variables & arrays', () => { | ||
const name = 'Josh'; | ||
const items = [1, 'hi', 'Hmmm']; | ||
expect(logger.interpolate`Hello ${name}! Here are your goodies:${items}`) | ||
.toMatchInlineSnapshot(` | ||
"Hello Josh! Here are your goodies: | ||
- 1 | ||
- hi | ||
- Hmmm" | ||
`); | ||
}); | ||
test('should recognize valid flags', () => { | ||
expect( | ||
logger.interpolate`The package at %p${'packages/docusaurus'} has %n${10} files. %i${'Babel'} is exported here %s${'(as a preset)'} that you can with %c${"require.resolve('@docusaurus/core/lib/babel/preset')"}`, | ||
).toMatchInlineSnapshot( | ||
`"The package at [36m[4mpackages/docusaurus[24m[39m has [33m10[39m files. [34m[1mBabel[22m[39m is exported here [90m(as a preset)[39m that you can with [36m\`require.resolve('@docusaurus/core/lib/babel/preset')\`[39m"`, | ||
); | ||
}); | ||
test('should interpolate arrays with flags', () => { | ||
expect( | ||
logger.interpolate`The following commands are available:%c${[ | ||
'docusaurus start', | ||
'docusaurus build', | ||
'docusaurus deploy', | ||
]}`, | ||
).toMatchInlineSnapshot(` | ||
"The following commands are available: | ||
- [36m\`docusaurus start\`[39m | ||
- [36m\`docusaurus build\`[39m | ||
- [36m\`docusaurus deploy\`[39m" | ||
`); | ||
}); | ||
test('should print detached flags as-is', () => { | ||
expect( | ||
logger.interpolate`You can use placeholders like %c ${'and it will'} be replaced with the succeeding arguments`, | ||
).toMatchInlineSnapshot( | ||
`"You can use placeholders like %c and it will be replaced with the succeeding arguments"`, | ||
); | ||
}); | ||
test('should throw with bad flags', () => { | ||
expect( | ||
() => | ||
logger.interpolate`I mistyped this: %a${'this code'} and I will be damned`, | ||
).toThrowErrorMatchingInlineSnapshot( | ||
`"Bad Docusaurus logging message. This is likely an internal bug, please report it."`, | ||
); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
even if it works, I don't really see the value of introducing a fancy logging syntax using template literals
never seen this anywhere before