{"id":22608803,"url":"https://github.com/atombrenner/npm-log-json","last_synced_at":"2026-05-01T15:36:11.110Z","repository":{"id":57099574,"uuid":"458849029","full_name":"atombrenner/npm-log-json","owner":"atombrenner","description":"Pragmatic JSON line logging for humans and Elasticsearch.","archived":false,"fork":false,"pushed_at":"2023-12-23T11:38:14.000Z","size":858,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-04-25T07:20:25.571Z","etag":null,"topics":["logging","npm-package","structured-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/atombrenner.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-13T15:28:03.000Z","updated_at":"2022-02-14T05:03:03.000Z","dependencies_parsed_at":"2024-12-08T15:09:29.949Z","dependency_job_id":"7fa7ac1f-0992-4708-a3db-0a2a14112b82","html_url":"https://github.com/atombrenner/npm-log-json","commit_stats":{"total_commits":18,"total_committers":1,"mean_commits":18.0,"dds":0.0,"last_synced_commit":"aed22c40b54f97fa4de520d02c1d22a426cecaeb"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atombrenner%2Fnpm-log-json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atombrenner%2Fnpm-log-json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atombrenner%2Fnpm-log-json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atombrenner%2Fnpm-log-json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atombrenner","download_url":"https://codeload.github.com/atombrenner/npm-log-json/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246112642,"owners_count":20725300,"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":["logging","npm-package","structured-logging"],"created_at":"2024-12-08T15:09:26.478Z","updated_at":"2026-05-01T15:36:06.082Z","avatar_url":"https://github.com/atombrenner.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# npm-log-json\n\nPragmatic JSON logging with javascript for humans and Elasticsearch\n\n## Motivation\n\nWhy not use an existing logger like [pino](https://github.com/pinojs/pino),\n[winston](https://github.com/winstonjs/winston)\nor [log4js](https://github.com/log4js-node/log4js-node)?\nBecause mature logging frameworks tend to suffer from feature overload.\nMany of them are designed for a world, where monolithic applications run\na long time on the same servers. They need to take care of writing to files,\ncleaning up old files or aggregating logs. In a serverless world, most of those\nrequirements are now [YAGNIs](https://martinfowler.com/bliki/Yagni.html).\n\nThe goal was to have something really simple, with focus on\n\n1. usability: every javascript developer can use it\n2. output is formatted as [JSON lines](https://jsonlines.org/)\n3. works out of the box in serverless environments\n4. no or minimal dependencies\n\nWhen working with Node or the Browser, you already have a logging framework built in.\nIt's the console module. You don't need to include it, it exists in the browser\nand nodejs. The API is known and used by every Javacscript developer.\nIn AWS Lambda, the console module is enhanced by AWS with some interesting\ndata, e.g. the requestId and memory usage. So why not benefit from this?\nThe console module just works in the browser and nodejs, even if writing\nto `process.stdout` could save some nanoseconds on node.\nSo the basic idea was to stick with the console.log pattern as long as possible\nand add error and json formatting.\n\nThis package does not optimize for:\n\n- for the last bit of speed\n- for preventing users from making rare mistakes, e.g.\n  - log non-serializable objects like cyclic graphs or functions\n  - do inefficient log message formatting\n- suppress logs below a certain level (should be done in the viewer or at ingestion time)\n- super fine granular log levels. All you need is debug, info, warn, and error.\n- message formatting. Use javascript string templates if you need this.\n\n## Responsibility\n\n```\n+-----------------+                                               +-----------------+\n|  Application    |                                               |  Elasticsearch  |\n|                 |                           +--------------+    |                 |\n|     +--------+  |  stdout  +-----------+    | Log Ingester |    |                 |\n|     | logger |------------\u003e| Logstream |---\u003e|              |---\u003e|                 |\n|     +--------+  |  jsonl   |           |    |              |    |                 |\n+-----------------+          +-----------+    +--------------+    +-----------------+\n```\n\nThe logging framework inside an application is responsible for formatting logs as\nJSON lines and writing them to stdout as fast as possible. Data could be enriched\nwith level, timestamp or application names.\n\nThe Log Ingester adds additional data to log events, e.g. the ingestion time.\nIt can use a convention to derive the application name from the log stream name.\nThe Log Ingester is also responsible for handling unstructured data that might be\nwritten to log streams. For example, if a node process fails because\nof a missing dependency, node writes an unstructured error message.\nNo logging framework can handle this error message.\nHere is an example ingester for [AWS Logstreams and Elasticsearch](https://github.com/atombrenner/aws-log-to-elastic#readme).\n\n## Installation\n\n`npm i @atombrenner/log-json`\n\n## Usage\n\n```ts\nimport { log, setContext } from '@atombrenner/log-json'\n\nlog.info('message')\nlog.info('message')\nlog.info('message with structured data', { id: 4711, foo: 'bar' })\nlog.info('message with error', error)\nlog.info('message with data and error object', { id: 4711 }, error)\nlog.info(error) // error only\n\n// the usual console levels are available\nlog.debug('something')\nlog.info('something')\nlog.warn('something')\nlog.error('something')\n\n// use string templates for message formatting\nlog.info(`${method} ${path}`, { method, path })\n// -\u003e {\"msg\":\"GET /index.html\",\"method\":\"GET\",\"path\":\"/index.html\"}\n\n// add context to every log (mixin properties to every log)\nsetContext({ app: 'my-app' })\nlog.info('message') // -\u003e {\"app\":\"my-app\",\"msg\":\"message\"}\nlog.info('next message') // -\u003e {\"app\":\"my-app\",\"msg\":\"next message\"}\n\n// if you need a dynamic context, you can provide a function returning the context\nsetContext(() =\u003e {\n  heapTotal: process.memoryUsage().heapTotal\n})\nlog.info('message') // -\u003e {\"heapTotal\":6667453,msg:\"message\"}\n```\n\n## API\n\nThe signature for all logging functions is identical to `console.log`\n\n```ts\ntype LogFunction = (message: unknown, ...optional: unknown[])\n```\n\nArguments are processed from left to right. Every argument that is not a\nsimple object `{}` or `Error` gets converted to an object with a `msg` property.\nErrors are converted to objects with a `msg` and `stack` property.\nThen all objects are merged. Duplicate properties are overwritten by the\nrightmost one except for `msg`, where all values are concatenated.\n\nJSON logging is enabled if `NODE_ENV=production` or `AWS_LAMBDA_FUNCTION_NAME`\nhas a value. If `NODE_ENV=test` then all logs are swallowed to keep the output clean.\nOtherwise, we assume we run in a local development environment and pass all arguments\nunchanged to `console` methods.\nWhen running in AWS Lambda (detected by the presence of `process.env.AWS_LAMBDA_FUNCTION_NAME`)\ntimestamp and level are omitted because the AWS lambda environment adds those.\n\n### Examples of some edge cases\n\n```ts\nlog.info('Count', 42, 'Temperature') // -\u003e {\"msg\":\"Count 42 Temperature\"}\nlog.info(true, { hasData: false }) // -\u003e {\"msg\":\"true\",\"hasData\":\"false\"}\nlog.info('Failure:', new Error('reason')) // -\u003e {\"msg\":\"Failure: reason\",\"stack\":\"...\"}\nlog.info({msg: 'a', data: 1}, {msg: 'b', data: 2}) -\u003e // {\"msg\":\"a b\",\"data\":2}\n```\n\n## How to publish a new version\n\n1. `npm version \u003cmajor|minor|patch\u003e` (creates a git commit and tag)\n2. `npm publish` (implicitly calls `npm run prepare`)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatombrenner%2Fnpm-log-json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatombrenner%2Fnpm-log-json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatombrenner%2Fnpm-log-json/lists"}