Logging
The way to output messages to your users
¶ Logger
Every time you want to log something in a plugin, you have to go through the logger. Every function of a plugin is passed a logger instance as a parameter. This instance has already all the information Parcel needs to identify your plugin as the origin of the message.
The logger uses a format we called diagnostics which is a JavaScript object with a standardized set of properties, a Reporter uses this information to log your message to its target format while having complete freedom as to how this data should be formatted and displayed.
There is a function for each type of log you can output, these functions are verbose(diagnostic)
, info(diagnostic)
, log(diagnostic)
, warn(diagnostic)
and error(diagnostic)
. These log levels are used for defining the severity of your log message, this is useful for formatting and filtering. For example, the end user can use the flag --log-level
to define which messages it wants to see. Each of these functions also have a single parameter called diagnostic, this parameter can either be a single diagnostic object or an array of diagnostics, depending on how many messages you want to log.
¶ Log levels
Level | When to use | function(s) |
---|---|---|
verbose | Use this when you want to log anything that can be used for debugging issues, while not being particularly interesting for normal usage | logger.verbose(...) |
info | Use this to log any information that is not related to a problem | logger.info(...) or logger.log(...) |
warning | Use this to log anything related to a problem that is not critical | logger.warning(...) |
error | Use this to log any critical issues, you probably want to throw a ThrowableDiagnostic instead | logger.error(...) or throw ThrowableDiagnostic(...) |
¶ Logger API
PluginLogger parcel/packages/core/logger/src/Logger.js:86
interface PluginLogger {
verbose(diagnostic: DiagnosticWithoutOrigin | Array<DiagnosticWithoutOrigin>): void,
info(diagnostic: DiagnosticWithoutOrigin | Array<DiagnosticWithoutOrigin>): void,
log(diagnostic: DiagnosticWithoutOrigin | Array<DiagnosticWithoutOrigin>): void,
warn(diagnostic: DiagnosticWithoutOrigin | Array<DiagnosticWithoutOrigin>): void,
error(input: Diagnostifiable | DiagnosticWithoutOrigin | Array<DiagnosticWithoutOrigin>): void,
}
Referenced by:
Bundler, DedicatedThreadValidator, MultiThreadValidator, Namer, Optimizer, Packager, Reporter, Resolver, Runtime, Transformer¶ Automatically collected logs and errors
Parcel core automatically collects any logs created by calling the global variable console
, this means whenever you do a console.log
we internally catch this and convert it to a Diagnostic object. This is not recommended as we do not have as much information as we do when calling the logger instance directly. We also do the same for errors, whenever you throw an error we convert it into a Diagnostic, append information about the plugin to it and send it to the logger.
¶ Diagnostics
A Diagnostic
is a JavaScript object with a set of properties that are required to create a useful log message, this can be anything from a verbose message to an error. This object can includes a message, information about the file, a codeframe, error information and hints on how to potentially resolve the issue.
¶ Formatting the messages
To format the messages in a diagnostic, we use a very minimal version of markdown specifically built to be compatible with terminals and anything else, while also not being too cryptic when displayed without any formatting. For our @parcel/reporter-cli
we use our own @parcel/markdown-ansi
library that converts these markdown strings to ANSI escape sequences.
The supported markdown features are **bold**
, *italic*
/_italic_
, __underlined__
and ~~strikethrough~~
.
¶ How to log a message
Once you're familiar with the Diagnostic format, you can log anything you want, from verbose messages to errors with codeframes and hints so your users don't have to search the web for hours to find a solution.
For errors you can also throw an error that has been augmented with diagnostic information, this is very useful for failing a build while also providing a useful error message, with a codeframe and suggestions. This is also the recommended way of throwing errors in Parcel.
An example for every method you can use:
import { Transformer } from "@parcel/plugin";
import ThrowableDiagnostic from "@parcel/diagnostic";
export default new Transformer({
// ...
async transform({ asset, ast, config, logger, resolve, options }) {
logger.verbose({
message: "Started transforming a dummy asset",
filePath: asset.filePath,
language: asset.type,
});
logger.info([
{
message: "This is an example message",
filePath: asset.filePath,
language: asset.type,
},
{
message: "This is another example message",
filePath: asset.filePath,
language: asset.type,
},
]);
logger.warn({
message: "This is an example message",
filePath: asset.filePath,
language: asset.type,
});
try {
loadDummyCompiler();
} catch (err) {
throw new ThrowableDiagnostic({
diagnostic: {
message: err.message,
filePath: asset.filePath,
language: asset.type,
stack: err.stack,
name: err.name,
codeFrame: {
code: await asset.getCode(),
codeHighlights: [
{
start: {
line: 1,
column: 5,
},
end: {
line: 2,
column: 3,
},
message: "This is an example message inside a **codeframe**",
},
],
},
hints: [
"Install __@dummy/compiler__ using *npm install @dummy/compiler*",
],
},
});
}
// ...
},
});
¶ API
DiagnosticHighlightLocation parcel/packages/core/diagnostic/src/diagnostic.js:10
These positions are 1-based (so 1
is the first line/column)
type DiagnosticHighlightLocation = {|
+line: number,
+column: number,
|}
Referenced by:
DiagnosticCodeHighlight, getJSONSourceLocationDiagnosticSeverity parcel/packages/core/diagnostic/src/diagnostic.js:15
Type
type DiagnosticSeverity = 'error' | 'warn' | 'info';
DiagnosticCodeHighlight parcel/packages/core/diagnostic/src/diagnostic.js:21
Note: A tab character is always counted as a single character This is to prevent any mismatch of highlighting across machines
type DiagnosticCodeHighlight = {|
start: DiagnosticHighlightLocation,
end: DiagnosticHighlightLocation,
message?: string,
|}
Referenced by:
DiagnosticCodeFrame, generateJSONCodeHighlightsDiagnosticCodeFrame parcel/packages/core/diagnostic/src/diagnostic.js:35
Describes how to format a code frame. A code frame is a visualization of a piece of code with a certain amount of code highlights that point to certain chunk(s) inside the code.
type DiagnosticCodeFrame = {|
code?: string,
If no code is passed, it will be read in from Diagnostic#filePath, remember that the asset's current code could be different from the input contents.
codeHighlights: Array<DiagnosticCodeHighlight>,
|}
Referenced by:
DiagnosticDiagnostic parcel/packages/core/diagnostic/src/diagnostic.js:51
A style agnostic way of emitting errors, warnings and info. Reporters are responsible for rendering the message, codeframes, hints, ...
type Diagnostic = {|
message: string,
origin?: string,
stack?: string,
name?: string,
filePath?: FilePath,
language?: string,
codeFrame?: DiagnosticCodeFrame,
hints?: Array<string>,
|}
Referenced by:
BuildFailureEvent, DiagnosticCodeFrame, DiagnosticLogEvent, DiagnosticWithoutOrigin, Diagnostifiable, ResolveResult, ThrowableDiagnostic, ThrowableDiagnosticOpts, ValidateResult, anyToDiagnostic, errorToDiagnosticPrintableError parcel/packages/core/diagnostic/src/diagnostic.js:78
Type
type PrintableError = Error & {
fileName?: string,
filePath?: string,
codeFrame?: string,
highlightedCodeFrame?: string,
loc?: ?{
column: number,
line: number,
...
},
source?: string,
...
};
Referenced by:
Diagnostifiable, errorToDiagnosticDiagnosticWithoutOrigin parcel/packages/core/diagnostic/src/diagnostic.js:92
type DiagnosticWithoutOrigin = {|
...Diagnostic,
origin?: string,
|}
Referenced by:
PluginLoggerDiagnostifiable parcel/packages/core/diagnostic/src/diagnostic.js:98
Something that can be turned into a diagnostic.
Type
type Diagnostifiable = Diagnostic | Array<Diagnostic> | ThrowableDiagnostic | PrintableError | string;
Referenced by:
PluginLogger, anyToDiagnosticanyToDiagnostic parcel/packages/core/diagnostic/src/diagnostic.js:106
Normalize the given value into a diagnostic.
Type
function anyToDiagnostic(input: Diagnostifiable): Array<Diagnostic> {}
errorToDiagnostic parcel/packages/core/diagnostic/src/diagnostic.js:120
Normalize the given error into a diagnostic.
Type
function errorToDiagnostic(error: ThrowableDiagnostic | PrintableError | string, realOrigin?: string): Array<Diagnostic> {}
ThrowableDiagnosticOpts parcel/packages/core/diagnostic/src/diagnostic.js:175
type ThrowableDiagnosticOpts = {
diagnostic: Diagnostic | Array<Diagnostic>,
}
Referenced by:
ThrowableDiagnosticThrowableDiagnostic parcel/packages/core/diagnostic/src/diagnostic.js:184
An error wrapper around a diagnostic that can be throw
n (e.g. to signal a
build error).
interface ThrowableDiagnostic extends Error {
diagnostics: Array<Diagnostic>,
constructor(opts: ThrowableDiagnosticOpts): void,
}
Referenced by:
Diagnostifiable, errorToDiagnosticgenerateJSONCodeHighlights parcel/packages/core/diagnostic/src/diagnostic.js:209
Turns a list of positions in a JSON file with messages into a list of diagnostics.
Uses epoberezkin/json-source-map.
Parameter Descriptions
code
: the JSON codeids
: A list of JSON keypaths (key: "/some/parent/child"
) with corresponding messages,type
signifies whether the key of the value in a JSON object should be highlighted.
Type
function generateJSONCodeHighlights(code: string, ids: Array<{|
key: string,
type?: ?'key' | 'value',
message?: string,
|}>): Array<DiagnosticCodeHighlight> {}
Referenced by:
encodeJSONKeyComponentgetJSONSourceLocation parcel/packages/core/diagnostic/src/diagnostic.js:228
Converts entries in epoberezkin/json-source-map's
result.pointers
array.
Type
function getJSONSourceLocation(pos: {|
value: {|
line: number,
column: number,
|},
valueEnd: {|
line: number,
column: number,
|},
...{||} | {|
key: {|
line: number,
column: number,
|},
keyEnd: {|
line: number,
column: number,
|},
|},
|}, type?: ?'key' | 'value'): {|
start: DiagnosticHighlightLocation,
end: DiagnosticHighlightLocation,
|} {}
encodeJSONKeyComponent parcel/packages/core/diagnostic/src/diagnostic.js:265
Sanitizes object keys before using them as key
in generateJSONCodeHighlights
Type
function encodeJSONKeyComponent(component: string): string {}