{"id":26415609,"url":"https://github.com/ymonb1291/papyrus","last_synced_at":"2025-03-18T00:53:54.718Z","repository":{"id":57675418,"uuid":"301531127","full_name":"ymonb1291/papyrus","owner":"ymonb1291","description":"Lightweight, modular JSON logger for `Deno` with support for external formatters and transports.","archived":false,"fork":false,"pushed_at":"2021-05-01T19:03:50.000Z","size":109,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-17T03:34:34.249Z","etag":null,"topics":["deno","json-logger","logger","logging"],"latest_commit_sha":null,"homepage":"","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/ymonb1291.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-05T20:25:47.000Z","updated_at":"2023-09-17T02:33:12.000Z","dependencies_parsed_at":"2022-09-26T18:11:32.414Z","dependency_job_id":null,"html_url":"https://github.com/ymonb1291/papyrus","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymonb1291%2Fpapyrus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymonb1291%2Fpapyrus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymonb1291%2Fpapyrus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymonb1291%2Fpapyrus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ymonb1291","download_url":"https://codeload.github.com/ymonb1291/papyrus/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244046965,"owners_count":20389198,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["deno","json-logger","logger","logging"],"created_at":"2025-03-18T00:53:54.068Z","updated_at":"2025-03-18T00:53:54.707Z","avatar_url":"https://github.com/ymonb1291.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Papyrus\n![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ymonb1291/papyrus/CI?label=ci)\n![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/ymonb1291/papyrus?include_prereleases)\n![GitHub commits since latest release (by SemVer)](https://img.shields.io/github/commits-since/ymonb1291/papyrus/latest?sort=semver)\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/ymonb1291/papyrus)\n[![deno doc](https://doc.deno.land/badge.svg)](https://doc.deno.land/https/deno.land/x/papyrus/mod.ts)\n![GitHub](https://img.shields.io/github/license/ymonb1291/papyrus)\n\nLightweight, modular JSON logger for `Deno` with support for external formatter and transports.\n\n## Features\n* 5 logging levels: `trace`, `debug`, `info`, `warn` and `error`\n* `Debug` features\n* All logs output as `JSON` strings\n* Decorate your logs with `bindings`\n* Create `child loggers` inherit their parent's bindings and settings\n* Support for external `formatters` and `transports`\n\n# How to use\nBasic usage:\n```\nimport Papyrus from \"https://deno.land/x/papyrus/mod.ts\";\n\nconst logger = new Papyrus({\n  useLabels: true,\n});\n\nlogger.trace(\"Hello World!\");\nlogger.debug(\"Hello World!\");\nlogger.info(\"Hello World!\");\nlogger.warn(\"Hello World!\");\nlogger.error(\"Hello World!\");\n\n// Outputs:\n//   {\"level\":\"trace\",\"time\":1589371200000,\"message\":\"Hello World!\"}\n//   {\"level\":\"debug\",\"time\":1589371200000,\"message\":\"Hello World!\"}\n//   {\"level\":\"info\",\"time\":1589371200000,\"message\":\"Hello World!\"}\n//   {\"level\":\"warn\",\"time\":1589371200000,\"message\":\"Hello World!\"}\n//   {\"level\":\"error\",\"time\":1589371200000,\"message\":\"Hello World!\"}\n```\nUsing child loggers\n```\nimport Papyrus from \"https://deno.land/x/papyrus/mod.ts\";\n\nconst parent = new Papyrus({\n  bindings: {pid: Deno.pid},\n  name: \"parentLogger\",\n  useLabels: true,\n});\n\nparent.info(\"Hello from parent!\");\n\nconst child = parent.child({\n  bindings: {host: \"127.0.0.1\"},\n  name: \"childLogger\"\n});\n\nchild.info(\"Hello from child!\");\n// Outputs:\n//   {\"level\":\"info\",\"name\":\"parentLogger\",\"time\":1589371200000,\"pid\":6210,\"message\":\"Hello from parent!\"}\n//   {\"level\":\"info\",\"name\":\"childLogger\",\"time\":1589371200000,\"pid\":6210,\"host\":\"127.0.0.1\",\"message\":\"Hello from child!\"}\n```\n\n# Table of contents\n\n- [How to use](#how-to-use)\n- [Table of contents](#table-of-contents)\n- [Creating a logger](#creating-a-logger)\n- [Logging with bindings](#logging-with-bindings)\n- [Child loggers](#child-loggers)\n- [Options](#options)\n  - [PapyrusOptions](#p#apyrusoptions)\n  - [ChildOptions](##childoptions)\n  - [TransportOptions](##transportoptions)\n- [Logging](#logging)\n  - [Level enum](##level-enum)\n  - [Log methods and debug features](##log-methods-and-debug-features)\n  - [Logging with payload](##logging-with-payload)\n- [Output](#output)\n  - [Route of a log](##route-of-a-log)\n  - [Interfaces of a log](##interfaces-of-a-log)\n- [Formatter](#formatter)\n  - [What's a formatter?](##what's-a-formatter?)\n  - [How to create a formatter?](##how-to-create-a-formatter?)\n- [Transport](#Transport)\n  - [What's a transport?](##what's-a-transport?)\n  - [How to create a transport?](##how-to-create-a-transport)\n- [Plugins](#plugins)\n- [Contributions](#contributions)\n\n# Creating a logger\nImport Papyrus from [Deno.land](https://deno.land/x):\n```\nimport Papyrus from \"https://deno.land/x/papyrus/mod.ts\";\n// Or\nimport { Papyrus } from \"https://deno.land/x/papyrus/mod.ts\";\n```\n\n### Nameless logger with default options\nA nameless logger will be created with the default options:\n```\nconst logger = new Papyrus();\n```\n### Named logger with default options\nA named logger will be created with the default options:\n```\nconst logger = new Papyrus(\"myLogger\");\n```\n### Customized logger\nAn object of type `PapyrusOptions` can be used to specify options:\n```\nconst logger = new Papyrus({\n  // options...\n});\n```\n\n### Logging with bindings\nBindings are properties that are *bound* to the logger. In other therms, any log output by the logger will contain it's bindings. Bindings are typically found before the log's message.\n```\nconst logger = new Papyrus({\n  bindings: {pid: Deno.pid}\n});\n\nlogger.info(\"Hello World!\");\n\n// Outputs:\n//   {\"level\":2,\"time\":1589371200000,\"pid\":3876,\"message\":\"Hello World!\"}\n```\nIf the `mergeBindings` property is false, all bindings will be grouped in a plain object under the `bindings` property.\n```\nconst logger = new Papyrus({\n  bindings: {pid: Deno.pid},\n  mergeBindings: false\n});\n\nlogger.info(\"Hello World!\");\n\n// Outputs:\n//   {\"level\":2,\"time\":1589371200000,\"bindings\":{\"pid\":4309},\"message\":\"Hello World!\"}\n```\n\n### Child loggers\nChild loggers can be created from a `Papyrus` logger by calling the `child` method. The `child` method requires options of type `ChildOptions` that contains at least a name property.\nA child logger inherits of all of its parent's bindings.\n```\nconst logger = new Papyrus({\n  bindings: {pid: Deno.pid}\n}).child({\n    bindings: {host: \"127.0.0.1\"},\n    name: \"myChildLogger\"\n  });\n\nlogger.info(\"Hello World!\");\n\n// Outputs:\n//   {\"level\":2,\"name\":\"childLogger\",\"time\":1589371200000,\"pid\":4022,\"host\":\"127.0.0.1\",\"message\":\"Hello World!\"}\n```\n\n# Options\n\n## PapyrusOptions\n`Papyrus` can be configured through an object that implements the interface `PapyrusOptions`. All properties are optional.\n```\ninterface PapyrusOptions {\n  bindings?: KeyValuePair;\n  destination?: DestinationOptions | DestinationOptions[];\n  enabled?: boolean;\n  formatter?: Formatter;\n  level?: Level | keyof typeof Level;\n  mergeBindings?: boolean;\n  mergePayload?: boolean;\n  name?: string;\n  time?: boolean;\n  useLabels?: boolean;\n}\n```\n\nProperty | Type | Default | Description\n-------- | ---- | ------- | -----------\n`bindings` | KeyValuePair | { } | Object that contains the bindings\n`enabled` | boolean | true | Disables the logger and its children when true\n`formatter` | Formatter | undefined | Defines a `Formatter` to use\n`level` | string \\| number | \"trace\" | Sets the min. level to a key of `Level`\n`mergeBindings` | boolean | true | The bindings will be merged with `Log` if true\n`mergePayload` | boolean | true | The payload will be merged with `Log` if true\n`name` | string | undefined | The logs will include this name, which must be unique\n`time` | boolean | true | The logs will not include the time when false\n`transport` | TransportOptions \\| TransportOptions[ ] | [ ] | Defines a `Transport`, or an array or `Transport` to use\n`useLabels` | boolean | false | The logs will be output with a numeric level when false\n\n## ChildOptions\nA `ChildOptions` configuration object must be provided when creating a child logger.\n```\ninterface ChildOptions {\n  bindings?: KeyValuePair;\n  name: string;\n}\n```\n\n## TransportOptions\nA `TransportOptions` configuration object is used when specifying a `Transport`.\n```\ninterface TransportOptions {\n  use?: Transport;\n  formatter?: Formatter;\n}\n```\nProperty | Type | Default | Description\n-------- | ---- | ------- | -----------\nuse | Transport | undefined | Defines a `Transport` to use\nformatter | Formatter | undefined | Defines a `Formatter` to use\n\n# Logging\n## Level enum\nAll levels are defined in a numeric enum.\n```\nenum Level {\n  trace,     // Value: 0\n  debug,     // Value: 1\n  info,      // Value: 2\n  warn,      // Value: 3\n  error,     // Value: 4\n}\n```\n## Log methods and debug features\nInstances of `Papyrus` have five logging methods that one can use, each specific to a level. The methods are `trace`, `debug`, `info`, `warn` and `error`.\n```\nconst logger = new Papyrus();\n\nlogger.trace(\"Level is trace\");\nlogger.debug(\"Level is debug\");\nlogger.info(\"Level is info\");\nlogger.warn(\"Level is warn\");\nlogger.error(\"Level is error\");\n\n// Outputs:\n//   {\"level\":0,\"time\":1589371200000,\"message\":\"Level is trace\"}\n//   {\"level\":1,\"time\":1589371200000,\"message\":\"Level is debug\"}\n//   {\"level\":2,\"time\":1589371200000,\"message\":\"Level is info\"}\n//   {\"level\":3,\"time\":1589371200000,\"message\":\"Level is warn\"}\n//   {\"level\":4,\"time\":1589371200000,\"message\":\"Level is error\"}\n```\nIt's possible to configure your logger so that it doesn't output logs below a given level. Let's repeat the example of above with the level set to `warn`.\n```\nconst logger = new Papyrus({level: Level.warn});\n\nlogger.trace(\"Level is trace\");\nlogger.debug(\"Level is debug\");\nlogger.info(\"Level is info\");\nlogger.warn(\"Level is warn\");\nlogger.error(\"Level is error\");\n\n// Outputs:\n//   {\"level\":3,\"time\":1589371200000,\"message\":\"Level is warn\"}\n//   {\"level\":4,\"time\":1589371200000,\"message\":\"Level is error\"}\n```\nOnly the logs with a level of `warn` or above were output.\nNote that we imported the level directly from the enum in this example. The configurations `{level: \"warn\"}` and `{level: 3}` would have given the same result.\n\n## Logging with payload\nA payload is like bindings, except that it's log-specific. A payload is typically found after the log's message.\n```\nconst logger = new Papyrus();\n\nlogger.info(\"Hello World!\", {a: \"A\"});\n\n// Outputs:\n//   {\"level\":2,\"time\":1589371200000,\"message\":\"Hello World!\",\"a\":\"A\"}\n```\nIf the `mergePayload` property is false, all properties from the payload will be grouped in a plain object under the `payload` property.\n```\nconst logger = new Papyrus({mergePayload: false});\n\nlogger.info(\"Hello World!\", {a: \"A\"});\n\n// Outputs:\n//   {\"level\":2,\"time\":1589371200000,\"message\":\"Hello World!\",\"payload\":{\"a\":\"A\"}}\n```\n\n# Output\n\n## Route of a log\nInternally, `Papyrus` logs are defined as plain objects implementing `Log`. The log is then sent to the formatter, which may return the log as a modified `Log` object or as a JSON string. At this point, any log which is not already a string will be stringified using the `JSON.stringify()` function. The string is finally sent to the transport(s) which will consume the log.\n\n`Papyrus` supports several transports, and each can have their own formatter.\n\n## Interfaces of a log\nA log is transmitted to a formatter or a transport as an object implementing the `Log` interface, which is a generic interface for any type of log, or as a JSON string representing this object. In formatters and transports, it can be interesting to differentiate messages from errors. Which is why `Papyrus` is exporting the interfaces `LogWithMessage` and `LogWithError`.\n\nAll logs contain a `level` property.\n```\ninterface Log {\n  level: number | string;\n  name?: string;\n  time?: number | string;\n  bindings?: KeyValuePair;\n  message?: string | number | boolean;\n  error?: {\n    message: string;\n    name: string;\n    stack?: string;\n  };\n  payload?: KeyValuePair;\n}\n\ninterface LogWithMessage {\n  level: number | string;\n  name?: string;\n  time?: number | string;\n  bindings?: KeyValuePair;\n  message?: string | number | boolean;\n  payload?: KeyValuePair;\n}\n\ninterface LogWithError {\n  level: number | string;\n  name?: string;\n  time?: number | string;\n  bindings?: KeyValuePair;\n  error: {\n    message: string;\n    name: string;\n    stack?: string;\n  }\n  payload?: KeyValuePair;\n}\n```\n\n# Formatter\n## What's a formatter?\nA formatter is a class that implements the `Formatter` interface. It can modify an object of type `Log`, or convert it into a string. There are two kind of formatters:\n* **Editors:** These formatters will alter, add or delete properties of `Log`. In principle, they should always return a object that implements `Log`, or a JSON representation of such object.\n* **Prettifiers:** These formatters will convert `Log` to a string formatted to be easier to read than a JSON string.\n```\ninterface Formatter {\n  format: (data: string | Log, _v: number) =\u003e string | Log;\n}\n```\nThe `_v` property represents the version of the `Log` interface and will always be the same value for a given version of `Papyrus`. is hidden and defines the version of the `Log` interface. Should the `Log` interface be updated in the future, the value of `_v` will be incremented. For now, it is always `1`.\n\n## How to create a formatter?\nHere is an example of a formatter that returns the log it receives as a `Log`:\n```\nclass IdentityFormatter implements Formatter {\n  public format(log: Log | string): Log {\n    if(typeof log === \"string\") return JSON.parse(log);\n    else return log;\n  }\n}\n```\n\n# Transport\n## What's a transport?\nA transport is a class that implements the `Transport` interface. It's the final destination of the log. For example, it can:\n* Send the log to the console\n* Write the log into a file\n* Save the log in a database\n```\ninterface Transport {\n  log: (data: string, _v: number) =\u003e void;\n}\n```\n\n## How to create a Transport?\nHere is an example of a transport sends the log to the console as a string:\n```\nclass ConsoleTransport implements Transport {\n  public log(log: Log |string): void {\n    if(typeof log === \"string\") console.log(log);\n    else JSON.stringify(log);\n  }\n}\n```\n\n# Plugins\n* [Papyrus-File](https://github.com/ymonb1291/papyrus-file): A transport for writing into files\n* [Papyrus-Pretty](https://github.com/ymonb1291/papyrus-pretty): A formatter that prettifies your logs\n\n# Contributions\nPRs are welcome!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fymonb1291%2Fpapyrus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fymonb1291%2Fpapyrus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fymonb1291%2Fpapyrus/lists"}