{"id":13455732,"url":"https://github.com/fullstack-build/tslog","last_synced_at":"2026-02-18T05:03:00.920Z","repository":{"id":38341921,"uuid":"258150059","full_name":"fullstack-build/tslog","owner":"fullstack-build","description":"📝 tslog - Universal Logger for TypeScript and JavaScript","archived":false,"fork":false,"pushed_at":"2026-02-06T13:36:19.000Z","size":5890,"stargazers_count":1608,"open_issues_count":76,"forks_count":74,"subscribers_count":7,"default_branch":"master","last_synced_at":"2026-02-16T01:27:46.355Z","etag":null,"topics":["error-handling","exceptions","json","json-api","logger","logging","logging-library","pretty-print","stack","stacktrace","typescript-library"],"latest_commit_sha":null,"homepage":"https://tslog.js.org","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fullstack-build.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"fullstack-build"}},"created_at":"2020-04-23T09:08:24.000Z","updated_at":"2026-02-15T18:18:32.000Z","dependencies_parsed_at":"2023-10-11T21:01:25.438Z","dependency_job_id":"2e1570fe-d017-4fd6-92bf-bc11cf4e4948","html_url":"https://github.com/fullstack-build/tslog","commit_stats":{"total_commits":593,"total_committers":23,"mean_commits":"25.782608695652176","dds":"0.11635750421585156","last_synced_commit":"84830fd7d81d3a66ea6cad486e5c426a42fc504a"},"previous_names":[],"tags_count":104,"template":false,"template_full_name":null,"purl":"pkg:github/fullstack-build/tslog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstack-build%2Ftslog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstack-build%2Ftslog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstack-build%2Ftslog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstack-build%2Ftslog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fullstack-build","download_url":"https://codeload.github.com/fullstack-build/tslog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstack-build%2Ftslog/sbom","scorecard":{"id":413578,"data":{"date":"2025-08-11","repo":{"name":"github.com/fullstack-build/tslog","commit":"9a5d15696ae813142b64a21f42987e59e7115448"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":4,"reason":"Found 3/7 approved changesets -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":4,"reason":"dependency not pinned by hash detected -- score normalized to 4","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/fullstack-build/tslog/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/fullstack-build/tslog/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/fullstack-build/tslog/ci.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 27 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"41 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx","Warn: Project is vulnerable to: GHSA-593f-38f6-jp5m","Warn: Project is vulnerable to: GHSA-x2rg-q646-7m2v","Warn: Project is vulnerable to: GHSA-jgmv-j7ww-jx2x","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-8266-84wp-wv5c","Warn: Project is vulnerable to: GHSA-64vr-g452-qvp3","Warn: Project is vulnerable to: GHSA-9cwx-2883-4wfx","Warn: Project is vulnerable to: GHSA-vg6x-rcgg-rjx6","Warn: Project is vulnerable to: GHSA-x574-m823-4x7w","Warn: Project is vulnerable to: GHSA-4r4m-qw57-chr8","Warn: Project is vulnerable to: GHSA-xcj6-pq6g-qj4x","Warn: Project is vulnerable to: GHSA-356w-63v5-8wf4","Warn: Project is vulnerable to: GHSA-859w-5945-r5v3","Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-8hc4-vh64-cxmj","Warn: Project is vulnerable to: GHSA-jr5f-v2jv-69x6","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-4r62-v4vq-hr96","Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj","Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf","Warn: Project is vulnerable to: GHSA-x7hr-w5r2-h6wg","Warn: Project is vulnerable to: GHSA-pq67-2wwv-3xjx","Warn: Project is vulnerable to: GHSA-8cj5-5rvv-wf4v","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T23:16:11.612Z","repository_id":38341921,"created_at":"2025-08-18T23:16:11.612Z","updated_at":"2025-08-18T23:16:11.612Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29569853,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T04:18:28.490Z","status":"ssl_error","status_checked_at":"2026-02-18T04:13:49.018Z","response_time":162,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["error-handling","exceptions","json","json-api","logger","logging","logging-library","pretty-print","stack","stacktrace","typescript-library"],"created_at":"2024-07-31T08:01:10.130Z","updated_at":"2026-02-18T05:03:00.913Z","avatar_url":"https://github.com/fullstack-build.png","language":"TypeScript","readme":"# 📝 tslog: Beautiful logging experience for TypeScript and JavaScript\n\n[![lang: Typescript](https://img.shields.io/badge/Language-Typescript-Blue.svg?style=flat-square)](https://www.typescriptlang.org)\n![License: MIT](https://img.shields.io/npm/l/tslog?logo=tslog\u0026style=flat-square)\n[![npm version](https://img.shields.io/npm/v/tslog?color=76c800\u0026logoColor=76c800\u0026style=flat-square)](https://www.npmjs.com/package/tslog)\n![CI: GitHub](https://github.com/fullstack-build/tslog/actions/workflows/ci.yml/badge.svg)\n[![codecov.io](https://codecov.io/github/fullstack-build/tslog/coverage.svg?branch=v4)](https://codecov.io/github/fullstack-build/tslog?branch=master)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n[![](https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026color=%23fe8e86)](https://github.com/sponsors/fullstack-build)\n[![GitHub stars](https://img.shields.io/github/stars/fullstack-build/tslog.svg?style=social\u0026label=Star)](https://github.com/fullstack-build/tslog)\n\n\n\u003e Powerful, fast and expressive logging for TypeScript and JavaScript\n\n![tslog pretty output](https://raw.githubusercontent.com/fullstack-build/tslog/master/docs/assets/tslog.png \"tslog pretty output in browser and Node.js\")\n\n\n## Highlights\n\n⚡ **Fast and powerful**\u003cbr\u003e\n🪶 **Lightweight and flexible**\u003cbr\u003e\n🏗 **Universal: Works in Browsers, Node.js, Deno and Bun**\u003cbr\u003e\n👮‍️ **Fully typed with TypeScript support (native source maps)**\u003cbr\u003e\n🗃 **_Pretty_ or `JSON` output**\u003cbr\u003e\n📝 **Customizable log level**\u003cbr\u003e\n⭕️ **Supports _circular_ structures**\u003cbr\u003e\n🦸 **Custom pluggable loggers**\u003cbr\u003e\n💅 **Object and error interpolation**\u003cbr\u003e\n🤓 **Stack trace and pretty errors**\u003cbr\u003e\n👨‍👧‍👦 **Sub-logger with inheritance**\u003cbr\u003e\n🙊 **Mask/hide secrets and keys**\u003cbr\u003e\n📦 **CJS \u0026 ESM with tree shaking support**\u003cbr\u003e\n✍️ **Well documented and tested**\u003cbr\u003e\n\n## Example\n\n```typescript\nimport { Logger, ILogObj } from \"tslog\";\n\nconst log: Logger\u003cILogObj\u003e = new Logger();\nlog.silly(\"I am a silly log.\");\n```\n\n## [Become a Sponsor](https://github.com/sponsors/fullstack-build)\nDonations help me allocate more time for my open source work.\n\n[![](https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026color=%23fe8e86)](https://github.com/sponsors/fullstack-build)\n\n\n## Install\n\n```bash\nnpm install tslog\n```\n\n### Node.js\n\nEnable native ESM by setting `\"type\": \"module\"` and run Node with source maps for accurate stack traces:\n\n```json5\n{\n  \"name\": \"NAME\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"tsc -p .\",\n    \"start\": \"node --enable-source-maps dist/index.js\"\n  },\n  \"dependencies\": {\n    \"tslog\": \"^4\"\n  }\n}\n```\n\nAfter building (`npm run build`), start your app with:\n\n```bash\nnpm start\n```\n\nOther handy entry points:\n\n- `node --enable-source-maps dist/index.cjs` – run the CommonJS bundle.\n- `node --enable-source-maps --loader ts-node/esm src/index.ts` – execute TypeScript via `ts-node` in ESM mode.\n- `node --enable-source-maps --require ts-node/register src/index.ts` – execute TypeScript via `ts-node` in CommonJS mode.\n\n### Deno\n\n```ts\n// main.ts\nimport { Logger } from \"npm:tslog\";\n\nconst logger = new Logger();\nlogger.info(\"Hello from Deno\");\n```\n\n```bash\ndeno run main.ts\n# grant optional metadata access: deno run --allow-env main.ts\n```\n\n### Bun\n\n```ts\n// main.ts\nimport { Logger } from \"tslog\";\n\nconst logger = new Logger();\nlogger.info(\"Hello from Bun\");\n```\n\n```bash\nbun run main.ts\n# or add \"dev\": \"bun run src/main.ts\" to package.json scripts\n```\n\nBrowser:\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n\u003ctitle\u003etslog example\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003ch1\u003eExample\u003c/h1\u003e\n\n\u003cscript src=\"tslog.js\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\n  const logger = new tslog.Logger();\n  logger.silly(\"I am a silly log.\");\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n**Enable TypeScript source map support:**\n\nThis feature enables `tslog` to reference a correct line number in your TypeScript source code.\n\n```json5\n// tsconfig.json\n{\n  // ...\n  compilerOptions: {\n    // ...\n    \"inlineSourceMap\": true,  // \u003c!-- here\n    // we recommend using a current ES version\n    target: \"es2020\",\n  },\n}\n```\n\n## Simple example\n\n```typescript\nimport { Logger } from \"tslog\";\n\nconst logger = new Logger({ name: \"myLogger\" });\nlogger.silly(\"I am a silly log.\");\nlogger.trace(\"I am a trace log.\");\nlogger.debug(\"I am a debug log.\");\nlogger.info(\"I am an info log.\");\nlogger.warn(\"I am a warn log with a json object:\", { foo: \"bar\" });\nlogger.error(\"I am an error log.\");\nlogger.fatal(new Error(\"I am a pretty Error with a stacktrace.\"));\n```\n\n## All Features\n\n- **Universal:** Works in browsers, Node.js, Deno, and Bun\n- **Tested:** Great code coverage, CI\n- **Super customizable:** Every aspect can be overwritten\n- **Fully typed:** Written in TypeScript, with native TypeScript support\n- **Default log level:** `silly`, `trace`, `debug`, `info`, `warn`, `error`, `fatal` (different colors)\n- **Customizable log level:** BaseLogger with configurable log level\n- **Pretty \u0026 JSON output:** Structured/_pretty_, `JSON` or suppressed output\n- **Attachable transports:** Send logs to an external log aggregation services, file system, database, or email/slack/sms/you name it...\n- **Minimum log level per output:** `minLevel` level can be set individually per transport\n- **Native source maps lookup:** Shows exact position also in TypeScript code (compile-to-JS), one click to IDE position\n- **Pretty Error:** Errors and stack traces printed in a structured way and fully accessible through _JSON_ (e.g. external Log services)\n- **ES Modules:** import syntax with ([tree-shaking](https://webpack.js.org/guides/tree-shaking/))\n- **Object/JSON highlighting:** Nicely prints out objects\n- **Instance Name**: _(Server-side only)_ Logs capture instance name (default host name) making it easy to distinguish logs coming from different instances\n- **Named Logger:** Logger can be named (e.g. useful for packages/modules and monorepos)\n- **Sub-logger with inheritance:** Powerful sub-loggers with settings inheritance, also at runtime\n- **Secrets masking:** Prevent passwords and secrets from sneaking into log files by masking them\n- **Short paths:** Paths are relative to the root of the application folder\n- **Prefixes:** Prefix log messages and bequeath prefixes to child loggers\n\n## API documentation\n\n\u003e **`tslog \u003e= v4` is a major rewrite and introduces breaking changes.** \u003cbr\u003e\n\u003e Please, follow this documentation when migrating.\n\n### \u003ca name=\"life_cycle\"\u003e\u003c/a\u003eLifecycle of a log message\n\nEvery 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.\n\n![tslog pretty output](https://raw.githubusercontent.com/fullstack-build/tslog/master/docs/assets/tslog_lifesycle.png \"tslog: life cycle of a log message\")\n\n- **log message** Log message comes in through the `BaseLogger.log()` method\n- **mask** If masking is configured, log message gets recursively masked\n- **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.\n- **addMetaToLogObj** Additional meta information, like date, runtime and source code position of the log will be gathered and added to the `_meta` property or any other one configured with the setting `metaProperty`.\n- **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 `formatLogObj`.\n- **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.\n\n### ❗Performance\n\nBy default, `tslog` is optimized for the best developer experience and includes some default settings that may impact performance in production environments.\nTo ensure optimal performance in production, we recommend modifying these settings, such as `hideLogPositionForProduction`(s. below), as needed.  \n\n\n### Default log level\n\n`tslog` comes with default log level `0: silly`, `1: trace`, `2: debug`, `3: info`, `4: warn`, `5: error`, `6: fatal`.\n\n\u003e **Tip:** Each logging method has a return type, which is a _JSON_ representation of the log message (`ILogObj`).\n\n```typescript\nimport { Logger } from \"tslog\";\n\nconst log = new Logger();\nlog.silly(\"I am a silly log.\");\nlog.trace(\"I am a trace log.\");\nlog.debug(\"I am a debug log.\");\nlog.info(\"I am an info log.\");\nlog.warn(\"I am a warn log with a json object:\", { foo: \"bar\" });\nlog.error(\"I am an error log.\");\nlog.fatal(new Error(\"I am a pretty Error with a stacktrace.\"));\n```\n\n### Custom log level\n\nIn addition to the default log level, custom log level can be defined in the same way `tslog` does it under the hood, by extending the `BaseLogger` and utilizing the `log` method.\n`log` method expects the following parameters:\n- logLevelId    - Log level ID e.g. 0\n- logLevelName  - Log level name e.g. silly\n- args          - Multiple log attributes that should be logged.\n\n\u003e **Tip:** Also the generic logging method (log()) returns a _JSON_ representation of the log message (`ILogObject`).\n\n```typescript\nimport { BaseLogger, ILogObjMeta, ISettingsParam, ILogObj } from \"tslog\";\n\nexport class CustomLogger\u003cLogObj\u003e extends BaseLogger\u003cLogObj\u003e {\n  constructor(settings?: ISettingsParam\u003cLogObj\u003e, logObj?: LogObj) {\n    super(settings, logObj, 5);\n  }\n\n  /**\n   * Logs a _CUSTOM_ message.\n   * @param args  - Multiple log attributes that should be logged.\n   * @return LogObject with meta property, when log level is \u003e= minLevel\n   */\n  public custom(...args: unknown[]): LogObj \u0026 ILogObjMeta | undefined {\n    return super.log(8, \"CUSTOM\", ...args);\n  }\n\n}\n```\n\n### Sub-logger\n\nEach `tslog`-Logger instance can create sub-loggers and bequeath its settings to a child.\nIt is also possible to overwrite the `LogObj` when creating a child.\u003cbr\u003e\nSub-loggers are a powerful feature when building a modular application and due to its inheritance make it easy to configure the entire application.\n\nUse `getSubLogger()` to create a child logger based on the current instance.\n\n\n**Example:**\n\n```typescript\nconst mainLogger = new Logger({ type: \"pretty\", name: \"MainLogger\" });\nmainLogger.silly(\"foo bar\");\n\nconst firstSubLogger = mainLogger.getSubLogger({ name: \"FirstSubLogger\" });\nfirstSubLogger.silly(\"foo bar 1\");\n```\n\n#### Sub-logger with `LogObj`\nYou can also overwrite the `LogObj`(s. below), when you create a sub-logger:\n\n```typescript\nconst mainLogObj = { main: true, sub: false };\nconst mainLogger = new Logger({ type: \"pretty\", name: \"MainLogger\" }, mainLogObj);\nmainLogger.silly(\"foo bar\");\n\nconst subLogObj = { main: false, sub: true };\nconst firstSubLogger = mainLogger.getSubLogger({ name: \"FirstSubLogger\" }, subLogObj);\nfirstSubLogger.silly(\"foo bar 1\");\n```\n\n### Settings\n`tslog` is highly customizable and pretty much every aspect can be either configured or overwritten.\nA `settings` object is the first parameter passed to the `tslog` constructor:\n\n```typescript\nconst logger = new Logger\u003cILogObj\u003e({ /* SETTINGS */ }, defaultLogObject);\n```\n\n##### Changing settings at runtime\n`settings` is a public property and can also be changed on runtime. \n\nExample on changing `minLevel` on runtime:\n\n```typescript\n    const logger = new Logger({\n      minLevel: 1\n    });\n    \n    // visible\n    logger.log(1, \"level_one\", \"LOG1\");\n    // visible\n    logger.log(2, \"level_two\", \"LOG2\");\n    \n    // change minLevel to 2\n    logger.settings.minLevel = 2;\n\n    // hidden\n    logger.log(1, \"level_one\", \"LOG3\");\n    // visible\n    logger.log(2, \"level_two\", \"LOG4\");\n```\n\n#### Type: pretty, json, hidden\n\n- `pretty` **Default setting** prints out a formatted structured \"pretty\" log entry.\n- `json` prints out a `JSON` formatted log entry.\n- `hidden` suppresses any output whatsoever and can be used with attached loggers for example.\n\n\u003e Hint: Each JSON log is printed in one line, making it easily parsable by external services.\n\n```typescript\n// pretty output\nconst defaultPrettyLogger = new Logger();\n\n// also pretty output\nconst prettyLogger = new Logger({type: \"pretty\"});\n\n// JSON output\nconst jsonLogger = new Logger({type: \"json\"});\n\n// hidden output\nconst hiddenLogger = new Logger({type: \"hidden\"});\n```\n\n\n#### name\n\nEach logger has an optional name.\nYou can find the name of the logger responsible for a log inside the `Meta`-object or printed in `pretty` mode.\nNames 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.\n\nSimple name example:\n```typescript\nnew Logger({ name: \"myLogger\" });\n```\n\nSub-loggers with an inherited name:\n```typescript\nconst mainLogger = new Logger({ type: \"pretty\", name: \"MainLogger\" });\nmainLogger.silly(\"foo bar\");\n\nconst firstSubLogger = mainLogger.getSubLogger({ name: \"FirstSubLogger\" });\nfirstSubLogger.silly(\"foo bar 1\");\n\nconst secondSubLogger = firstSubLogger.getSubLogger({ name: \"SecondSubLogger\" });\nsecondSubLogger.silly(\"foo bar 2\");\n```\n\nOutput:\n```bash\n2022-11-17 10:45:47.705 SILLY   [/examples/server/index2.ts:51 MainLogger]    foo bar\n2022-11-17 10:45:47.706 SILLY   [/examples/server/index2.ts:54 MainLogger:FirstSubLogger ]    foo bar 1\n2022-11-17 10:45:47.706 SILLY   [/examples/server/index2.ts:57 MainLogger:FirstSubLogger:SecondSubLogger]   foo bar 2\n```\n\n#### minLevel\n\nYou can ignore every log message from being processed until a certain severity.\nDefault severities are:\n`0: silly`, `1: trace`, `2: debug`, `3: info`, `4: warn`, `5: error`, `6: fatal`\n\n```typescript\n\nconst suppressSilly = new Logger({ minLevel: 1 });\nsuppressSilly.silly(\"Will be hidden\");\nsuppressSilly.trace(\"Will be visible\");\n```\n\n#### argumentsArrayName\n\n`tslog` \u003c 4 wrote all parameters into an arguments array. In `tslog` \u003e= 4 the main object becomes home for all log parameters, and they get merged with the default `logObj`.\nIf you still want to put them into a separated parameter, you can do so by defining the `argumentsArrayName`.\n\n```typescript\n\nconst logger = new Logger({\n  type: \"json\",\n  argumentsArrayName: \"argumentsArray\",\n});\nconst logMsg = logger.silly(\"Test1\", \"Test2\");\n\n//logMsg : {\n// argumentsArray: [ 'Test1', 'Test2' ],\n//   _meta: {\n//       [...]\n//     }\n//   }\n// }\n\n```\n\n\n#### hideLogPositionForProduction (default: `false`)\n\nBy default, `tslog` gathers and includes the log code position in the meta information of a `logObj` o improve the developer experience. \nHowever, this can significantly impact performance and slow down execution times in production. \nTo improve performance, you can disable this functionality by setting the option `hideLogPositionForProduction` to `true`.\n\n#### Pretty templates and styles (color settings)\nEnables you to overwrite the looks of a formatted _\"pretty\"_ log message by providing a template string.\nFollowing settings are available for styling:\n\n- **Templates:**\n  - `prettyLogTemplate`: template string for log messages. Possible placeholders:\n    - `{{yyyy}}`: year\n    - `{{mm}}`: month\n    - `{{dd}}`: day\n    - `{{hh}}`: hour\n    - `{{MM}}`: minute\n    - `{{ss}}`: seconds\n    - `{{ms}}`: milliseconds\n    - `{{dateIsoStr}}`: Shortcut for `{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}`\n    - `{{rawIsoStr}}`: Renders the date and time in ISO format (e.g.: YYYY-MM-DDTHH:mm:ss.SSSZ)\n    - `{{logLevelName}}`: name of the log level\n    - `{{name}}`: optional name of the current logger and his parents (e.g. \"ParentLogger:ThisLogger\")\n    - `{{nameWithDelimiterPrefix}}`: optional name of the current logger (s. above) with a delimiter in the beginning\n    - `{{nameWithDelimiterSuffix}}`: optional name of the current logger (s. above) with a delimiter at the end\n    - `{{fullFilePath}}`: a full path starting from `/` root\n    - `{{filePathWithLine}}`: a full path below the project path with line number\n    - `{{fileNameWithLine}}`: file name with line number\n  - `prettyErrorTemplate`: template string for error message. Possible placeholders:\n    - `{{errorName}}`: name of the error\n    - `{{errorMessage}}`: error message\n    - `{{errorStack}}`: Placeholder for all stack lines defined by `prettyErrorStackTemplate`\n  - `prettyErrorStackTemplate`: template string for error stack trace lines. Possible placeholders:\n    - `{{fileName}}`: name of the file\n    - `{{fileNameWithLine}}`: file name with line number\n    - `{{filePathWithLine}}`: a full path below the project path with a line number\n    - `{{method}}`: _optional_ name of the invoking method\n  - `prettyErrorParentNamesSeparator`: separator to be used when joining names ot the parent logger, and the current one (default: `:`)\n  - `prettyErrorLoggerNameDelimiter`: if a logger name is set this delimiter will be added afterwards\n  - `prettyInspectOptions`: \u003ca href=\"https://nodejs.org/api/util.html#utilinspectobject-options\" target=\"_blank\"\u003eAvailable options\u003c/a\u003e\n\n  ### Customizing template tokens\n  You can add your own template tokens by overriding `settings.overwrite.addPlaceholders`. The callback receives the current metadata object and the placeholder map so you can add or overwrite entries.\n  For example, to add the token `{{custom}}`:\n  ```javascript\n  const logger = new Logger({\n    type: \"pretty\",\n    prettyLogTemplate: \"{{custom}} \",\n    overwrite: {\n      addPlaceholders: (logObjMeta: IMeta, placeholderValues: Record\u003cstring, string\u003e) =\u003e {\n        placeholderValues[\"custom\"] = \"test\";\n      },\n    },\n  });\n  ```\n  This replaces `{{custom}}` with the string `\"test\"` in the rendered output.\n\n- **Styling:**\n  - `stylePrettyLogs`: defines whether logs should be styled and colorized (ANSI in server runtimes, CSS in browsers that support it)\n  - `prettyLogStyles`: provides colors and styles for different placeholders and can also be dependent on the value (e.g. log level)\n    - Level 1: template placeholder (defines a style for a certain template placeholder, s. above, without brackets).\n    - 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.\n    - 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.\n  - `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)\n\n- **Time zone support:**\n  - `prettyLogTimeZone`: Set timezone of pretty log messages to either `UTC` (default) or `local` (based on your server/browser configuration)\n\n#### Log meta information\n`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`.\nYou can define the property containing this meta information with `metaProperty`, which is \"_meta\" by default.\n\n`tslog` automatically determines the first caller frame outside of the library, even in bundled environments such as Vite or Next.js. If you need to override the detected frame, provide `stackDepthLevel` when constructing a `Logger`.\n\n#### Pretty templates and styles (color settings)\n\n```typescript\n\nconst logger = new Logger({\n  prettyLogTemplate: \"{{yyyy}}.{{mm}}.{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}}\\t{{logLevelName}}\\t[{{filePathWithLine}}{{name}}]\\t\",\n  prettyErrorTemplate: \"\\n{{errorName}} {{errorMessage}}\\nerror stack:\\n{{errorStack}}\",\n  prettyErrorStackTemplate: \"  • {{fileName}}\\t{{method}}\\n\\t{{filePathWithLine}}\",\n  prettyErrorParentNamesSeparator: \":\",\n  prettyErrorLoggerNameDelimiter: \"\\t\",\n  stylePrettyLogs: true,\n  prettyLogTimeZone: \"UTC\",\n  prettyLogStyles: {\n    logLevelName: {\n      \"*\": [\"bold\", \"black\", \"bgWhiteBright\", \"dim\"],\n      SILLY: [\"bold\", \"white\"],\n      TRACE: [\"bold\", \"whiteBright\"],\n      DEBUG: [\"bold\", \"green\"],\n      INFO: [\"bold\", \"blue\"],\n      WARN: [\"bold\", \"yellow\"],\n      ERROR: [\"bold\", \"red\"],\n      FATAL: [\"bold\", \"redBright\"],\n    },\n    dateIsoStr: \"white\",\n    filePathWithLine: \"white\",\n    name: [\"white\", \"bold\"],\n    nameWithDelimiterPrefix: [\"white\", \"bold\"],\n    nameWithDelimiterSuffix: [\"white\", \"bold\"],\n    errorName: [\"bold\", \"bgRedBright\", \"whiteBright\"],\n    fileName: [\"yellow\"],\n    fileNameWithLine: \"white\",\n  },\n});\n\n```\n\n#### Masking secrets in logs\nOne of the most common ways of a password/secret breach is through log files.\nGiven the central position of `tslog` as the collecting hub of all application logs, it's only natural to use it as a filter.\nThere are multiple ways of masking secrets, before they get exposed:\n\n- `maskPlaceholder`: Placeholder to replaced masked secrets with, Default: `[***]`\n- `maskValuesOfKeys`: Array of keys to replace the values with the placeholder (`maskPlaceholder`). Default: `[\"password\"]`\n- `maskValuesOfKeysCaseInsensitive`: Should the keys be matched case-insensitive (e.g. \"password\" would replace \"password\" as well as \"Password\", and \"PASSWORD\"). Default: `false`\n- `maskValuesRegEx`: For even more flexibility, you can also replace strings and object values with a RegEx.\n\n#### Prefixing logs\nPrefix every log message with an array of additional attributes.\u003cbr\u003e\nPrefixes propagate to sub-loggers and can help to follow a chain of promises.\u003cbr\u003e\nIn addition to \u003ca href=\"https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage\" target=\"_blank\"\u003e`AsyncLocalStorage`\u003c/a\u003e, prefixes can help further distinguish different parts of a request.\n\n\u003e **Hint:** A good example could be a GraphQL request, that by design could consist of multiple queries and/or mutations.\n\n**Example:**\n\n```typescript\nconst logger = new Logger({\n  prefix: [\"main-prefix\", \"parent-prefix\"],\n});\nlogger.info(\"MainLogger message\");\n// Output:\n// main-prefix parent-prefix MainLogger message\n\nconst childLogger = logger.getSubLogger({\n  prefix: [\"child1-prefix\"],\n});\nchildLogger.info(\"child1 message\");\n// Output:\n// main-prefix parent-prefix child1-prefix MainLogger message\n\nconst grandchildLogger = childLogger.getSubLogger({\n  prefix: [\"grandchild1-prefix\"],\n});\ngrandchildLogger.silly(\"grandchild1 message\");\n// Output:\n// main-prefix parent-prefix child1-prefix grandchild1-prefix grandchild1 message\n```\n\n\n#### Attach additional transports\n\n`tslog` focuses on the one thing it does well: capturing logs.\nTherefore, there is no built-in _file system_ logging, _log rotation_, or similar.\nPer default all logs go to `console`, which can be overwritten (s. below).\n\nHowever, you can easily attach as many _transports_ as you wish, enabling you to do fancy stuff\nlike sending messages to _Slack_ or _Telegram_ in case of an urgent error or forwarding them to a log aggregator service.\n\n**Attached transports are also inherited by sub-loggers.**\n\n##### Simple transport example\n\nHere is a very simple implementation used in our _vitest_ tests.\nThis example will suppress logs from being sent to `console` (`type: \"hidden\"`) and will instead collect them in an `array`.\n\n```typescript\nconst transports: any[] = [];\nconst logger = new Logger({ type: \"hidden\" });\n\nlogger.attachTransport((logObj) =\u003e {\n  transports.push(logObj);\n});\n\nconst logMsg = logger.info(\"Log message\");\n```\n\n##### Storing logs in a file\n\nHere is an example of how to store all logs in a file.\n\n```typescript\nimport { Logger } from \"tslog\";\nimport { appendFileSync } from \"fs\";\n\nconst logger = new Logger();\nlogger.attachTransport((logObj) =\u003e {\n  appendFileSync(\"logs.txt\", JSON.stringify(logObj) + \"\\n\");\n});\n\nlogger.debug(\"I am a debug log.\");\nlogger.info(\"I am an info log.\");\nlogger.warn(\"I am a warn log with a json object:\", { foo: \"bar\" });\n\n```\n\n##### Storing logs in a file system with rotating files\n\nIf 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.\nThere is a great library called `rotating-file-stream` solving this problem for us and even adding features like compression, file size limit etc.\n\n1. First you need to install this library:\n```bash\n  npm i rotating-file-stream\n```\n\n2. Combine it with `tslog`:\n\n```typescript\nimport { Logger } from \"tslog\";\nimport { createStream } from \"rotating-file-stream\";\n\nconst stream = createStream(\"tslog.log\", {\n  size: \"10M\", // rotate every 10 MegaBytes written\n  interval: \"1d\", // rotate daily\n  compress: \"gzip\", // compress rotated files\n});\n\nconst logger = new Logger();\nlogger.attachTransport((logObj) =\u003e {\n  stream.write(JSON.stringify(logObj) + \"\\n\");\n});\n\nlogger.debug(\"I am a debug log.\");\nlogger.info(\"I am an info log.\");\nlogger.warn(\"I am a warn log with a json object:\", { foo: \"bar\" });\n\n```\n\n#### Overwriting default behavior\n\nOne of the key advantages of `tslog` \u003e= 4 is that you can overwrite pretty much every aspect of the log processing described in \u003ca href=\"#life_cycle\"\u003e\"Lifecycle of a log message\"\u003c/a\u003e.\n\nFor every log:\n```typescript\n    const logger = new Logger({\n  overwrite: {\n    mask: (args: unknown[]): unknown[] =\u003e {\n      // mask and return an array of log attributes for further processing\n    },\n    toLogObj: (args: unknown[], clonesLogObj?: LogObj): unknown =\u003e {\n      // convert the log attributes to a LogObj and return it\n    },\n    addMeta: (logObj: any, logLevelId: number, logLevelName: string) =\u003e {\n      // add meta information to the LogObj and return it\n    }\n\n  },\n});\n```\n\nFor `pretty` logs:\n```typescript\n    const logger = new Logger({\n      type: \"pretty\",\n      overwrite: {\n        formatMeta: (meta?: IMeta) =\u003e {\n          // format LogObj meta object to a string and return it\n        },\n        formatLogObj: \u003cLogObj\u003e(maskedArgs: unknown[], settings: ISettings\u003cLogObj\u003e) =\u003e {\n            // format LogObj attributes to a string and return it\n        },\n        transportFormatted: (\n          logMetaMarkup: string,\n          logArgs: unknown[],\n          logErrors: string[],\n          logMeta?: IMeta,\n          settings?: ISettings\u003cLogObj\u003e\n        ) =\u003e {\n          // overwrite the default transport for formatted (e.g. pretty) log levels. e.g. replace console with StdOut, write to file etc.\n        },\n      },\n    });\n```\n\n\u003e **Note:** `transportFormatted` receives the resolved log meta as an optional fourth argument and the active settings as an optional fifth argument. Handlers that still accept only three arguments continue to work unchanged.\n\nFor `JSON` logs (no formatting happens here):\n```typescript\n    const logger = new Logger({\n      type: \"json\",\n      overwrite: {\n        transportJSON: (logObjWithMeta: any) =\u003e {\n          // transport the LogObj to console, StdOut, a file or an external service\n        },\n      },\n    });\n```\n\n##### Example of sending logs to console instead of the standard output.\n\n```typescript\n    const logger = new Logger({\n      type: \"pretty\",\n      overwrite: {\n        transportFormatted: (logMetaMarkup, logArgs, logErrors, logMeta) =\u003e {\n          // Send different log levels to appropriate console methods\n          const logLevel = logMeta?.logLevelName ?? logMetaMarkup.trim().split(\"\\t\")[1];\n          switch (logLevel) {\n            case \"WARN\":\n              console.warn(logMetaMarkup, ...logArgs, ...logErrors);\n              break;\n            case \"ERROR\":\n            case \"FATAL\":\n              console.error(logMetaMarkup, ...logArgs, ...logErrors);\n              break;\n            case \"INFO\":\n              console.info(logMetaMarkup, ...logArgs, ...logErrors);\n              break;\n            case \"DEBUG\":\n            case \"TRACE\":\n            case \"SILLY\":\n            default:\n              console.log(logMetaMarkup, ...logArgs, ...logErrors);\n              break;\n          }\n      },\n    });\n```\n\n### Defining and accessing `logObj`\nAs described in \u003ca href=\"#life_cycle\"\u003e\"Lifecycle of a log message\"\u003c/a\u003e, every log message goes through some lifecycle steps and becomes an object representation of the log with the name `logObj`.\nA default logObj can be passed to the `tslog` constructor and will be cloned and merged into the log message. This makes `tslog` \u003e= 4 highly configurable and easy to integrate into any 3rd party service.\nThe entire `logObj` will be printed out in `JSON` mode and also returned by every log method.\n\n\u003e **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).\n\n```typescript\ninterface ILogObj {\n    foo: string;\n}\n\nconst defaultLogObject: ILogObj = {\n  foo: \"bar\",\n};\n\nconst logger = new Logger\u003cILogObj\u003e({ type: \"json\" }, defaultLogObject);\nconst logMsg = logger.info(\"Test\");\n\n// logMsg: {\n//  '0': 'Test',\n//  foo: 'bar',\n//  _meta: {\n//    runtime: 'node',\n//    hostname: 'Eugenes-MBP.local',\n//    date: 2022-10-23T10:51:08.857Z,\n//    logLevelId: 3,\n//    logLevelName: 'INFO',\n//    path: {\n//      fullFilePath: 'file:///[...]/tslog/examples/server/index.ts:113:23',\n//      fileName: 'index.ts',\n//      fileColumn: '23',\n//      fileLine: '113',\n//      filePath: '/examples/server/index.ts',\n//      filePathWithLine: '/examples/server/index.ts:113'\n//    }\n//  }\n//}\n```\n\n## Backwards compatibility\n\n\u003e **`tslog` follows a semantic release policy.** A major version change indicates breaking changes.\u003cbr\u003e\u003cbr\u003e\n\u003e `tslog \u003e=4` is less limiting when it comes to configuration. There are many use cases (especially when it comes to integration with 3rd party services) that now can be achieved elegantly and were not possible before.\n\n### RequestID: Mark a request (e.g. HTTP) call with AsyncLocalStorage and `tslog`\n\u003e**Node.js 13.10 introduced a new feature called \u003ca href=\"https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage\" target=\"_blank\"\u003eAsyncLocalStorage.\u003c/a\u003e**\u003cbr\u003e\n\n** Keep track of all subsequent calls and promises originated from a single request (e.g. HTTP).**\n\nIn a real world application a call to an API would lead to many logs produced across the entire application.\nWhen debugging it can be quite handy to be able to group all logs based on a unique identifier, e.g.  `requestId`.\n\nSome providers (e.g. `Heroku`) already set a `X-Request-ID` header, which we are going to use or fallback to a short ID generated by \u003ca href=\"https://www.npmjs.com/package/nanoid\" target=\"_blank\"\u003e`nanoid`\u003c/a\u003e.\n\n**In this example every subsequent logger is a sub-logger of the main logger and thus inherits all of its settings making `requestId` available throughout the entire application without any further ado.**\n\n`tslog` works with any API framework (like `Express`, `Koa`, `Hapi` and so on), but in this example we are using `Koa`.\n```typescript\n  import { AsyncLocalStorage } from \"async_hooks\";\n  import Koa from \"koa\";\n  import { customAlphabet } from \"nanoid\";\n  import { Logger } from \"tslog\";\n\n  interface ILogObj {\n    requestId?: string | (() =\u003e string | undefined);\n  }\n\n  const asyncLocalStorage: AsyncLocalStorage\u003c{ requestId: string }\u003e = new AsyncLocalStorage();\n\n  const defaultLogObject: ILogObj = {\n    requestId: () =\u003e asyncLocalStorage.getStore()?.requestId,\n  };\n\n  const logger = new Logger\u003cILogObj\u003e({ type: \"json\" }, defaultLogObject);\n  export { logger };\n\n  logger.info(\"Test log without requestId\");\n\n  const koaApp = new Koa();\n\n  /** START AsyncLocalStorage requestId middleware **/\n  koaApp.use(async (ctx: Koa.Context, next: Koa.Next) =\u003e {\n    // use x-request-id or fallback to a nanoid\n    const requestId: string = (ctx.request.headers[\"x-request-id\"] as string) ?? customAlphabet(\"1234567890abcdefghijklmnopqrstuvwxyz\", 6)();\n    // every other Koa middleware will run within the AsyncLocalStorage context\n    await asyncLocalStorage.run({ requestId }, async () =\u003e {\n      return next();\n    });\n  });\n  /** END AsyncLocalStorage requestId middleware **/\n\n  // example middleware\n  koaApp.use(async (ctx: Koa.Context, next) =\u003e {\n\n    // log request\n    logger.silly({ originalUrl: ctx.originalUrl, status: ctx.response.status, message: ctx.response.message });\n\n    // also works with a sub-logger\n    const subLogger = logger.getSubLogger();\n    subLogger.info(\"Log containing requestId\"); // \u003c-- will contain a requestId\n\n    return await next();\n  });\n\n  koaApp.listen(3000);\n\n  logger.info(\"Server running on port 3000\");\n```\n","funding_links":["https://github.com/sponsors/fullstack-build"],"categories":["TypeScript","json","Built with TypeScript"],"sub_categories":["Libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffullstack-build%2Ftslog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffullstack-build%2Ftslog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffullstack-build%2Ftslog/lists"}