{"id":27946086,"url":"https://github.com/logdna/logger-node","last_synced_at":"2025-05-07T13:48:04.345Z","repository":{"id":39989310,"uuid":"288208109","full_name":"logdna/logger-node","owner":"logdna","description":"A nodejs logger client for LogDNA","archived":false,"fork":false,"pushed_at":"2024-08-16T12:51:43.000Z","size":181,"stargazers_count":35,"open_issues_count":3,"forks_count":17,"subscribers_count":23,"default_branch":"main","last_synced_at":"2025-05-01T22:36:07.473Z","etag":null,"topics":["lib"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/logdna.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2020-08-17T14:52:50.000Z","updated_at":"2025-02-11T14:02:49.000Z","dependencies_parsed_at":"2024-10-31T04:02:32.713Z","dependency_job_id":"58294102-7b38-425c-83de-2a7680f84c39","html_url":"https://github.com/logdna/logger-node","commit_stats":{"total_commits":94,"total_committers":10,"mean_commits":9.4,"dds":"0.42553191489361697","last_synced_commit":"87463cbff9f6e64db596ce1f450bdd064bb1b22d"},"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logdna%2Flogger-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logdna%2Flogger-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logdna%2Flogger-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logdna%2Flogger-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/logdna","download_url":"https://codeload.github.com/logdna/logger-node/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252890536,"owners_count":21820408,"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":["lib"],"created_at":"2025-05-07T13:47:59.096Z","updated_at":"2025-05-07T13:48:04.338Z","avatar_url":"https://github.com/logdna.png","language":"JavaScript","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://app.logdna.com\"\u003e\n    \u003cimg height=\"95\" width=\"201\" src=\"https://raw.githubusercontent.com/logdna/artwork/master/logo%2Bnode.png\"\u003e\n  \u003c/a\u003e\n  \u003cp align=\"center\"\u003eNode.js library for logging to \u003ca href=\"https://logdna.com\"\u003eLogDNA\u003c/a\u003e\u003c/p\u003e\n\u003c/p\u003e\n\n[![Coverage Status](https://coveralls.io/repos/github/logdna/logger-node/badge.svg?branch=main)](https://coveralls.io/github/logdna/logger-node?branch=main)\n---\n\n* **[Migrating From Other Versions](#migrating-from-other-versions)**\n* **[Install](#install)**\n* **[Setup](#setup)**\n* **[Usage](#usage)**\n    * [Logging Errors](#logging-errors)\n* **[Default Log Levels](#default-log-levels)**\n* **[Custom Log Levels](#custom-log-levels)**\n* **[Convenience Methods](#convenience-methods)**\n* **[Events](#events)**\n    * [addMetaProperty](#event-addMetaProperty)\n    * [cleared](#event-cleared)\n    * [error](#event-error)\n        * [Error while sending to LogDNA](#error-while-sending-to-logdna)\n        * [Error while calling `log()`](#error-while-calling-log)\n        * [Error due to `payloadStructure` mismatch](#error-due-to-payloadstructure-mismatch)\n        * [Error for a `207` (partial success) response](#error-for-a-207-partial-success-response)\n    * [removeMetaProperty](#event-removeMetaProperty)\n    * [send](#event-send)\n    * [warn](#event-warn)\n        * [Warnings during `log()`](#warnings-during-log)\n        * [Warnings during `agentLog()`](#warnings-during-agentlog)\n        * [Warnings during `removeMetaProperty`](#warnings-during-removemetaproperty)\n* **[API](#api)**\n    * [createLogger](#createloggerkey-options)\n    * [setupDefaultLogger](#setupdefaultloggerkey-options)\n    * [logger.agentLog](#loggeragentlogopts)\n    * [logger.addMetaProperty](#loggeraddmetapropertykey-value)\n    * [logger.flush](#loggerflush)\n    * [logger.log](#loggerlogstatement-options)\n    * [logger.removeMetaProperty](#loggerremovemetapropertykey)\n* **[How Log Lines are Sent to LogDNA](#how-log-lines-are-sent-to-logdna)**\n* **[Exponential Backoff Strategy](#exponential-backoff-strategy)**\n* **[Best Practices](#best-practices)**\n* **[Client Side Support](#client-side)**\n* **[Bunyan Stream](#bunyan-stream)**\n* **[Winston Transport](#winston-transport)**\n* **[Using with AWS Lambda](#using-with-aws-lambda)**\n* **[Proxy Support](#proxy-support)**\n* **[License](#license)**\n* **[Contributing](#contributing)**\n\n## Migrating From Other Versions\n\nPrevious versions of this client are [still supported](https://github.com/logdna/nodejs), but if you are upgrading to this version, please see\nour [migration document](./docs/migrating-from-other-versions.md) for the differences between this version and prior versions.\n\n## Install\n\n```javascript\n$ npm install @logdna/logger\n```\n\n## Setup\n\nOperation requires a [LogDNA Ingestion Key](https://docs.logdna.com/docs/ingestion-key). Without it, the client will not be able to post\nlogs to the cloud. Please contact our support if you have questions about this setup process!\n\n## Usage\n\nTo use the client, create an instance, then call `.log()` or a [convenience method](#convenience-methods).\n\n```javascript\nconst logdna = require('@logdna/logger')\n\nconst options = {\n  app: 'myAppName'\n, level: 'debug' // set a default for when level is not provided in function calls\n}\n\nconst logger = logdna.createLogger('\u003cYOUR INGESTION KEY\u003e', options)\n\nlogger.log('This is an INFO statement', 'info')\n\nlogger.log('This will be a DEBUG statement, based on the default')\n\nlogger.log('This is an INFO statement with an options object', {\n  level: 'info'\n, meta: {\n    somekey: 'Arbitrary message'\n  , anotherkey: 'Another arbitrary message or data point'\n  }\n})\n\nlogger.info('This is an INFO statement using a convenience method')\n\n// Objects can be logged, too, but they're just serialized\nlogger.info({\n  message: 'Got some user data'\n, userId: req.params.userId // This assumes `req.params` comes from some HTTP framework\n})\n\n// Just sets `level: 'error'` automatically\nlogger.error('An error was encountered while processing user data')\n```\n\n### Logging Errors\n\nAlthough the logger can accept an object as its \"message\", `Error` instances contain\nnon-enumerable properties such that `log.error(err)` will not yield the expected results.\nTo mitigate this, users can trap (or generate) errors, then expose the error properties\nas desired.\n\nThis example hardcodes some JSON to parse, but it could easily come from user input.\n\n```javascript\nconst input = '{\"whoops\": \"This JSON is malformed because it\\'s missing a closing quote}'\ntry {\n  JSON.parse(input)\n} catch (err) {\n  log.error('JSON parse error while processing a string that should be JSON', {\n    indexMeta: true // Makes `meta` searchable. See docs below.\n  , meta: {\n      name: err.name\n    , message: err.message\n    , stack: err.stack\n    , input\n    }\n  })\n\n  // OR, if the all the details aren't important, a more concise log could be this\n  log.error(err.message, {\n    meta: {\n      message: 'JSON parse error during function xxx'\n    , input\n    }\n  })\n}\n```\n\n## Default Log Levels\n\nThe client supports the following log levels by default. They are case-insensitive. Users may also add [custom log levels](#custom-log-levels).\n\n* `TRACE`\n* `DEBUG`\n* `INFO`\n* `WARN`\n* `ERROR`\n* `FATAL`\n\n## Custom Log Levels\n\nUsers may provide an array of `levels` as a logger instantiation option. The `levels`\nvalue must be an array, and its values must be letters only. All level values are\nnormalized to upper-case when sent to the LogDNA server, but their use in function\ncalls is case-insensitive.\n\n```js\nconst {createLogger} = require('@logdna/logger')\nconst logger = createLogger(myKey, {\n  levels: ['info', 'warn', 'critical', 'catastrophic']\n})\n\nlogger.info('my text') // ok\nlogger.warn('some warning text') // ok\nlogger.catastrophic('OH NO!') // error\nlogger.log('OH NO!', 'critical') // ok\nlogger.log('We are crashing!', 'catastrophic') // ok\n```\n\n## Convenience Methods\n\nWe have set up convenience methods that automatically set the log level appropriately, and are easy to read. If using [custom log levels](#custom-log-levels), then convenience methods will\nonly be added for custom levels that also match the [default log levels](#default-log-levels), e.g. `log.info()`.\n\n### `logger.trace(msg[, options])`\n### `logger.debug(msg[, options])`\n### `logger.info(msg[, options])`\n### `logger.warn(msg[, options])`\n### `logger.error(msg[, options])`\n### `logger.fatal(msg[, options])`\n\n* `msg` [`\u003cObject\u003e`][] | [`\u003cString\u003e`][] - The message (or object) to log\n* `options` [`\u003cObject\u003e`][] - Per-message options. See [`logger.log()`](#loggerlogstatement-options) for those.\n\n## Events\n\nThe `Logger` is an `EventEmitter` and will emit events rather than use promises or callbacks to communicate its progress.\nListening to the events is optional, although an `error` listener is recommended.\n\n### Event: `'addMetaProperty'`\n\n* [`\u003cObject\u003e`][]\n    * `message` [`\u003cString\u003e`][] - Static message: `'Successfully added meta property'`\n    * `key` [`\u003cString\u003e`][] - The added key name\n    * `value` [`\u003cString\u003e`][] | [`\u003cNumber\u003e`][] | [`\u003cBoolean\u003e`][] | [`\u003cObject\u003e`][] | [`\u003cArray\u003e`][] - The value\n\nEmitted when a meta property is successfully added. This meta property will be attached to each log message.\n\n### Event: `'cleared'`\n\n* [`\u003cObject\u003e`][]\n    * `message` [`\u003cString\u003e`][] - A message indicating that everything was sent or that nothing needed to be sent\n\nWhen all log lines have been sent to LogDNA, this event is emitted. If it emits after lines have successfully been sent,\nthen the message will be `'All accumulated log entries have been sent'`. If there were no lines to be sent\n(for example, if `flush()` was called proactively), then the message will be `'All buffers clear; Nothing to send'`.\n\n\n### Event: `'error'`\n\n* [`\u003cTypeError\u003e`][] | [`\u003cError\u003e`][]\n    * `message` [`\u003cString\u003e`][] - The error message\n    * `meta` [`\u003cObject\u003e`][] - Meta object populated with different information depending on the error\n\nThis event is emitted when an asynchronous error is encountered. Depending on the context, `meta` will contain\ndifferent pieces of information about the error.  If the error is retry-able, the error's `message`\nproperty will indicate that it's a \"temporary\" error to avoid confusion with hard errors.\n\n#### Error while sending to LogDNA\n\n**Note:** `ignoreRetryableErrors` is `true` by default, and will not emit errors when\nthe `retrying` property in the metadata is `true`.  To emit all errors regardless of\n`retrying`, set `ignoreRetryableErrors: false`.\n\nThe metadata for an error encountered during an HTTP call to LogDNA will have the following `meta` properties in the error.\n\n* `actual` [`\u003cString\u003e`][] - The raw error message from the HTTP client\n* `code` [`\u003cString\u003e`][] | [`\u003cNumber\u003e`][] - The HTTP agent's \"code\" or `statusCode` value\n* `firstLine` [`\u003cString\u003e`][] - The first log line in the buffer that was sending\n* `lastLine` [`\u003cString\u003e`][] - The last log line in the buffer that was sending\n* `retrying` [`\u003cBoolean\u003e`][] - Whether an attempt will be made to resend the payload\n* `attempts` [`\u003cNumber\u003e`][] - The number of consecutive failures\n\n#### Error while calling `log()`\n\nWhen `log()` is called directly, or indirectly (via a convenience method), errors can be emitted if certain validations fail.\nIf an invalid log level is provided, or if a bad data type is found for the `options` parameter, the `meta` property of the error\nwill contain the following properties:\n\n* `got` [`\u003cString\u003e`][] - Description of the invalid input. Will depend on error context.\n* `expected` [`\u003cString\u003e`][] - The allowable log levels if `options` is an invalid log level\n* `used` [`\u003cString\u003e`][] - If a bad `level` is used in `options`, it will be ignored, and the default will be used.\n   This property indicates what that value is.\n\n#### Error due to `payloadStructure` mismatch\n\nWhen `log()` or `agentLog()` is called, the `payloadStructure` must be set appropriately.  If it is not, an error is emitted.\nKeep in mind that `agentLog()` is reserved for LogDNA systems and is not intended for public usage.\n\n* `message` [`\u003cString\u003e`][] - Static message of `Invalid method based on payloadStructure`\n* `payloadStructure` [`\u003cString\u003e`][] - The current payload structure value that is set on the instance\n* `expected` [`\u003cString\u003e`][] - The expected payload structure to be able to call the method.\n\n#### Error for a `207` (partial success) response\n\nIf a `207` status code is received, this means that some of the lines failed to be ingested.  An `error` event is emitted for each\nfailed line and will have the following structure:\n\n* `message` [`\u003cString\u003e`][] - Static message: `Non-200 status while ingesting this line`\n* `meta` [`\u003cObject\u003e`][] - Details about the failed line\n    * `statusCode` [`\u003cNumber\u003e`][] - The http status code for the failed line\n    * `line` [`\u003cString\u003e`][] - The line that failed to be ingested\n\n### Event: `'removeMetaProperty'`\n\n* [`\u003cObject\u003e`][]\n    * `message` [`\u003cString\u003e`][] - Static message: `'Successfully removed meta property'`\n    * `key` [`\u003cString\u003e`][] - The key that was removed\n\nThis is emitted when a key (and implied value) are removed from the global `meta` object. If the key does not exist,\nthen a [`warn`](#event-warn) event with the same signature will be emitted instead.\n\n\n### Event: `'send'`\n\n* [`\u003cObject\u003e`][]\n    * `httpStatus` [`\u003cString\u003e`][] - The `status` property of the HTTP agent's response\n    * `firstLine` [`\u003cString\u003e`][] - The first log line in the buffer that was sent\n    * `lastLine` [`\u003cString\u003e`][] - The last log line in the buffer that was sent\n    * `totalLinesSent` [`\u003cNumber\u003e`][] - The total number of lines in the sent buffer\n    * `totalLinesReady` [`\u003cNumber\u003e`][] - The number of lines left to be sent (if queueing has happened)\n    * `bufferCount` [`\u003cNumber\u003e`][] - The number of buffers left to be sent (if queueing has happened)\n\nThis event is emitted when a buffer is successfully sent to LogDNA. Since a buffer can contain many log entries, this event summarizes the activity.\nIn a high throughput system where `flushLimit` is exceeded and multiple buffers are waiting to be sent, information\nlike `totalLinesReady` and `bufferCount` help illustrate how much work is left to be done. Any buffers that have been queued will\nbe sent one after another, ignoring any flush timer.\n\n\n### Event: `'warn'`\n\n* [`\u003cObject\u003e`][]\n    * `message` [`\u003cString\u003e`][] - The warn message. Depends on context.\n\nThis event is emitted when there is no log data provided to the `log` method, or when `removeMetaProperty` is called with an unrecognized key.\nFor those cases, additional properties (apart from `message`) are included:\n\n#### Warnings during `log()`\n\n* `statement` (Any) - If `log()` was called with a `null` string or an invalid data type, this key will contain the given log statement.\n\n#### Warnings during `agentLog()`\n\n* `statement` (Any) - If `agentLog()` was called with a `null` string or an invalid data type, this key will contain the given log statement.\n\n#### Warnings during `removeMetaProperty`\n\n* `key` [`\u003cString\u003e`][] - The key that the command attempted to remove but that did not exist\n\n## API\n\n### `createLogger(key[, options])`\n\n* `key` [`\u003cString\u003e`][] - Your [ingestion key](https://docs.logdna.com/docs/ingestion-key)\n* `options` [`\u003cObject\u003e`][]\n    * `level` [`\u003cString\u003e`][] - [Level](#default-log-levels) to be used if not specified elsewhere. **Default:** `INFO`\n    * `levels` [`\u003cArray\u003e`][] - An array of custom log levels to use. **Default:** [Default log levels](#default-log-levels)\n    * `tags` [`\u003cArray\u003e`][] | [`\u003cString\u003e`][] - Tags to be added to each message\n    * `meta` [`\u003cObject\u003e`][] - Global metadata. Added to each message, unless overridden.\n    * `timeout` [`\u003cNumber\u003e`][] - Millisecond timeout for each HTTP request. **Default:** `30000`ms. **Max:** `300000`ms\n    * `hostname` [`\u003cString\u003e`][] - Hostname for each HTTP request.\n    * `mac` [`\u003cString\u003e`][] - MAC address for each HTTP request.\n    * `ip` [`\u003cString\u003e`][] - IPv4 or IPv6 address for each HTTP request.\n    * `url` [`\u003cString\u003e`][] - URL of the logging server. **Default:** `https://logs.logdna.com/logs/ingest`\n    * `flushLimit` [`\u003cNumber\u003e`][] - Maximum total line lengths before a `flush` is forced. **Default:** `5000000`\n    * `flushIntervalMs` [`\u003cNumber\u003e`][] - Mseconds to wait before sending the buffer. **Default:** `250`ms\n    * `shimProperties` [`\u003cArray\u003e`][] - List of dynamic `options` keys to look for when calling `log()`\n    * `indexMeta` [`\u003cBoolean\u003e`][] - Controls whether `meta` data for each message is searchable. **Default:** `false`\n    * `app` [`\u003cString\u003e`][] - Arbitrary app name for labeling each message. **Default:** `default`\n    * `env` [`\u003cString\u003e`][] - An environment label attached to each message\n    * `baseBackoffMs` [`\u003cNumber\u003e`][] - Minimum exponential backoff time in milliseconds. **Default:** `3000`ms\n    * `maxBackoffMs` [`\u003cNumber\u003e`][] - Maximum exponential backoff time in milliseconds. **Default:** `30000`ms\n    * `maxAttempts` [`\u003cNumber\u003e`][] - Maximum number of times the logger will try to send a buffer of messages when retryable errors are encountered; when the limit is reached, retryable errors will be treated as non-retryable errors.  **Default:** `-1`, meaning unlimited.\n    * `withCredentials` [`\u003cBoolean\u003e`][] - Passed to the request library to make CORS requests. **Default:** `false`\n    * `verboseEvents` [`\u003cBoolean\u003e`][] - Include the complete content of the buffer sent when emitting `send` and `error` events.  When this option is enabled, the events will include an additional `buffer` field which is an array of the messages and any metadata associated with those messages that were involved in the transmission that triggered the event.  **Default:** `false`\n    * `payloadStructure` [`\u003cString\u003e`][] - (*LogDNA usage only*) Ability to specify a different payload structure for ingestion. **Default:** `default`\n    * `compress` [`\u003cBoolean\u003e`][] - (*LogDNA usage only*) Compression support for the agent. **Default:** `false`\n    * `proxy` [`\u003cString\u003e`][] - The full URL of an http or https proxy to pass through\n    * `ignoreRetryableErrors` [`\u003cBoolean\u003e`][] - Do not emit \"errors\" that are retry-able. Typically, theses are\n      temporary connection-based errors. **Default:** `true`\n    * `sendUserAgent` [`\u003cBoolean\u003e`][] - This option controls the sending of our library's user-agent string\n      in HTTP requests to LogDNA. When this setting is `true` in a browser context, it may print a console\n      error although the payloads are still sent.  Setting this to `false` in a browser context will\n      retain the `user-agent` header of the browser. **Default:** `true`\n* Throws: [`\u003cTypeError\u003e`][] | [`\u003cTypeError\u003e`][] | [`\u003cError\u003e`][]\n* Returns: `Logger`\n\nReturns a logging instance to use. `flushLimit` and `flushIntervalMs` control when the buffer is sent to LogDNA.\nThe `flushIntervalMs` timer is only started after lines are logged, and the `flushLimit` is a size approximation based on the summation\nof `.length` properties of each log line. If the buffer size exceeds `flushLimit`, it will immediately send the buffer and ignore\nthe `flushIntervalMs` timer. Otherwise, a timer will repeatedly flush the buffer every `flushIntervalMs` milliseconds,\nas long as the buffer contains log entries.\n\nIf `indexMeta` is `false`, then the metadata will still appear in LogDNA search, but the fields themselves will not be searchable.\nIf this option is `true`, then meta objects will be parsed and searchable up to three levels deep. Any fields\ndeeper than three levels will be stringified and cannot be searched.\n**WARNING**: When this option is `true`, your metadata objects across all types of log messages *MUST* have consistent\ntypes, or the metadata object may not be parsed properly!\n\n`shimProperties` can be used to set up keys to look for in the `options` parameter of a `log()` call. If the specified keys\nare found in `options`, their key-values will be included the top-level of the final logging payload send to LogDNA.\n\n`payloadStructure` is only for LogDNA's use in other parts of the system such as our logging agent.\nIt is not intended to be used by public consumers, and it should be left to the default value.\n\nFor more information on the backoff algorithm and the options for it, see the [Exponential Backoff Strategy](#exponential-backoff-strategy) section.\n\n\n### `setupDefaultLogger(key[, options])`\n\nThe same as [`createLogger()`](#createloggerkey-options), except for that it creates a singleton that will be reused if called again.\nUsers can call this multiple times, and the client package will maintain (create and/or return) the singleton.\n\nNote that only the first call will instantiate a new instance. Therefore, any successive calls will ignore the provided parameters.\n\n```javascript\nconst logdna = require('@logdna/logger')\n\nconst logger = logdna.setupDefaultLogger('\u003cYOUR KEY HERE\u003e')\nconst sameLogger = logdna.setupDefaultLogger()\n```\n\n### `logger.agentLog(opts)`\n\nThis method is for use exclusively by LogDNA, and is not intended for public logging.\n\n* Emits: [error](#event-error)\n\n### `logger.addMetaProperty(key, value)`\n\n* `key` [`\u003cString\u003e`][] - The meta property's key\n* `value` [`\u003cString\u003e`][] | [`\u003cNumber\u003e`][] | [`\u003cBoolean\u003e`][] | [`\u003cObject\u003e`][] | [`\u003cArray\u003e`][] - The meta property's value\n* Emits: [`addMetaProperty`](#event-addmetaproperty)\n\nThis method adds a key-value to the global metadata, which is added to each log entry upon calling `log()`.\nAlthough `meta` can be set on instantiation, this method provides a way to update it on-the-fly.\n\nIf `options.meta` is also used in a `log()` call, the key-value pairs from the global `meta` will be merged with\n`options.meta`, and those new pairs will take precedence over any matching keys in the global metadata.\n\n```javascript\n// This will use `meta` to track logs from different modules\nconst logger = createLogger('\u003cYOUR API KEY\u003e', {\n  meta: {\n    module: 'main.js' // Global default\n  }\n})\n\nlogger.debug('This is the main module') // Uses global meta\n\n// ... elsewhere, in another file, perhaps\nlogger.info('I am in module1.js', {\n  meta: {module: __filename} // Overrides global meta\n})\n```\n\n### `logger.flush()`\n\n* Emits: [`cleared`](#event-cleared)\n\nWhen `flush` is called, any messages in the buffer are sent to LogDNA. It's not necessary to call this manually, although it is useful\nto do so to ensure clean shutdown (see [Best Practices](#best-practices)). When `log` is called, it automatically starts a timer\nthat will call `flush`, but it is idempotent and can be called at any time.\n\nIf log lines exist in the current buffer, it is pushed onto a send queue, and a new buffer is created. The send queue is processed and uploaded to LogDNA.\n\nIf no work needs to be done, the `cleared` event is immediately emitted.\n\n### `logger.log(statement[, options])`\n\n* `statement` [`\u003cString\u003e`][] | [`\u003cObject\u003e`][] - Text or object of the log entry. Objects are serialized.\n* `options` [`\u003cString\u003e`][] | [`\u003cObject\u003e`][] - A string representing a [level](#default-log-levels) or an object with the following elements:\n    * `level` [`\u003cString\u003e`][] - Desired [level](#default-log-levels) for the current message. **Default:** `logger.level`\n    * `app` [`\u003cString\u003e`][] - App name to use for the current message. **Default:** `logger.app`\n    * `env` [`\u003cString\u003e`][] - Environement name to use for the current message. **Default:** `logger.env`\n    * `timestamp` [`\u003cNumber\u003e`][] - Epoch ms time to use for the current message. Must be within 24 hours. **Default:** `Date.now()`\n    * `context` [`\u003cObject\u003e`][] - Synonym for `meta`, but mutually exclusive. Ignored if `meta` exists.\n    * `indexMeta` [`\u003cBoolean\u003e`][] - Allows for the `meta` to be searchable in LogDNA. **Default:** `logger.indexMeta`\n    * `meta` [`\u003cObject\u003e`][] - Per-message meta data. Combined with key-values created with `addMetaProperty`\n* Emits: [warn](#event-warn), [error](#event-error)\n\nSends a string or object to LogDNA for storage. If the [convenience methods](#convenience-methods) are used, they call this function\nunder the hood, so the options are the same. The only difference is that `level` is automatically set in the convenience methods.\n\n### `logger.removeMetaProperty(key)`\n\n* `key` [`\u003cString\u003e`][] - The key (and implied value) to be removed from the global `meta` object.\n* Emits: [`warn`](#event-warn)\n\nAttempts to remove the given key from the global `meta` data object. If the key is not found, `warn` is emitted.\n\n## How Log Lines are Sent to LogDNA\n\nIn default operation, when `log` functions are called, the line is added to a buffer to cut down on HTTP traffic to the server.\nThe buffer is flushed every `flushIntervalMs` milliseconds or if the log line lengths grow beyond `flushLimit`.\n\nWhen `flush` fires (or is called manually), the current buffer is put onto a send queue, and a new buffer is started. The send queue begins\nsending to LogDNA. It will continue to send without pausing or honoring `flushIntervalMs` as long as there are buffers in the send queue.\nWhen the send queue is empty, `cleared` is emitted.\n\n### Handling Errors\n\n* If a `207` status code was received, this means that at least one line failed ingestion. Each offending line and its status code\n  will be emitted as [an error](#error-for-a-207-partial-success-response).\n* User-level errors (such as `400`) will not be retried because they most likely would never be successful (if the message is deemed invalid),\n  and `error` events are emitted for these errors, also.\n* Connection-based errors or `500`-level response status codes will be retried using an [exponential backoff strategy](#exponential-backoff-strategy), but will\n  also emit `error` events along the way.\n    * Connection error codes that will retry:\n      `ECONNABORTED` (timeout),\n      `ECONNRESET`,\n      `EADDRINUSE`,\n      `ECONNREFUSED`,\n      `EPIPE`,\n      `ENOTFOUND`,\n      `ENETUNREACH`\n    * HTTP status codes that will retry:\n      `500`,\n      `502`,\n      `503`,\n      `504`,\n      `521`,\n      `522`,\n      `524`\n\n## Exponential Backoff Strategy\n\nWhen HTTP failures happen, if they are deemed \"retryable\" (non-user errors), then the client will pause for a short time before\ntrying to resend. The algorithm it implements is an exponential backoff with a \"jitter\" strategy that uses random numbers statistically to\nspread out the wait times to avoid flooding.\n\nThe settings for `baseBackoffMs` and `maxBackoffMs` are used in this algorithm and serve as the lower and upper boundaries for the wait time.\n\nThese types of errors are blocking since they are related to timeouts and server errors. Logs will continue to buffer as normal, and\nif the HTTP calls becomes successful, they will begin to send immediately, and without pause.\n\n## Best Practices\n\n* The client is optimized for high throughput. Using a single instance is no problem, but multiple instances can be created with the same key if desired.\n* Set up an `error` listener so that your app is aware of problems. Things like HTTP errors are emitted this way.\n* When shutting down your application, ensure all log entries are flushed by waiting for a final `cleared`\n  event during shutdown:\n\n```javascript\nconst {createLogger} = require('@logdna/logger')\nconst {once} = require('events')\nconst process = require('process')\n\nconst logger = createLogger('This is not a real key and will cause an error')\n\nlogger.on('error', console.error)\n\nfunction onSignal(signal) {\n  logger.warn(`received signal ${signal} shutting down`, {meta: {signal}})\n  shutdown().catch(() =\u003e {})\n}\n\nasync function shutdown() {\n  await once(logger, 'cleared')\n}\n\nprocess.on('SIGTERM', onSignal)\nprocess.on('SIGINT', onSignal)\n\n// For running this as a standalone example, an error will be shown due\n// to the key being invalid, but it shows the signal handler message\n// attempting to be sent for ingestion.\nsetTimeout(() =\u003e {\n  process.kill(process.pid)\n}, 1000)\n```\n\n## Client Side\n\nFor logging from a browser, we recommend our [@logdna/browser](https://github.com/logdna/logdna-browser) package which is designed for that purpose.\n\n## Bunyan Stream\n\nFor Bunyan Stream support, reference our [logdna-bunyan](https://github.com/logdna/logdna-bunyan/) module.\n\n## Winston Transport\n\nFor Winston support, reference our [logdna-winston](https://github.com/logdna/logdna-winston/) module.\n\n## Using with AWS Lambda\n\nAWS Lambda relays `stdout` and `stderr` output from your function's code to CloudWatch,\nbut you can easily set up a `Logger` instance as shown above to send logs to LogDNA instead.\nIf you have existing code that uses `console.log` and `console.error` statements, you can\nalso override these `console` methods to send output to LogDNA without changing your code:\n\n```javascript\n'use strict'\n\nconst {once} = require('events')\nconst {createLogger} = require('@logdna/logger')\n\nconst options = {\n  env: 'env'\n, app: 'lambda-app'\n, hostname: 'lambda-test'\n}\nconst logger = createLogger('API KEY HERE', options)\n\n// Override console methods to send logs to both LogDNA and stdout/stderr\nconst {\n  log: consoleLog\n, error: consoleError\n} = console\n\nconsole.log = function(message, ...args) {\n  logger.log(message)\n  consoleLog(message, ...args)\n}\n\nconsole.error = function(message, ...args) {\n  logger.error(message)\n  consoleError(message, ...args)\n}\n\nexports.handler = async function handler(event, context) {\n  logger.on('error', consoleError)\n\n  // Your code here\n  console.log('Informational log')\n  console.log({\n    example: 'this is a sample object log'\n  })\n  console.error('Error log')\n\n  // Ensure logs have been flushed to LogDNA before finishing\n  await once(logger, 'cleared')\n}\n```\n\n## Proxy Support\n\nThe logger supports proxying for situations such as corporate proxies that require traffic\nto be passed through them before reaching the outside world.  For such implementations,\nuse the [`proxy` instantiation option](#createloggerkey-options) to set the full URL\nof the proxy.  It supports both *http* and *https* proxy URLs.  Under the hood, the logger uses\nthe [https-proxy-agent](https://www.npmjs.com/package/https-proxy-agent) package for this.\n\nIn this example, an http proxy (with credentials) is passed through before reaching LogDNA's\nsecure ingestion endpoint:\n\n```javascript\nconst {createLogger} = require('@logdna/logger')\n\nconst logger = createLogger(apiKey, {\n  proxy: 'http://username:pass@yourproxy.company.com:12345'\n, app: 'myapp'\n})\n\nlogger.info('Happy logging through your proxy!')\n```\n\n## License\n\nCopyright © [LogDNA](https://logdna.com), released under an MIT license. See the [LICENSE](./LICENSE) file and https://opensource.org/licenses/MIT\n\n*Happy Logging!*\n\n## Contributing\n\nThis project is open-sourced, and accepts PRs from the public for bugs or feature\nenhancements. These are the guidelines for contributing:\n\n* The project uses [Commitlint][] and enforces [Conventional Commit Standard][]. Please format your commits based on these guidelines.\n* An [issue must be opened](https://github.com/logdna/logger-node/issues) in the repository for any bug, feature, or anything else that will have a PR\n  * The commit message must reference the issue with an [acceptable action tag](https://github.com/logdna/commitlint-config/blob/41aef3b69f292e39fb41a5ef24bcd7043e0fceb3/index.js#L12-L20) in the commit footer, e.g. `Fixes: #5`\n\n\n[`\u003cBoolean\u003e`]: https://mdn.io/boolean\n[`\u003cNumber\u003e`]: https://mdn.io/number\n[`\u003cObject\u003e`]: https://mdn.io/object\n[`\u003cString\u003e`]: https://mdn.io/string\n[`\u003cArray\u003e`]: https://mdn.io/array\n[`\u003cTypeError\u003e`]: https://mdn.io/TypeError\n[`\u003cRangeError\u003e`]: https://mdn.io/RangeError\n[`\u003cError\u003e`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error\n[Commitlint]: https://commitlint.js.org\n[Conventional Commit Standard]: https://www.conventionalcommits.org/en/v1.0.0/\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/darinspivey\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1874788?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDarin Spivey\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/logdna/logger-node/commits?author=darinspivey\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/logdna/logger-node/commits?author=darinspivey\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#maintenance-darinspivey\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/logdna/logger-node/commits?author=darinspivey\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"#ideas-darinspivey\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://pxl.blue/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/59253100?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003erelative\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/logdna/logger-node/commits?author=relative\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/ligerzero459\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1093351?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRyan Mottley\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#maintenance-ligerzero459\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/alanzchen\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/2144783?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlan Chen\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/logdna/logger-node/commits?author=alanzchen\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/mdeltito\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/69520?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMike Del Tito\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/logdna/logger-node/commits?author=mdeltito\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://www.designveloper.com/vi/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/51075198?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eNhut Tran\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/logdna/logger-node/commits?author=nhuttm\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://codedependant.net/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/148561?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eEric Satterwhite\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/logdna/logger-node/commits?author=esatterwhite\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogdna%2Flogger-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flogdna%2Flogger-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogdna%2Flogger-node/lists"}