{"id":17328,"library":"pino-http-send","title":"Pino HTTP Log Transport","description":"pino-http-send is a basic handler for Pino logs that facilitates sending batches of structured log data to a desired HTTP or HTTPS endpoint. Currently at version 0.4.2, it is pre-v1, meaning minor version changes may introduce breaking changes. The library supports configurable HTTP methods (POST, PUT, PATCH, GET), two body types (JSON array wrapped in a 'logs' object or newline-delimited JSON), and includes basic authentication and retry mechanisms for failed sends. It can be used either as a command-line interface tool, piping `pino` output directly, or programmatically via its `createWriteStream` API, which acts as a Pino destination. Its key differentiators include its simplicity in setting up a direct HTTP log sink, batching capabilities to optimize network requests, and built-in retry logic, making it a robust, low-overhead option for forwarding Pino logs.","status":"active","version":"0.4.2","language":"javascript","source_language":"en","source_url":"https://github.com/technicallyjosh/pino-http-send","tags":["javascript","pino","logging","transport","http","typescript"],"install":[{"cmd":"npm install pino-http-send","lang":"bash","label":"npm"},{"cmd":"yarn add pino-http-send","lang":"bash","label":"yarn"},{"cmd":"pnpm add pino-http-send","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"This package acts as a transport for Pino logs; `pino` is required to generate the logs that `pino-http-send` will process and send.","package":"pino","optional":false}],"imports":[{"note":"While CommonJS `require` works, ESM `import` is preferred in modern Node.js environments. The function is a named export.","wrong":"const createWriteStream = require('pino-http-send').createWriteStream;","symbol":"createWriteStream","correct":"import { createWriteStream } from 'pino-http-send';"},{"note":"The options for `createWriteStream` are type-exported as PinoHttpSendOptions for TypeScript users, enabling strong typing for configuration.","symbol":"PinoHttpSendOptions","correct":"import type { PinoHttpSendOptions } from 'pino-http-send';"}],"quickstart":{"code":"import { createWriteStream } from 'pino-http-send';\nimport pino from 'pino';\nimport http from 'http';\n\n// 1. Setup a dummy HTTP server to receive logs (your actual log ingestion endpoint)\nconst server = http.createServer((req, res) => {\n  if (req.url === '/logs' && req.method === 'POST') {\n    let body = '';\n    req.on('data', (chunk) => { body += chunk.toString(); });\n    req.on('end', () => {\n      try {\n        console.log(`\\n--- Received Batch (${req.headers['content-type']}) ---\\n`);\n        if (req.headers['content-type']?.includes('application/json')) {\n          console.log(JSON.parse(body).logs); // 'json' bodyType wraps logs in { logs: [...] }\n        } else {\n          console.log(body); // 'ndjson' is raw new-line delimited JSON\n        }\n        console.log(`--- End Batch ---\\n`);\n        res.writeHead(200, { 'Content-Type': 'application/json' });\n        res.end(JSON.stringify({ status: 'ok', receivedLogsCount: body.split('\\n').filter(Boolean).length }));\n      } catch (e) {\n        console.error('Error parsing received logs:', e);\n        res.writeHead(400).end('Bad Request');\n      }\n    });\n  } else {\n    res.writeHead(404).end('Not Found');\n  }\n});\n\nserver.listen(3000, () => {\n  console.log('Dummy log server listening on http://localhost:3000');\n  console.log('Sending logs via pino-http-send...');\n\n  // 2. Configure pino-http-send as a Pino destination\n  const pinoSendStream = createWriteStream({\n    url: 'http://localhost:3000/logs',\n    method: 'POST',\n    bodyType: 'json', // or 'ndjson'\n    batchSize: 2,      // Send every 2 logs\n    timeout: 1000,     // or flush after 1 second if batch not full\n    log: true,         // Enable internal logging for pino-http-send itself\n    headers: { 'X-Custom-Header': 'pino-test' }\n  });\n\n  // 3. Create a Pino logger instance using the pino-http-send stream\n  const logger = pino(pinoSendStream);\n\n  let count = 0;\n  const interval = setInterval(() => {\n    logger.info({ id: ++count, service: 'my-app', event: 'data_processed', timestamp: new Date().toISOString() });\n    if (count >= 5) {\n      clearInterval(interval);\n      logger.flush(); // Ensure any buffered logs are sent\n      setTimeout(() => {\n        server.close(() => console.log('Dummy server closed. Exiting.'));\n      }, 2000); // Give time for the last batch to be sent\n    }\n  }, 500);\n});","lang":"typescript","description":"Demonstrates programmatic usage of `pino-http-send` by creating a dummy HTTP server to receive logs and configuring Pino to send logs to it via `createWriteStream`."},"warnings":[{"fix":"Always pin to exact minor versions (e.g., `~0.4.0` or `0.4.2`) and review release notes carefully before upgrading minor versions.","message":"As a pre-v1 package (current version 0.4.2), `pino-http-send` explicitly states that it is 'subject to breaking changes on minor version change'. Users should expect potential API shifts and review changelogs when updating.","severity":"breaking","affected_versions":">=0.1.0"},{"fix":"For custom headers, use the `createWriteStream` API and pass a `headers` object in the options. Example: `createWriteStream({ url: '...', headers: { 'Authorization': 'Bearer YOUR_TOKEN' } })`.","message":"The CLI usage for `pino-http-send` only supports basic authentication via `--username` and `--password` flags. Custom HTTP headers for authentication (e.g., Bearer tokens) or other purposes are not supported via the CLI and must be configured when using the programmatic `createWriteStream` API.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Ensure your log ingestion endpoint is aware of and correctly parses the specific `bodyType` used by `pino-http-send`. If `json` is used, it should expect an object with a `logs` property containing the array. If `ndjson` is used, it should parse each line as a separate JSON object.","message":"When using `bodyType: 'json'`, `pino-http-send` wraps the batch of logs in an object with a `logs` key (e.g., `{ logs: [...] }`). If your receiving endpoint expects a direct JSON array of logs, this will cause parsing issues. Conversely, `ndjson` sends new-line delimited JSON objects.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Specify the target URL using `--url` or `-u` flag. Example: `pino-http-send --url=http://your-log-endpoint.com/logs`.","cause":"Attempting to run `pino-http-send` via the CLI without providing the `--url` argument, which is mandatory.","error":"Error: Missing required argument: url"},{"fix":"Ensure `createWriteStream` is imported as a named export. For ESM: `import { createWriteStream } from 'pino-http-send';`. For CommonJS: `const { createWriteStream } = require('pino-http-send');`.","cause":"Incorrectly importing `createWriteStream` using a default import or a CommonJS `require` statement that expects a default export.","error":"TypeError: createWriteStream is not a function"},{"fix":"Verify that the `bodyType` option (`json` or `ndjson`) passed to `createWriteStream` or the CLI `--bodyType` flag matches the format your log ingestion endpoint is designed to consume. Adjust either the client configuration or the server's parsing logic accordingly.","cause":"Mismatch between the `bodyType` configured in `pino-http-send` (e.g., 'json') and what the receiving server expects (e.g., 'ndjson' or a raw array).","error":"Received logs are not in expected format (e.g., missing 'logs' array or not NDJSON)"}],"ecosystem":"npm","meta_description":null}