{"id":18665446,"url":"https://github.com/cb1kenobi/snooplogg","last_synced_at":"2025-04-11T22:31:09.742Z","repository":{"id":16731190,"uuid":"80554347","full_name":"cb1kenobi/snooplogg","owner":"cb1kenobi","description":"Your mind on your logs and your logs on your mind","archived":false,"fork":false,"pushed_at":"2025-04-07T03:44:23.000Z","size":26740,"stargazers_count":9,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-07T04:29:33.877Z","etag":null,"topics":["debug","log","logger","logging","nodejs","snoop"],"latest_commit_sha":null,"homepage":null,"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/cb1kenobi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2017-01-31T19:33:29.000Z","updated_at":"2025-04-07T03:44:18.000Z","dependencies_parsed_at":"2024-09-06T09:43:19.203Z","dependency_job_id":"36e4ba64-f8c0-46ae-8168-14d3d260c34e","html_url":"https://github.com/cb1kenobi/snooplogg","commit_stats":{"total_commits":103,"total_committers":3,"mean_commits":"34.333333333333336","dds":0.03883495145631066,"last_synced_commit":"3a68bdce96597653f58567ca31adb3c19888d900"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cb1kenobi%2Fsnooplogg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cb1kenobi%2Fsnooplogg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cb1kenobi%2Fsnooplogg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cb1kenobi%2Fsnooplogg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cb1kenobi","download_url":"https://codeload.github.com/cb1kenobi/snooplogg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248489567,"owners_count":21112602,"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":["debug","log","logger","logging","nodejs","snoop"],"created_at":"2024-11-07T08:27:44.558Z","updated_at":"2025-04-11T22:31:09.079Z","avatar_url":"https://github.com/cb1kenobi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cbr\u003e\n\u003cdiv align=\"center\"\u003e\n\t\u003cimg width=\"640\" height=\"240\" src=\"media/SnoopLogg.webp\" alt=\"SnoopLogg\"\u003e\n\u003c/div\u003e\n\u003cbr\u003e\n\nSnoopLogg is a lightweight, zero dependency debug logging library for Node.js\nand Bun. It is specifically designed for CLI programs, daemons, and libraries.\n\nSnoopLogg is flexible and capable, but it's not the best solution for things\nsuch as logging HTTP server requests, filtering by log level, and web browser\nconsole is not supported. For CLI apps and libaries, SnoopLogg is the shiz.\n\n# Features\n\n - Snoop on other SnoopLogg instances to aggregate log messages\n - Pipe log messages to one or more streams (such as a file or socket)\n - Namespaced and nested namespaced loggers with filtering support\n - Automatic namespace colorization\n - Custom log message formatting and styling\n - Pretty stack trace rendering\n - Support for object mode streams\n - Zero dependencies\n\n# Basic Logging\n\nSnoopLogg provides 7 loggers. `log()` is the only one that doesn't print a\nlabel.\n\n```javascript\nimport { log, trace, debug, info, warn, error, panic } from 'snooplogg';\n\nlog('This is a log() message');\ntrace('This is a trace() message');\ndebug('This is a debug() message');\ninfo('This is a info() message');\nwarn('This is a warn() message');\nerror('This is a error() message');\npanic('This is a panic() message');\n```\n\n![Basic Logging](media/01-basic-logging.webp)\n\nBy default, it prints the time from which the program has started, the log\nmethod, and the log message. The format is completely customizable.\n\n# Logging Values\n\nSnoopLogg uses the built-in `util.format()` and `util.inspect()` to render\nvalues.\n\n```javascript\ninfo('My name is %s and my favorite drink is %s', 'Snoop', 'juice');\n\ndebug({\n  name: 'Snoop',\n  occupation: 'Logger'\n});\n\nerror(new Error('This is an error'));\n```\n\n![Logging Values](media/02-logging-values.webp)\n\n# Namespaces\n\nThe default export is a `snooplogg` instance that can be invoked as a function\nto create a namespaced child logger. You can have as many deeply nested\nnamespaces as you'd like.\n\n```javascript\nimport snooplogg from 'snooplogg';\n\nsnooplogg.info('This is the default namespace');\n\nconst fooLogger = snooplogg('foo');\nfooLogger.info('This is the foo namespace');\n\nconst barLogger = fooLogger('bar');\nbarLogger.info('This is the bar namespace');\n\nconst bazLogger = snooplogg('baz');\nbazLogger.info('This is the baz namespace');\n```\n\n![Namespaces](media/03-namespaces.webp)\n\n# Namespace Filtering\n\nBy default, debug logging is suppressed. You must enable it by setting the\n`SNOOPLOGG` (or `DEBUG`) environment variable to the desired filter pattern.\n\n```bash\n$ SNOOPLOGG=* node myscript.js\n```\n\nSpecifying `*` will display all log messages. The root log methods cannot be\nfiltered, only enabled or disabled.\n\nMultiple namespace filters can be specified as a comma separated list.\nWildcards are supported. Prefix the filter with `-` (dash) to ignore the\npattern.\n\n```javascript\nconst fooLogger = snooplogg('foo');\nfooLogger.info('FOO!');\n\nconst barLogger = snooplogg('bar');\nbarLogger.info('BAR!');\n\nconst bazLogger = snooplogg('baz');\nbazLogger.info('BAZ!');\n```\n\n![Filtering](media/04-filtering.webp)\n\nNote that SnoopLogg does not support \"log levels\". If you want to filter by\nlog method, then you'll need to pipe SnoopLogg into an object mode\n[transform stream](\n  https://nodejs.org/api/stream.html#implementing-a-transform-stream\n) that suppresses unwanted log messages, then pipe that into `stderr`, file,\netc. See `pipe()` below.\n\n# Snooping\n\nSnoopLogg allows you to \"snoop\" or aggregrate log messages from other\nSnoopLogg instances.\n\nFor example, say you have an app and a library. The app writes all debug logs\nto disk. You wouldn't necessarily want the library writing debug logs to disk,\nso you can have the app debug logger \"snoop\" on the library's debug logger.\n\n```\nconst app = new SnoopLogg().enable('*').pipe(process.stdout);\nconst lib = new SnoopLogg();\n\napp('app').info('This is the app logger and it will snoop on all other loggers');\nlib('lib').info('This is the lib logger, but nothing will be logged');\napp.snoop();\nlib('lib').info(`This is the lib logger and I\\'m being snooped`);\n```\n\n![Snoop](media/05-snoop.webp)\n\nYou can stop snooping by calling `snooplogg.unsnoop()`.\n\n# Programmatic Instantiation\n\nYou can create your own SnoopLogg instances instead of using the default one:\n\n```javascript\nimport { SnoopLogg } from 'snooplogg';\n\nconst myLogger = new SnoopLogg();\nmyLogger.enable('*');\nmyLogger.info('Yippee yo!');\n\nconst fooLogger = myLogger('foo');\nfooLogger.log('Yippee yay!');\n```\n\nShould you need to, you can also check to see if a specific namespace is\nenabled by calling:\n\n```\nmyLogger.isEnabled('foo');\n```\n\n# Piping\n\nYou can pipe SnoopLogg into one or more writable streams such as a file.\n\n```javascript\nconst out = fs.createWriteStream('debug.log');\nsnooplogg.pipe(out);\nsnooplogg.info('This will be written to stderr and a file');\n```\n\n`pipe()` also accepts a second argument containing the stream specific\noverrides:\n\n```typescript\ninterface StreamOptions {\n  colors?: boolean;\n  elements?: LogElements;\n  flush?: boolean;\n  format?: LogFormatter;\n}\n```\n\nIf the history feature is enabled, then you can set the `flush` option to write\nall messages in the history to the new pipe:\n\n```javascript\nsnooplogg.pipe(out, { flush: true });\n```\n\nTo stop piping to a stream:\n\n```javascript\nsnooplogg.unpipe(out);\n```\n\nYou can pipe the messages to a transform stream to have complete control over\neach log message:\n\n```javascript\nimport { Transform } from 'node:stream';\n\nclass MyTransformer extends Transform {\n  constructor(opts = {}) {\n    opts.objectMode = true;\n    super(opts);\n  }\n\n  _transform(msg, enc, cb) {\n    if (msg \u0026\u0026 typeof msg === 'object' \u0026\u0026 !(msg instanceof Buffer)) {\n      this.push(JSON.stringify(msg, null, 2));\n    }\n    cb();\n  }\n}\n\nconst out = new MyTransformer();\nout.pipe(process.stdout);\n\nconst myLogger = new SnoopLogg().enable('*');\nmyLogger.pipe(out);\nmyLogger.info('Transform me!')\n```\n\n![Transform](media/06-transform.webp)\n\nYou can pipe the debug log to as many streams as you like, however each log\nmessage is formatted per stream. This could impact performance if you have a\nlot of log messages and several streams. Instead, consider piping SnoopLogg to\na transform stream that in turn pipes to several streams:\n\n```javascript\nimport { Transform } from 'node:stream';\n\nclass Demuxer extends Transform {\n  _transform(msg, enc, cb) {\n    this.push(msg);\n    cb();\n  }\n}\n\nconst demuxer = new Demuxer();\ndemuxer.pipe(process.stdout);\ndemuxer.pipe(myfile);\n\nmyLogger.pipe(demuxer);\n```\n\n# History\n\nSnoopLogg can buffer the previous log messages. By default, this is disabled.\nTo enable it, set the history size to the desired value:\n\n```javascript\nsnooplogg.config({ historySize: 5 });\n```\n\nThe code above will buffer the last 5 messages. To dump the history, you need\nto pipe SnoopLogg to a writable stream and set the `flush: true` flag.\n\n```javascript\nfor (let i = 1; i \u003c= 10; i++) {\n\tsnooplogg.info(`This is message ${i}`);\n}\n\nsnooplogg.pipe(process.stdout, { flush: true });\n\n```\n\n![History](media/07-history.webp)\n\nThis feature is specifically designed for daemons (e.g. servers) and takes\ninspiration from `adb logcat`.\n\nFor example, pretend you have a server running in the background. Now you want\nto see the debug log for when the server is initializes, but by the time you\nconnect, those messages are in the past. Don't stress. Simply set the\n`historySize` to something reasonable, then implement a \"logcat\" route handler\nthat pipes the SnoopLogg instance to the connection socket with `flush: true`\nset. SnoopLogg will automatically unpipe the stream when it is ended.\n\nNote that setting a relative large history size may impact performance.\n\n# Config\n\nSnoopLogg has a relatively simple configuration:\n\n```typescript\ninterface SnoopLoggConfig {\n\tcolors?: boolean;\n\telements?: LogElements;\n\tformat?: LogFormatter | null;\n\thistorySize?: number;\n}\n```\n\nYou can call the `.config()` function to change the default logger or pass the\nconfig into a new instance.\n\n```javascript\nsnooplogg.config({ historySize: 10 });\n```\n\n```javascript\nconst myLogger = new SnoopLogg({ historySize: 10 });\nmyLogger.config({ historySize: 20 });\n```\n\nWe'll discuss these settings in more detail below.\n\n## `colors`\n\nSet this flag to `false` to to disable colors. Colors are enabled by default\nunless overwritten by the stream settings or the stream is not a TTY.\n\n## `elements`\n\nYou can pass in an object with overrides for any of the element specific\nrenderers.\n\n```typescript\ntype FormatLogElements = {\n\terror: (err: Error, styles: StyleHelpers) =\u003e string;\n\tmessage: (msg: string, method: string, styles: StyleHelpers) =\u003e string;\n\tmethod: (name: string, styles: StyleHelpers) =\u003e string;\n\tnamespace: (ns: string, styles: StyleHelpers) =\u003e string;\n\ttimestamp: (ts: Date, styles: StyleHelpers) =\u003e string;\n\tuptime: (uptime: number, styles: StyleHelpers) =\u003e string;\n};\n```\n\nEach element formatter is passed a `styles` object containing the contents of\nthe [ansi-styles](https://github.com/chalk/ansi-styles) package. It also\nincludes the `nsToRgb(string)` function which deterministically finds a color\nbased on the supplied string where the color is not too light or too dark.\n\n```javascript\nsnooplogg.config({\n  elements: {\n    namespace(ns, { color, nsToRgb, rgbToAnsi256 }) {\n      const { r, g, b } = nsToRgb(ns);\n      return `${color.ansi256(\n        rgbToAnsi256(r, g, b)\n      )}${ns}${color.close}`;\n    }\n  }\n});\n```\n\n## `format()`\n\nA custom formatter that renders a log message.\n\n```javascript\nsnooplogg.info('This is the default format');\n\nsnooplogg.config({\n  format(msg, styles) {\n    const { args, colors, elements, method, ns, ts, uptime } = msg;\n    return `${ts.toISOString()} [${method}] ${args.join(' ')}`;\n  }\n});\n\nsnooplogg.info('This is the custom format');\n```\n\n![Format](media/08-format.webp)\n\n## `historySize`\n\nThe number of log messages to buffer. Defaults to `0`. Pipe SnoopLogg to a\nwritable stream with `{ flush: true }` to see the buffered messages.\n\n# Demo\n\nPull the repo, `pnpm i \u0026\u0026 pnpm build`, then run:\n\n```bash\nSNOOPLOGG=* node demo/demo.js\n\n# or\n\nSNOOPLOGG=* bun demo/demo.js\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcb1kenobi%2Fsnooplogg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcb1kenobi%2Fsnooplogg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcb1kenobi%2Fsnooplogg/lists"}