diff --git a/README.md b/README.md
index b8db80b..d8ce8a0 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
> Powerful, fast and expressive logging for TypeScript and JavaScript
-
+
![tslog pretty output](https://raw.githubusercontent.com/fullstack-build/tslog/master/docs/assets/tslog.png "tslog pretty output in browser and Node.js")
@@ -49,13 +49,13 @@ Donations help me allocate more time for my open source work.
## Install
-> ❗ **`tslog` is a native ES module.**
+> ❗ **`tslog` is a native ES module.**
```bash
npm install tslog
```
-In order to run a native ES module in Node.js, you have to do two things:
+In order to run a native ES module in Node.js, you have to do two things:
1) Set `"type": "module"` in `package.json`.
2) For now, start with `--experimental-specifier-resolution=node`
@@ -180,21 +180,21 @@ logger.fatal(new Error("I am a pretty Error with a stacktrace."));
## API documentation
-> **`tslog >= v4` is a major rewrite and introduces breaking changes.**
-> Please, follow this documentation when migrating.
+> **`tslog >= v4` is a major rewrite and introduces breaking changes.**
+> Please, follow this documentation when migrating.
### Lifecycle of a log message
-Every incoming log message runs through a number of steps before being displayed or handed over to a "transport". Every step can be overwritten and adjusted.
+Every incoming log message runs through a number of steps before being displayed or handed over to a "transport". Every step can be overwritten and adjusted.
![tslog pretty output](https://raw.githubusercontent.com/fullstack-build/tslog/master/docs/assets/tslog_lifesycle.png "tslog: life cycle of a log message")
- **log message** Log message comes in through the `BaseLogger.log()` method
- **mask** If masking is configured, log message gets recursively masked
-- **toLogObj** Log message gets transformed into a log object: A default typed log object can be passed to constructor as a second parameter and will be cloned and enriched with the incoming log parameters. Error properties will be handled accordingly. If there is only one log property, and it's an object, both objects (cloned default `logObj` as well as the log property object) will be merged. If there are more than one, they will be put into properties called "0", "1", ... and so on. Alternatively, log message properties can be put into a property with a name configured with the `argumentsArrayName` setting.
+- **toLogObj** Log message gets transformed into a log object: A default typed log object can be passed to constructor as a second parameter and will be cloned and enriched with the incoming log parameters. Error properties will be handled accordingly. If there is only one log property, and it's an object, both objects (cloned default `logObj` as well as the log property object) will be merged. If there are more than one, they will be put into properties called "0", "1", ... and so on. Alternatively, log message properties can be put into a property with a name configured with the `argumentsArrayName` setting.
- **addMetaToLogObj** Additional meta information, like the source code position of the log will be gathered and added to the `_meta` property or any other one configured with the setting `metaProperty`.
-- **format** In case of "pretty" configuration, a log object will be formatted based on the templates configured in settings. Meta will be formatted by the method `_prettyFormatLogObjMeta` and the actual log payload will be formatted by `prettyFormatLogObj`. Both steps can be overwritten with the settings `formatMeta` and `formatMeta`.
-- **transport** Last step is to "transport" a log message to every attached transport from the setting `attachedTransports`. Last step is the actual transport, either JSON (`transportJSON`), formatted (`transportFormatted`) or omitted, if its set to "hidden". Both default transports can also be overwritten by the corresponding setting.
+- **format** In case of "pretty" configuration, a log object will be formatted based on the templates configured in settings. Meta will be formatted by the method `_prettyFormatLogObjMeta` and the actual log payload will be formatted by `prettyFormatLogObj`. Both steps can be overwritten with the settings `formatMeta` and `formatMeta`.
+- **transport** Last step is to "transport" a log message to every attached transport from the setting `attachedTransports`. Last step is the actual transport, either JSON (`transportJSON`), formatted (`transportFormatted`) or omitted, if its set to "hidden". Both default transports can also be overwritten by the corresponding setting.
### Default log level
@@ -245,16 +245,16 @@ export class CustomLogger extends BaseLogger {
```
### Settings
-`tslog` is highly customizable and pretty much every aspect can be either configured or overwritten.
+`tslog` is highly customizable and pretty much every aspect can be either configured or overwritten.
A `settings` object is the first parameter passed to the `tslog` constructor:
-```typescript
+```typescript
const logger = new Logger({ /* SETTINGS */ }, defaultLogObject);
```
#### Type: pretty, json, hidden
-- `pretty` **Default setting** prints out a formatted structured "pretty" log entry.
+- `pretty` **Default setting** prints out a formatted structured "pretty" log entry.
- `json` prints out a `JSON` formatted log entry.
- `hidden` suppresses any output whatsoever and can be used with attached loggers for example.
@@ -275,16 +275,16 @@ const hiddenLogger = new Logger({type: "hidden"});
#### name
-Each logger has an optional name.
-You can find the name of the logger responsible for a log inside the `Meta`-object or printed in `pretty` mode.
-Names get also inherited to sub loggers and can be found inside the `Meta`-object `parentNames` as well as printed out with a separator (e.g. `:`) in `pretty` mode.
+Each logger has an optional name.
+You can find the name of the logger responsible for a log inside the `Meta`-object or printed in `pretty` mode.
+Names get also inherited to sub loggers and can be found inside the `Meta`-object `parentNames` as well as printed out with a separator (e.g. `:`) in `pretty` mode.
Simple name example:
```typescript
new Logger({ name: "myLogger" });
```
-Sub-loggers with an inherited name:
+Sub-loggers with an inherited name:
```typescript
const mainLogger = new Logger({ type: "pretty", name: "MainLogger" });
mainLogger.silly("foo bar");
@@ -296,11 +296,11 @@ const secondSubLogger = firstSubLogger.getSubLogger({ name: "SecondSubLogger" })
secondSubLogger.silly("foo bar 2");
```
-Output:
+Output:
```bash
-2022-11-17 10:45:47.705 SILLY [/examples/nodejs/index2.ts:51 MainLogger] foo bar
-2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:54 MainLogger:FirstSubLogger] foo bar 1
-2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:57 MainLogger:FirstSubLogger:SecondSubLogger] foo bar 2
+2022-11-17 10:45:47.705 SILLY [/examples/nodejs/index2.ts:51] MainLogger foo bar
+2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:54] MainLogger:FirstSubLogger foo bar 1
+2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:57] MainLogger:FirstSubLogger:SecondSubLogger foo bar 2
```
#### minLevel
@@ -318,7 +318,7 @@ suppressSilly.trace("Will be visible");
#### argumentsArrayName
-`tslog` < 4 wrote all parameters into an arguments array. In `tslog` >= 4 the main object becomes home for all log parameters, and they get merged with the default `logObj`.
+`tslog` < 4 wrote all parameters into an arguments array. In `tslog` >= 4 the main object becomes home for all log parameters, and they get merged with the default `logObj`.
If you still want to put them into a separated parameter, you can do so by defining the `argumentsArrayName`.
```typescript
@@ -344,7 +344,7 @@ Enables you to overwrite the looks of a formatted _"pretty"_ log message by prov
Following settings are available for styling:
- **Templates:**
- - `prettyLogTemplate`: template string for log messages. Possible placeholders:
+ - `prettyLogTemplate`: template string for log messages. Possible placeholders:
- `{{yyyy}}`: year
- `{{mm}}`: month
- `{{dd}}`: day
@@ -353,6 +353,7 @@ Following settings are available for styling:
- `{{ss}}`: seconds
- `{{ms}}`: milliseconds
- `{{dateIsoStr}}`: Shortcut for `{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}`
+ - `{{rawIsoStr}}`: Renders the date and time in ISO format (e.g.: YYYY-MM-DDTHH:mm:ss.SSSZ)
- `{{logLevelName}}`: name of the log level
- `{{name}}`: optional name of the current logger and his parents (e.g. "ParentLogger:ThisLogger")
- `{{fullFilePath}}`: a full path starting from `/` root
@@ -360,24 +361,25 @@ Following settings are available for styling:
- `prettyErrorTemplate`: template string for error message. Possible placeholders:
- `{{errorName}}`: name of the error
- `{{errorMessage}}`: error message
- - `{{errorStack}}`: Placeholder for all stack lines defined by `prettyErrorStackTemplate`
+ - `{{errorStack}}`: Placeholder for all stack lines defined by `prettyErrorStackTemplate`
- `prettyErrorStackTemplate`: template string for error stack trace lines. Possible placeholders:
- `{{fileName}}`: name of the file
- `{{filePathWithLine}}`: a full path below the project path with a line number
- `{{method}}`: _optional_ name of the invoking method
- `prettyErrorParentNamesSeparator`: separator to be used when joining names ot the parent logger, and the current one (default: `:`)
+ - `prettyErrorLoggerNameDelimiter`: if a logger name is set this delimiter will be added afterwards
- `prettyInspectOptions`: Available options
-
+
- **Styling:**
- `stylePrettyLogs`: defines whether logs should be styled and colorized
- `prettyLogStyles`: provides colors and styles for different placeholders and can also be dependent on the value (e.g. log level)
- Level 1: template placeholder (defines a style for a certain template placeholder, s. above, without brackets).
- - Level 2: Either a string with one style (e.g. `white`), or an array of styles (e.g. `["bold", "white"]`), or a nested object with key being a value.
+ - Level 2: Either a string with one style (e.g. `white`), or an array of styles (e.g. `["bold", "white"]`), or a nested object with key being a value.
- Level 3: Optional nested style based on placeholder values. Key is the value of the template placeholder and value is either a string of a style, or an array of styles (s. above), e.g. `{ SILLY: ["bold", "white"] }` which means: value "SILLY" should get a style of "bold" and "white". `*` means any value other than the defined.
- `prettyInspectOptions`: When a (potentially nested) object is printed out in Node.js, we use `util.formatWithOptions` under the hood. With `prettyInspectOptions` you can define the output. [Possible values](https://nodejs.org/api/util.html#utilinspectobject-showhidden-depth-colors)
#### Log meta information
-`tslog` collects meta information for every log, like runtime, code position etc. The meta information collected depends on the runtime (browser or Node.js) and is accessible through the `LogObj`.
+`tslog` collects meta information for every log, like runtime, code position etc. The meta information collected depends on the runtime (browser or Node.js) and is accessible through the `LogObj`.
You can define the property containing this meta information with `metaProperty`, which is "_meta" by default.
#### Pretty templates and styles (color settings)
@@ -389,6 +391,7 @@ const logger = new Logger({
prettyErrorTemplate: "\n{{errorName}} {{errorMessage}}\nerror stack:\n{{errorStack}}",
prettyErrorStackTemplate: " • {{fileName}}\t{{method}}\n\t{{filePathWithLine}}",
prettyErrorParentNamesSeparator: ":",
+ prettyErrorLoggerNameDelimiter: "\t",
stylePrettyLogs: true,
prettyLogStyles: {
logLevelName: {
@@ -403,7 +406,7 @@ const logger = new Logger({
},
dateIsoStr: "white",
filePathWithLine: "white",
- name: "white",
+ name: ["white", "bold"],
errorName: ["bold", "bgRedBright", "whiteBright"],
fileName: ["yellow"],
},
@@ -467,7 +470,7 @@ like sending messages to _Slack_ or _Telegram_ in case of an urgent error or for
##### Simple transport example
-Here is a very simple implementation used in our _jest_ tests.
+Here is a very simple implementation used in our _jest_ tests.
This example will suppress logs from being sent to `console` (`type: "hidden"`) and will instead collect them in an `array`.
```typescript
@@ -502,10 +505,10 @@ logger.warn("I am a warn log with a json object:", { foo: "bar" });
##### Storing logs in a file system with rotating files
-If you want to limit the file size of the stored logs, a good practice is to use file rotation, where old logs will be deleted automatically.
+If you want to limit the file size of the stored logs, a good practice is to use file rotation, where old logs will be deleted automatically.
There is a great library called `rotating-file-stream` solving this problem for us and even adding features like compression, file size limit etc.
-1. First you need to install this library:
+1. First you need to install this library:
```bash
npm i rotating-file-stream
```
@@ -533,7 +536,7 @@ logger.warn("I am a warn log with a json object:", { foo: "bar" });
```
-#### Overwriting default behavior
+#### Overwriting default behavior
One of the key advantages of `tslog` >= 4 is that you can overwrite pretty much every aspect of the log processing described in "Lifecycle of a log message".
@@ -567,7 +570,7 @@ For `pretty` logs:
// format LogObj attributes to a string and return it
},
transportFormatted: (logMetaMarkup: string, logArgs: unknown[], logErrors: string[], settings: unknown) => {
- // overwrite the default transport for formatted (e.g. pretty) log levels. e.g. replace console with StdOut, write to file etc.
+ // overwrite the default transport for formatted (e.g. pretty) log levels. e.g. replace console with StdOut, write to file etc.
},
},
});
@@ -590,7 +593,7 @@ As described in "Lifecycle of a log message", every lo
A default logObj can be passed to the `tslog` constructor and will be cloned and merged into the log message. This makes `tslog` >= 4 highly configurable and easy to integrate into any 3rd party service.
The entire `logObj` will be printed out in `JSON` mode and also returned by every log method.
-> **Tip:** All properties of the default `LogObj` containing function calls will be executed for every log message making use cases possible like `requestId` (s. below).
+> **Tip:** All properties of the default `LogObj` containing function calls will be executed for every log message making use cases possible like `requestId` (s. below).
```typescript
interface ILogObj {
@@ -602,7 +605,7 @@ const defaultLogObject: ILogObj = {
};
const logger = new Logger({ type: "json" }, defaultLogObject);
-const logMsg = logger.info("Test");
+const logMsg = logger.info("Test");
// logMsg: {
// '0': 'Test',
@@ -648,24 +651,24 @@ Some providers (e.g. `Heroku`) already set a `X-Request-ID` header, which we are
import Koa from "koa";
import { customAlphabet } from "nanoid";
import { Logger } from "tslog";
-
+
interface ILogObj {
requestId?: string | (() => string | undefined);
}
-
+
const asyncLocalStorage: AsyncLocalStorage<{ requestId: string }> = new AsyncLocalStorage();
-
+
const defaultLogObject: ILogObj = {
requestId: () => asyncLocalStorage.getStore()?.requestId,
};
-
+
const logger = new Logger({ type: "json" }, defaultLogObject);
export { logger };
-
+
logger.info("Test log without requestId");
-
+
const koaApp = new Koa();
-
+
/** START AsyncLocalStorage requestId middleware **/
koaApp.use(async (ctx: Koa.Context, next: Koa.Next) => {
// use x-request-id or fallback to a nanoid
@@ -676,21 +679,21 @@ Some providers (e.g. `Heroku`) already set a `X-Request-ID` header, which we are
});
});
/** END AsyncLocalStorage requestId middleware **/
-
+
// example middleware
koaApp.use(async (ctx: Koa.Context, next) => {
-
+
// log request
logger.silly({ originalUrl: ctx.originalUrl, status: ctx.response.status, message: ctx.response.message });
-
+
// also works with a sub logger
const subLogger = logger.getSubLogger();
subLogger.info("Log containing requestId"); // <-- will contain a requestId
-
+
return await next();
});
-
+
koaApp.listen(3000);
-
+
logger.info("Server running on port 3000");
```
diff --git a/docs/README.md b/docs/README.md
index b8db80b..d8ce8a0 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -11,7 +11,7 @@
> Powerful, fast and expressive logging for TypeScript and JavaScript
-
+
![tslog pretty output](https://raw.githubusercontent.com/fullstack-build/tslog/master/docs/assets/tslog.png "tslog pretty output in browser and Node.js")
@@ -49,13 +49,13 @@ Donations help me allocate more time for my open source work.
## Install
-> ❗ **`tslog` is a native ES module.**
+> ❗ **`tslog` is a native ES module.**
```bash
npm install tslog
```
-In order to run a native ES module in Node.js, you have to do two things:
+In order to run a native ES module in Node.js, you have to do two things:
1) Set `"type": "module"` in `package.json`.
2) For now, start with `--experimental-specifier-resolution=node`
@@ -180,21 +180,21 @@ logger.fatal(new Error("I am a pretty Error with a stacktrace."));
## API documentation
-> **`tslog >= v4` is a major rewrite and introduces breaking changes.**
-> Please, follow this documentation when migrating.
+> **`tslog >= v4` is a major rewrite and introduces breaking changes.**
+> Please, follow this documentation when migrating.
### Lifecycle of a log message
-Every incoming log message runs through a number of steps before being displayed or handed over to a "transport". Every step can be overwritten and adjusted.
+Every incoming log message runs through a number of steps before being displayed or handed over to a "transport". Every step can be overwritten and adjusted.
![tslog pretty output](https://raw.githubusercontent.com/fullstack-build/tslog/master/docs/assets/tslog_lifesycle.png "tslog: life cycle of a log message")
- **log message** Log message comes in through the `BaseLogger.log()` method
- **mask** If masking is configured, log message gets recursively masked
-- **toLogObj** Log message gets transformed into a log object: A default typed log object can be passed to constructor as a second parameter and will be cloned and enriched with the incoming log parameters. Error properties will be handled accordingly. If there is only one log property, and it's an object, both objects (cloned default `logObj` as well as the log property object) will be merged. If there are more than one, they will be put into properties called "0", "1", ... and so on. Alternatively, log message properties can be put into a property with a name configured with the `argumentsArrayName` setting.
+- **toLogObj** Log message gets transformed into a log object: A default typed log object can be passed to constructor as a second parameter and will be cloned and enriched with the incoming log parameters. Error properties will be handled accordingly. If there is only one log property, and it's an object, both objects (cloned default `logObj` as well as the log property object) will be merged. If there are more than one, they will be put into properties called "0", "1", ... and so on. Alternatively, log message properties can be put into a property with a name configured with the `argumentsArrayName` setting.
- **addMetaToLogObj** Additional meta information, like the source code position of the log will be gathered and added to the `_meta` property or any other one configured with the setting `metaProperty`.
-- **format** In case of "pretty" configuration, a log object will be formatted based on the templates configured in settings. Meta will be formatted by the method `_prettyFormatLogObjMeta` and the actual log payload will be formatted by `prettyFormatLogObj`. Both steps can be overwritten with the settings `formatMeta` and `formatMeta`.
-- **transport** Last step is to "transport" a log message to every attached transport from the setting `attachedTransports`. Last step is the actual transport, either JSON (`transportJSON`), formatted (`transportFormatted`) or omitted, if its set to "hidden". Both default transports can also be overwritten by the corresponding setting.
+- **format** In case of "pretty" configuration, a log object will be formatted based on the templates configured in settings. Meta will be formatted by the method `_prettyFormatLogObjMeta` and the actual log payload will be formatted by `prettyFormatLogObj`. Both steps can be overwritten with the settings `formatMeta` and `formatMeta`.
+- **transport** Last step is to "transport" a log message to every attached transport from the setting `attachedTransports`. Last step is the actual transport, either JSON (`transportJSON`), formatted (`transportFormatted`) or omitted, if its set to "hidden". Both default transports can also be overwritten by the corresponding setting.
### Default log level
@@ -245,16 +245,16 @@ export class CustomLogger extends BaseLogger {
```
### Settings
-`tslog` is highly customizable and pretty much every aspect can be either configured or overwritten.
+`tslog` is highly customizable and pretty much every aspect can be either configured or overwritten.
A `settings` object is the first parameter passed to the `tslog` constructor:
-```typescript
+```typescript
const logger = new Logger({ /* SETTINGS */ }, defaultLogObject);
```
#### Type: pretty, json, hidden
-- `pretty` **Default setting** prints out a formatted structured "pretty" log entry.
+- `pretty` **Default setting** prints out a formatted structured "pretty" log entry.
- `json` prints out a `JSON` formatted log entry.
- `hidden` suppresses any output whatsoever and can be used with attached loggers for example.
@@ -275,16 +275,16 @@ const hiddenLogger = new Logger({type: "hidden"});
#### name
-Each logger has an optional name.
-You can find the name of the logger responsible for a log inside the `Meta`-object or printed in `pretty` mode.
-Names get also inherited to sub loggers and can be found inside the `Meta`-object `parentNames` as well as printed out with a separator (e.g. `:`) in `pretty` mode.
+Each logger has an optional name.
+You can find the name of the logger responsible for a log inside the `Meta`-object or printed in `pretty` mode.
+Names get also inherited to sub loggers and can be found inside the `Meta`-object `parentNames` as well as printed out with a separator (e.g. `:`) in `pretty` mode.
Simple name example:
```typescript
new Logger({ name: "myLogger" });
```
-Sub-loggers with an inherited name:
+Sub-loggers with an inherited name:
```typescript
const mainLogger = new Logger({ type: "pretty", name: "MainLogger" });
mainLogger.silly("foo bar");
@@ -296,11 +296,11 @@ const secondSubLogger = firstSubLogger.getSubLogger({ name: "SecondSubLogger" })
secondSubLogger.silly("foo bar 2");
```
-Output:
+Output:
```bash
-2022-11-17 10:45:47.705 SILLY [/examples/nodejs/index2.ts:51 MainLogger] foo bar
-2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:54 MainLogger:FirstSubLogger] foo bar 1
-2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:57 MainLogger:FirstSubLogger:SecondSubLogger] foo bar 2
+2022-11-17 10:45:47.705 SILLY [/examples/nodejs/index2.ts:51] MainLogger foo bar
+2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:54] MainLogger:FirstSubLogger foo bar 1
+2022-11-17 10:45:47.706 SILLY [/examples/nodejs/index2.ts:57] MainLogger:FirstSubLogger:SecondSubLogger foo bar 2
```
#### minLevel
@@ -318,7 +318,7 @@ suppressSilly.trace("Will be visible");
#### argumentsArrayName
-`tslog` < 4 wrote all parameters into an arguments array. In `tslog` >= 4 the main object becomes home for all log parameters, and they get merged with the default `logObj`.
+`tslog` < 4 wrote all parameters into an arguments array. In `tslog` >= 4 the main object becomes home for all log parameters, and they get merged with the default `logObj`.
If you still want to put them into a separated parameter, you can do so by defining the `argumentsArrayName`.
```typescript
@@ -344,7 +344,7 @@ Enables you to overwrite the looks of a formatted _"pretty"_ log message by prov
Following settings are available for styling:
- **Templates:**
- - `prettyLogTemplate`: template string for log messages. Possible placeholders:
+ - `prettyLogTemplate`: template string for log messages. Possible placeholders:
- `{{yyyy}}`: year
- `{{mm}}`: month
- `{{dd}}`: day
@@ -353,6 +353,7 @@ Following settings are available for styling:
- `{{ss}}`: seconds
- `{{ms}}`: milliseconds
- `{{dateIsoStr}}`: Shortcut for `{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}`
+ - `{{rawIsoStr}}`: Renders the date and time in ISO format (e.g.: YYYY-MM-DDTHH:mm:ss.SSSZ)
- `{{logLevelName}}`: name of the log level
- `{{name}}`: optional name of the current logger and his parents (e.g. "ParentLogger:ThisLogger")
- `{{fullFilePath}}`: a full path starting from `/` root
@@ -360,24 +361,25 @@ Following settings are available for styling:
- `prettyErrorTemplate`: template string for error message. Possible placeholders:
- `{{errorName}}`: name of the error
- `{{errorMessage}}`: error message
- - `{{errorStack}}`: Placeholder for all stack lines defined by `prettyErrorStackTemplate`
+ - `{{errorStack}}`: Placeholder for all stack lines defined by `prettyErrorStackTemplate`
- `prettyErrorStackTemplate`: template string for error stack trace lines. Possible placeholders:
- `{{fileName}}`: name of the file
- `{{filePathWithLine}}`: a full path below the project path with a line number
- `{{method}}`: _optional_ name of the invoking method
- `prettyErrorParentNamesSeparator`: separator to be used when joining names ot the parent logger, and the current one (default: `:`)
+ - `prettyErrorLoggerNameDelimiter`: if a logger name is set this delimiter will be added afterwards
- `prettyInspectOptions`: Available options
-
+
- **Styling:**
- `stylePrettyLogs`: defines whether logs should be styled and colorized
- `prettyLogStyles`: provides colors and styles for different placeholders and can also be dependent on the value (e.g. log level)
- Level 1: template placeholder (defines a style for a certain template placeholder, s. above, without brackets).
- - Level 2: Either a string with one style (e.g. `white`), or an array of styles (e.g. `["bold", "white"]`), or a nested object with key being a value.
+ - Level 2: Either a string with one style (e.g. `white`), or an array of styles (e.g. `["bold", "white"]`), or a nested object with key being a value.
- Level 3: Optional nested style based on placeholder values. Key is the value of the template placeholder and value is either a string of a style, or an array of styles (s. above), e.g. `{ SILLY: ["bold", "white"] }` which means: value "SILLY" should get a style of "bold" and "white". `*` means any value other than the defined.
- `prettyInspectOptions`: When a (potentially nested) object is printed out in Node.js, we use `util.formatWithOptions` under the hood. With `prettyInspectOptions` you can define the output. [Possible values](https://nodejs.org/api/util.html#utilinspectobject-showhidden-depth-colors)
#### Log meta information
-`tslog` collects meta information for every log, like runtime, code position etc. The meta information collected depends on the runtime (browser or Node.js) and is accessible through the `LogObj`.
+`tslog` collects meta information for every log, like runtime, code position etc. The meta information collected depends on the runtime (browser or Node.js) and is accessible through the `LogObj`.
You can define the property containing this meta information with `metaProperty`, which is "_meta" by default.
#### Pretty templates and styles (color settings)
@@ -389,6 +391,7 @@ const logger = new Logger({
prettyErrorTemplate: "\n{{errorName}} {{errorMessage}}\nerror stack:\n{{errorStack}}",
prettyErrorStackTemplate: " • {{fileName}}\t{{method}}\n\t{{filePathWithLine}}",
prettyErrorParentNamesSeparator: ":",
+ prettyErrorLoggerNameDelimiter: "\t",
stylePrettyLogs: true,
prettyLogStyles: {
logLevelName: {
@@ -403,7 +406,7 @@ const logger = new Logger({
},
dateIsoStr: "white",
filePathWithLine: "white",
- name: "white",
+ name: ["white", "bold"],
errorName: ["bold", "bgRedBright", "whiteBright"],
fileName: ["yellow"],
},
@@ -467,7 +470,7 @@ like sending messages to _Slack_ or _Telegram_ in case of an urgent error or for
##### Simple transport example
-Here is a very simple implementation used in our _jest_ tests.
+Here is a very simple implementation used in our _jest_ tests.
This example will suppress logs from being sent to `console` (`type: "hidden"`) and will instead collect them in an `array`.
```typescript
@@ -502,10 +505,10 @@ logger.warn("I am a warn log with a json object:", { foo: "bar" });
##### Storing logs in a file system with rotating files
-If you want to limit the file size of the stored logs, a good practice is to use file rotation, where old logs will be deleted automatically.
+If you want to limit the file size of the stored logs, a good practice is to use file rotation, where old logs will be deleted automatically.
There is a great library called `rotating-file-stream` solving this problem for us and even adding features like compression, file size limit etc.
-1. First you need to install this library:
+1. First you need to install this library:
```bash
npm i rotating-file-stream
```
@@ -533,7 +536,7 @@ logger.warn("I am a warn log with a json object:", { foo: "bar" });
```
-#### Overwriting default behavior
+#### Overwriting default behavior
One of the key advantages of `tslog` >= 4 is that you can overwrite pretty much every aspect of the log processing described in "Lifecycle of a log message".
@@ -567,7 +570,7 @@ For `pretty` logs:
// format LogObj attributes to a string and return it
},
transportFormatted: (logMetaMarkup: string, logArgs: unknown[], logErrors: string[], settings: unknown) => {
- // overwrite the default transport for formatted (e.g. pretty) log levels. e.g. replace console with StdOut, write to file etc.
+ // overwrite the default transport for formatted (e.g. pretty) log levels. e.g. replace console with StdOut, write to file etc.
},
},
});
@@ -590,7 +593,7 @@ As described in "Lifecycle of a log message", every lo
A default logObj can be passed to the `tslog` constructor and will be cloned and merged into the log message. This makes `tslog` >= 4 highly configurable and easy to integrate into any 3rd party service.
The entire `logObj` will be printed out in `JSON` mode and also returned by every log method.
-> **Tip:** All properties of the default `LogObj` containing function calls will be executed for every log message making use cases possible like `requestId` (s. below).
+> **Tip:** All properties of the default `LogObj` containing function calls will be executed for every log message making use cases possible like `requestId` (s. below).
```typescript
interface ILogObj {
@@ -602,7 +605,7 @@ const defaultLogObject: ILogObj = {
};
const logger = new Logger({ type: "json" }, defaultLogObject);
-const logMsg = logger.info("Test");
+const logMsg = logger.info("Test");
// logMsg: {
// '0': 'Test',
@@ -648,24 +651,24 @@ Some providers (e.g. `Heroku`) already set a `X-Request-ID` header, which we are
import Koa from "koa";
import { customAlphabet } from "nanoid";
import { Logger } from "tslog";
-
+
interface ILogObj {
requestId?: string | (() => string | undefined);
}
-
+
const asyncLocalStorage: AsyncLocalStorage<{ requestId: string }> = new AsyncLocalStorage();
-
+
const defaultLogObject: ILogObj = {
requestId: () => asyncLocalStorage.getStore()?.requestId,
};
-
+
const logger = new Logger({ type: "json" }, defaultLogObject);
export { logger };
-
+
logger.info("Test log without requestId");
-
+
const koaApp = new Koa();
-
+
/** START AsyncLocalStorage requestId middleware **/
koaApp.use(async (ctx: Koa.Context, next: Koa.Next) => {
// use x-request-id or fallback to a nanoid
@@ -676,21 +679,21 @@ Some providers (e.g. `Heroku`) already set a `X-Request-ID` header, which we are
});
});
/** END AsyncLocalStorage requestId middleware **/
-
+
// example middleware
koaApp.use(async (ctx: Koa.Context, next) => {
-
+
// log request
logger.silly({ originalUrl: ctx.originalUrl, status: ctx.response.status, message: ctx.response.message });
-
+
// also works with a sub logger
const subLogger = logger.getSubLogger();
subLogger.info("Log containing requestId"); // <-- will contain a requestId
-
+
return await next();
});
-
+
koaApp.listen(3000);
-
+
logger.info("Server running on port 3000");
```
diff --git a/src/BaseLogger.ts b/src/BaseLogger.ts
index a946c3b..9890711 100644
--- a/src/BaseLogger.ts
+++ b/src/BaseLogger.ts
@@ -24,10 +24,11 @@ export class BaseLogger {
minLevel: settings?.minLevel ?? 0,
argumentsArrayName: settings?.argumentsArrayName,
prettyLogTemplate:
- settings?.prettyLogTemplate ?? "{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}\t{{logLevelName}}\t[{{filePathWithLine}}{{name}}]\t",
+ settings?.prettyLogTemplate ?? "{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}\t{{logLevelName}}\t[{{filePathWithLine}}]\t{{name}}",
prettyErrorTemplate: settings?.prettyErrorTemplate ?? "\n{{errorName}} {{errorMessage}}\nerror stack:\n{{errorStack}}",
prettyErrorStackTemplate: settings?.prettyErrorTemplate ?? " • {{fileName}}\t{{method}}\n\t{{filePathWithLine}}",
prettyErrorParentNamesSeparator: settings?.prettyErrorParentNamesSeparator ?? ":",
+ prettyErrorLoggerNameDelimiter: settings?.prettyErrorLoggerNameDelimiter ?? "\t",
stylePrettyLogs: settings?.stylePrettyLogs ?? true,
prettyLogStyles: settings?.prettyLogStyles ?? {
logLevelName: {
@@ -42,7 +43,7 @@ export class BaseLogger {
},
dateIsoStr: "white",
filePathWithLine: "white",
- name: "white",
+ name: ["white", "bold"],
errorName: ["bold", "bgRedBright", "whiteBright"],
fileName: ["yellow"],
},
@@ -272,7 +273,6 @@ export class BaseLogger {
// date and time performance fix
if (template.includes("{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}")) {
template = template.replace("{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}", "{{dateIsoStr}}");
- placeholderValues["dateIsoStr"] = logObjMeta?.date?.toISOString().replace("T", " ").replace("Z", "");
} else {
placeholderValues["yyyy"] = logObjMeta?.date?.getFullYear() ?? "----";
placeholderValues["mm"] = formatNumberAddZeros(logObjMeta?.date?.getMonth(), 2, 1);
@@ -282,13 +282,16 @@ export class BaseLogger {
placeholderValues["ss"] = formatNumberAddZeros(logObjMeta?.date?.getSeconds(), 2);
placeholderValues["ms"] = formatNumberAddZeros(logObjMeta?.date?.getMilliseconds(), 3);
}
+ placeholderValues["rawIsoStr"] = logObjMeta?.date?.toISOString();
+ placeholderValues["dateIsoStr"] = logObjMeta?.date?.toISOString().replace("T", " ").replace("Z", "");
placeholderValues["logLevelName"] = logObjMeta?.logLevelName;
placeholderValues["filePathWithLine"] = logObjMeta?.path?.filePathWithLine;
placeholderValues["fullFilePath"] = logObjMeta?.path?.fullFilePath;
// name
let parentNamesString = this.settings.parentNames?.join(this.settings.prettyErrorParentNamesSeparator);
parentNamesString = parentNamesString != null && logObjMeta?.name != null ? parentNamesString + this.settings.prettyErrorParentNamesSeparator : undefined;
- placeholderValues["name"] = logObjMeta?.name != null || parentNamesString != null ? " " + (parentNamesString ?? "") + logObjMeta?.name ?? "" : "";
+ const nameStr = logObjMeta?.name != null || parentNamesString != null ? (parentNamesString ?? "") + logObjMeta?.name ?? "" : "";
+ placeholderValues["name"] = nameStr.length > 0 ? nameStr + this.settings.prettyErrorLoggerNameDelimiter : "";
return formatTemplate(this.settings, template, placeholderValues);
}
diff --git a/src/interfaces.ts b/src/interfaces.ts
index ccac097..1141ebe 100644
--- a/src/interfaces.ts
+++ b/src/interfaces.ts
@@ -18,6 +18,7 @@ export interface ISettingsParam {
prettyErrorTemplate?: string;
prettyErrorStackTemplate?: string;
prettyErrorParentNamesSeparator?: string;
+ prettyErrorLoggerNameDelimiter?: string;
stylePrettyLogs?: boolean;
prettyLogStyles?: {
yyyy?: TStyle;
@@ -64,6 +65,7 @@ export interface ISettings extends ISettingsParam {
prettyErrorTemplate: string;
prettyErrorStackTemplate: string;
prettyErrorParentNamesSeparator: string;
+ prettyErrorLoggerNameDelimiter: string;
stylePrettyLogs: boolean;
prettyLogStyles: {
yyyy?: TStyle;
diff --git a/tests/Nodejs/7_pretty_Settings.test.ts b/tests/Nodejs/7_pretty_Settings.test.ts
index 848bbab..d27c9b9 100644
--- a/tests/Nodejs/7_pretty_Settings.test.ts
+++ b/tests/Nodejs/7_pretty_Settings.test.ts
@@ -203,4 +203,27 @@ describe("Pretty: Settings", () => {
const MM = dateMinutes == null ? "--" : dateMinutes < 10 ? "0" + dateMinutes : dateMinutes;
expect(getConsoleLog()).toContain(`**${dd}.${mm}.${yyyy} ${hh}:${MM}** Test`);
});
+
+
+ test("stylePrettyLogs: false / prettyLogTemplate - shortcut: {{dateIsoStr}}", (): void => {
+ const logger = new Logger({
+ type: "pretty",
+ prettyLogTemplate: "**{{dateIsoStr}}**",
+ stylePrettyLogs: false,
+ });
+ logger.log(1234, "testLevel", "Test");
+ expect(getConsoleLog()).toContain(`**${new Date().toISOString().replace("T", " ").replace("Z", "").split(".")[0]}`);
+ expect(getConsoleLog()).toContain("** Test");
+ });
+
+ test("prettyLogTemplate - rawIsoStr", (): void => {
+ const logger = new Logger({
+ type: "pretty",
+ prettyLogTemplate: "**{{rawIsoStr}}**",
+ stylePrettyLogs: false,
+ });
+ logger.log(1234, "testLevel", "Test");
+ expect(getConsoleLog()).toContain(`**${new Date().toISOString().split(".")[0]}`);
+ expect(getConsoleLog()).toContain("** Test");
+ });
});