Gathering detailed insights and metrics for cabin
Gathering detailed insights and metrics for cabin
Gathering detailed insights and metrics for cabin
Gathering detailed insights and metrics for cabin
🌲 Cabin is the best self-hosted JavaScript and Node.js logging service. Made for @forwardemail.
npm install cabin
Typescript
Module System
Min. Node Version
Node Version
NPM Version
JavaScript (87.4%)
HTML (11.7%)
Shell (0.9%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
891 Stars
296 Commits
44 Forks
6 Watchers
1 Branches
9 Contributors
Updated on Jul 11, 2025
Latest Version
14.0.0
Package Id
cabin@14.0.0
Unpacked Size
133.09 kB
Size
37.83 kB
File Count
9
NPM Version
10.7.0
Node Version
18.20.4
Published on
Nov 26, 2024
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
10
1
35
Please defer to Axe's Foreword for more insight.
Cabin is a layer on top of Axe that provides automatic logging for route middleware requests and errors.
1npm install express axe cabin signale
1const express = require('express'); 2const Axe = require('axe'); 3const Cabin = require('cabin'); 4const app = express(); 5const { Signale } = require('signale'); 6 7// initialize a new instance of Axe (see below TODO's that appeal to you) 8const logger = new Axe({ 9 logger: new Signale() 10}); 11 12// TODO: if you want to send logs to an HTTP endpoint then follow this guide: 13// https://github.com/cabinjs/axe/#send-logs-to-http-endpoint 14 15// TODO: if you want to send logs to Slack then follow this guide: 16// https://github.com/cabinjs/axe/#send-logs-to-slack 17 18// TODO: if you want to send logs to Sentry then follow this guide: 19// https://github.com/cabinjs/axe/#send-logs-to-sentry 20 21// TODO: if you want to send logs to Datadog then follow this guide: 22// https://github.com/cabinjs/axe/#send-logs-to-datadog 23 24// TODO: if you want to send logs to Papertrail then follow this guide: 25// https://github.com/cabinjs/axe/#send-logs-to-papertrail 26 27// TODO: if you want to suppress specific log metadata then follow this guide: 28// https://github.com/cabinjs/axe/#suppress-logger-data 29 30// initialize a new instance of Cabin with an Axe logger instance 31const cabin = new Cabin({ logger }); 32 33// 34// initialize route logging middleware 35// 36// NOTE: this will automatically log route middleware requests and errors 37// 38app.use(cabin.middleware); 39 40app.get('/', (req, res, next) => res.send('OK')); 41 42// start the server 43app.listen(3000);
1curl http://localhost:3000
Cabin will automatically detect and mask the following list of extremely sensitive types of data in your logs:
*Credit card numbers from the following providers are automatically detected and masked: Visa, Mastercard, American Express, Diners Club, Discover, JCB, UnionPay, Maestro, Mir, Elo, Hiper, Hipercard
Reduce your disk storage costs through Cabin's automatic conversion of Streams, Buffers, and ArrayBuffers to simplified, descriptive-only objects that otherwise would be unreadable (and obviously pollute your log files and disk storage).
Before:
1{ 2 "request": { 3 "body": { 4 "file": { 5 "type": "Buffer", 6 "data": [ 7 76, 8 111, 9 114, 10 101, 11 109, 12 32, 13 105, 14 112, 15 115, 16 117, 17 109, 18 32, 19 100, 20 111, 21 108, 22 111, 23 114, 24 32, 25 115, 26 105, 27 116, 28 '...' 29 ] 30 } 31 } 32 } 33}
After
1{ 2 "request": { 3 "body": { 4 "file": { 5 "type": "Buffer", 6 "byteLength": 2787 7 } 8 } 9 } 10}
Cabin works with the most popular Node.js HTTP frameworks (e.g. Express and Koa), request body handling packages (e.g. multer and body-parser), and the passport authentication framework.
It supports Node v18+ and modern browsers out of the box (its browser-ready bundle is only 20 KB).
1npx browserslist
1and_chr 107 2and_ff 106 3and_qq 13.1 4and_uc 13.4 5android 107 6chrome 107 7chrome 106 8chrome 105 9edge 107 10edge 106 11edge 105 12firefox 106 13firefox 105 14firefox 102 15ios_saf 16.1 16ios_saf 16.0 17ios_saf 15.6 18ios_saf 15.5 19ios_saf 14.5-14.8 20kaios 2.5 21op_mini all 22op_mob 64 23opera 91 24opera 90 25safari 16.1 26safari 16.0 27safari 15.6 28samsung 18.0 29samsung 17.0
See the Quick Start section above and our guide at https://github.com/cabinjs/axe/#send-logs-to-http-endpoint.
See the Quick Start section above and our guide at https://github.com/cabinjs/axe/#send-logs-to-slack.
See the Quick Start section above and our guide at https://github.com/cabinjs/axe/#send-logs-to-sentry.
See the Quick Start section above and our guide at https://github.com/cabinjs/axe/#send-logs-to-datadog.
See the Quick Start section above and our guide at https://github.com/cabinjs/axe/#send-logs-to-papertrail.
See the Quick Start section above and our guide at https://github.com/cabinjs/axe/#suppress-logger-data.
Note that as of v11.0.0 Cabin requires a peer dependency of Axe to be installed.
npm:
1npm install cabin axe
1const Cabin = require('cabin'); 2const cabin = new Cabin({ 3 // ... see the Quick Start and Options sections 4}); 5 6cabin.info('hello world'); 7cabin.error(new Error('oops!'));
1app.use(cabin.middleware);
See either the Node or Browser instructions below for further route middleware usage and proper setup.
The examples below show how to use Cabin in combination with Axe, Signale (instead of
console
), and how to add an accurateX-Response-Time
response time metric to your logs and response headers automatically.
Install required and recommended dependencies:
1npm install koa cabin signale request-received koa-better-response-time koa-better-request-id
Implement the example code below (also found here):
1const Koa = require('koa'); 2const Cabin = require('cabin'); 3const Router = require('koa-router'); 4const requestReceived = require('request-received'); 5const responseTime = require('koa-better-response-time'); 6const requestId = require('koa-better-request-id'); 7const { Signale } = require('signale'); 8 9const app = new Koa(); 10const router = new Router(); 11const cabin = new Cabin({ 12 logger: new Signale() 13}); 14 15// adds request received hrtime and date symbols to request object 16// (which is used by Cabin internally to add `request.timestamp` to logs 17app.use(requestReceived); 18 19// adds `X-Response-Time` header to responses 20app.use(responseTime()); 21 22// adds or re-uses `X-Request-Id` header 23app.use(requestId()); 24 25// use the cabin middleware (adds request-based logging and helpers) 26app.use(cabin.middleware); 27 28// add your user/session management middleware here (e.g. passport) 29// ... 30 31// an example home page route 32router.get('/', ctx => { 33 ctx.logger.info('visited home page'); 34 ctx.body = 'hello world'; 35}); 36 37// this assumes that you are using passport which 38// exposes `ctx.logout` to log out the logged in user 39router.get('/logout', ctx => { 40 ctx.logger.warn('Logged out'); 41 ctx.logout(); 42 ctx.redirect('/'); 43}); 44 45app.use(router.routes()); 46app.use(router.allowedMethods()); 47 48app.listen(3000, () => { 49 cabin.info('app started'); 50});
See Koa convenience methods below for helper utilities you can use while writing code.
Install required and recommended dependencies:
1npm install express cabin signale request-received response-time express-request-id
Implement the example code below (also found here):
1const express = require('express'); 2const Cabin = require('cabin'); 3const requestReceived = require('request-received'); 4const responseTime = require('response-time'); 5const requestId = require('express-request-id'); 6const { Signale } = require('signale'); 7 8const app = express(); 9const cabin = new Cabin({ 10 logger: new Signale() 11}); 12 13// adds request received hrtime and date symbols to request object 14// (which is used by Cabin internally to add `request.timestamp` to logs 15app.use(requestReceived); 16 17// adds `X-Response-Time` header to responses 18app.use(responseTime()); 19 20// adds or re-uses `X-Request-Id` header 21app.use(requestId()); 22 23// use the cabin middleware (adds request-based logging and helpers) 24app.use(cabin.middleware); 25 26// add your user/session management middleware here (e.g. passport) 27// ... 28 29// an example home page route 30app.get('/', (req, res) => { 31 req.logger.info('visited home page'); 32 res.send('hello world'); 33}); 34 35// this assumes that you are using passport which 36// exposes `req.logout` to log out the logged in user 37app.get('/logout', (req, res) => { 38 req.logger.warn('logged out'); 39 req.logout(); 40 res.redirect('/'); 41}); 42 43app.listen(3000, () => { 44 cabin.info('app started'); 45});
See Express convenience methods below for helper utilities you can use while writing code.
In order to easily interact and use the logger
utility function exposed by app.use(cabin.middleware)
, we expose convenient helper methods in Express and Koa:
req.log
req.logger
res.log
res.logger
ctx.log
ctx.logger
ctx.request.log
ctx.request.logger
ctx.response.log
ctx.response.logger
This package requires Promise support, therefore you will need to polyfill if you are using an unsupported browser (namely Opera mini).
We no longer support IE as of Cabin v10.0.0+.
This is the solution for you if you're just using <script>
tags everywhere!
1<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=Promise"></script> 2<script src="https://unpkg.com/cabin"></script> 3<script type="text/javascript"> 4 (function() { 5 var cabin = new Cabin(); 6 cabin.setUser({ 7 id: '1', 8 email: 'test@example.com', 9 full_name: 'Test' 10 }); 11 cabin.info('viewed docs'); 12 })(); 13</script>
We recommend using https://cdnjs.cloudflare.com/polyfill (specifically with the bundle mentioned in VanillaJS above):
1<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=Promise"></script>
This assumes you are using browserify, webpack, rollup, or another bundler.
1const Cabin = require('cabin'); 2 3const cabin = new Cabin(); 4 5cabin.setUser({ 6 id: '1', 7 email: 'test@example.com', 8 full_name: 'Test' 9}); 10 11cabin.info('viewed docs');
For server-side logging of requests, the Cabin middleware cabin.middleware
will automatically log requests for you upon completion. Just make sure you are using express-request-id
middleware like in the examples above in order for the X-Request-Id
header to be set (and re-used if already exists, e.g. generated from client side as in below). If you're using Koa make sure to use koa-better-request-id
as shown in the examples above.
We strongly recommend that you implement one of the following code snippets with xhook (for either VanillaJS or Bundler approaches) so that all your XHR requests have a X-Request-Id
automatically added (which in turn ensures both client and server have matching request ID's). Imagine how awesome your logs will be when you can see the full trace starting with the client!
1<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=Promise"></script> 2<script src="https://unpkg.com/xhook"></script> 3<script src="https://unpkg.com/cabin"></script> 4<script src="https://unpkg.com/parse-request"></script> 5<script src="https://unpkg.com/cuid"></script> 6<script> 7 (function() { 8 var cabin = new Cabin(); 9 cabin.setUser({ 10 id: '1', 11 email: 'test@example.com', 12 full_name: 'Test' 13 }); 14 xhook.before(function(req) { 15 if (typeof req.headers !== 'object') req.headers = {}; 16 17 if (!req.headers['X-Request-Id']) 18 req.headers['X-Request-Id'] = cuid(); 19 20 if (!req.headers['User-Agent']) 21 req.headers['User-Agent'] = window.navigator.userAgent; 22 23 if (!req.headers['Referer']) 24 req.headers['Referer'] = window.document.referrer; 25 26 if (!req.headers['Cookie']) 27 req.headers['Cookie'] = window.document.cookie; 28 29 cabin.info('xhr', parseRequest({ req: req })); 30 }); 31 })(); 32</script>
You can do a similar approach with React, EJS, or another templating language.
1script(src='https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=Promise') 2script(src='https://unpkg.com/xhook') 3script(src='https://unpkg.com/cabin') 4script(src='https://unpkg.com/parse-request') 5script(src='https://unpkg.com/cuid') 6script. 7 (function() { 8 var cabin = new Cabin(); 9 cabin.setUser({ 10 id: '1', 11 email: 'test@example.com', 12 full_name: 'Test' 13 }); 14 xhook.before(function(req) { 15 if (typeof req.headers !== 'object') req.headers = {}; 16 17 if (!req.headers['X-Request-Id']) 18 req.headers['X-Request-Id'] = cuid(); 19 20 if (!req.headers['X-Request-Id']) 21 req.headers['X-Request-Id'] = cuid(); 22 23 if (!req.headers['User-Agent']) 24 req.headers['User-Agent'] = window.navigator.userAgent; 25 26 if (!req.headers['Referer']) 27 req.headers['Referer'] = window.document.referrer; 28 29 if (!req.headers['Cookie']) 30 req.headers['Cookie'] = window.document.cookie; 31 32 cabin.info('xhr', parseRequest({ req: req })); 33 }); 34 })();
npm:
1npm install cabin xhook cuid
1const Cabin = require('cabin'); 2const xhook = require('xhook'); 3const parseRequest = require('parse-request'); 4const cuid = require('cuid'); 5 6const cabin = new Cabin(); 7 8cabin.setUser({ 9 id: '1', 10 email: 'test@example.com', 11 full_name: 'Test' 12}); 13 14xhook.before(req => { 15 if (typeof req.headers !== 'object') req.headers = {}; 16 17 if (!req.headers['X-Request-Id']) 18 req.headers['X-Request-Id'] = cuid(); 19 20 // 21 // NOTE: you may want to add User-Agent, Referer, and Cookie (see above) 22 // 23 cabin.info('xhr', parseRequest({ req: req })); 24});
We leave it up to you to decide how you wish to handle stack traces and errors, but we've documented our approaches for Node and Browser environments below.
If you're using Lad, then you don't need to worry about error handling, as it's built-in (complete with graceful reloading, even for database connections).
However you can otherwise use a tool such as uncaught to listen for errors, or bind purely to process
events emitted as shown below:
1const Cabin = require('cabin'); 2 3const cabin = new Cabin(); 4 5process.on('uncaughtException', err => { 6 cabin.error(err); 7 process.exit(1); 8}); 9 10process.on('unhandledRejection', err => { 11 cabin.error(err); 12});
Since cross-browser support is very limited and non-standardized for errors and stack traces, we highly recommend to use StackTrace.
We recommend to use StackTrace instead of TraceKit as it is a more modern alternative and provides much similarity between your Browser and your Node errors (stackframes are basically similar to representations in Gecko and V8, aka the ones you get with Node).
It does require you to have a polyfill if you're using it in the browser (only if you're supporting browsers that don't support standardized Promises/JSON). You'll basically need es6-promise
and json3
polyfills for browsers you wish to support that don't have them. The example below shows you how to polyfill, don't worry! You can reference Caniuse data on Promises and JSON respectively if you need.
The example below demonstrates using StackTrace with uncaught to catch global errors below.
1<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=Promise"></script> 2<script src="https://unpkg.com/stackframe"></script> 3<script src="https://unpkg.com/stacktrace-js"></script> 4<script src="https://unpkg.com/uncaught"></script> 5<script src="https://unpkg.com/cabin"></script> 6<script src="https://unpkg.com/prepare-stack-trace"></script> 7 8<script type="text/javascript"> 9 (function() { 10 // 11 // Sourced from the StackTrace example from CabinJS docs 12 // <https://github.com/cabinjs/cabin#stacktrace> 13 // 14 var cabin = new Cabin(); 15 16 // Use cabin globally in your app (instead of `console`) 17 window.cabin = cabin; 18 19 // Bind event listeners 20 uncaught.start(); 21 uncaught.addListener(function(err, event) { 22 if (!err) { 23 if (typeof ErrorEvent === 'function' && event instanceof ErrorEvent) 24 return cabin.error(event.message, { event: event }); 25 cabin.error({ event: event }); 26 return; 27 } 28 // this will transform the error's `stack` property 29 // to be consistently similar to Gecko and V8 stackframes 30 StackTrace.fromError(err) 31 .then(function(stackframes) { 32 err.stack = prepareStackTrace(err, stackframes); 33 cabin.error(err); 34 }) 35 .catch(function(err2) { 36 cabin.error(err); 37 cabin.error(err2); 38 }); 39 }); 40 })(); 41</script>
logger
(Object or Axe instance) - if you have a custom logger you wish to use or an existing Axe instance – defaults to an instance of Axe which uses console
as the logger – if you do not pass an instance of Axe, then an instance will be created and the logger
option will be passed downmeta
(Object) - defaults to an empty object - this will get passed as metadata (e.g. you could set a custom meta.user
object here for every request)parseRequest
(Object) - defaults to an empty object, which means it will use the defaults from parse-request (see Metadata below)errorProps
(Array) - a list of properties to cherry-pick from the error object parsed out of err thanks to parse-err (by default all properties are returned; even non-enumerable ones and ones on the prototype object) (see Metadata below)message
(Function) - inspired by morgan, and defaults to a dev-friendly format (or if in production mode, then it uses a standard Apache common log format)). – when requests finish, it will utilize logger
to output an error, warn, or info level log based off the status code, and this function is used to determine the string sent to the logger. It accepts one argument options
, which is comprised of options.level
, options.req
, options.res
, and optionally (if and only if Koa) options.ctx
. It is required that this function return a String. See src/message.js for the default message function. Note that both dev-friendly and Apache common log formats are stripped of basic auth lines for obvious security reasons. Note that if a null
or undefined
value is returned from the message function, then the logger will not be invoked unless there is an error.Under the hood, Cabin uses Axe which provides us with several options, including one to show metadata (e.g. request headers, body, and user) and another to show stack traces for errors.
To show/hide application metadata and/or stack traces, see the Axe options documentation.
Cabin uses the package parse-request to parse the request metadata for you automatically in your Express and Koa applications.
Here's an example of a parsed metadata object:
1{ 2 request: { 3 method: 'POST', 4 query: { 5 foo: 'bar', 6 beep: 'boop' 7 }, 8 headers: { 9 host: '127.0.0.1:63955', 10 'accept-encoding': 'gzip, deflate', 11 'user-agent': 'node-superagent/3.8.3', 12 authorization: 'Basic ********************', 13 accept: 'application/json', 14 cookie: 'foo=bar;beep=boop', 15 'content-type': 'multipart/form-data; boundary=--------------------------930511303948232291410214', 16 'content-length': '1599', 17 connection: 'close' 18 }, 19 cookies: { 20 foo: 'bar', 21 beep: 'boop' 22 }, 23 body: '{"product_id":"5d0350ef2ca74d11ee6e4f00","name":"nifty","surname":"lettuce","bank_account_number":"1234567890","card":{"number":"****-****-****-****"},"stripe_token":"***************","favorite_color":"green"}', 24 url: '/?foo=bar&beep=boop', 25 timestamp: '2019-06-14T07:46:55.568Z', 26 id: 'fd6225ed-8db0-4862-8566-0c0ad6f4c7c9', 27 http_version: '1.1', 28 files: '{"avatar":[{"fieldname":"avatar","originalname":"avatar.png","encoding":"7bit","mimetype":"image/png","buffer":{"type":"Buffer","byteLength":216},"size":216}],"boop":[{"fieldname":"boop","originalname":"boop-1.txt","encoding":"7bit","mimetype":"text/plain","buffer":{"type":"Buffer","byteLength":7},"size":7},{"fieldname":"boop","originalname":"boop-2.txt","encoding":"7bit","mimetype":"text/plain","buffer":{"type":"Buffer","byteLength":7},"size":7}]}' 29 }, 30 user: { 31 ip_address: '::ffff:127.0.0.1' 32 }, 33 id: '5d0350ef2ca74d11ee6e4f01', 34 timestamp: '2019-06-14T07:46:55.000Z', 35 duration: 6.651317 36}
As you can see, sensitive data is masked and contextual user information metadata is automatically populated.
ctx.throw
awesome!MIT © Titanism
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 existing vulnerabilities detected
Reason
security policy file detected
Details
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
no SAST tool detected
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More