LogTape 2.1.0: Throttling, logfmt, and smarter redaction #165
dahlia
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
LogTape is a logging library for JavaScript and TypeScript that works across Deno, Node.js, Bun, and browsers. It's built around structured logging, has zero dependencies, and is designed to work as well in library code as in application code.
Version 2.1.0 adds a throttling filter for high-volume production environments, a logfmt formatter that splits the difference between plain text and JSON, timezone control for timestamps, and substantial improvements to the redaction package. Here's what changed.
Throttling filter
Production services sometimes hit conditions where the same log message fires thousands of times a second: a database that's down, a misconfigured retry loop, a validation error on every request. The log volume becomes noise, and the underlying cause gets buried.
The new
getThrottlingFilter()addresses this. It tracks records by category, level, and raw message template, so records with different interpolated values are still counted as the same pattern:The default mode is fixed-window: the window opens when the first matching record arrives, allows up to
limitrecords duringwindowMs, and suppresses the rest until it closes. Switch to"sliding"if you want a rolling count instead.You can define what counts as “the same record” with a custom
keyfunction. For multi-tenant applications, for example, you might want to throttle per tenant ID rather than per message template:When suppressed records are released, the filter can emit a summary so you know how many were dropped:
Summary records carry structured properties including
suppressed,allowed,startTime,endTime, and the first and last records from the suppressed window.See the throttling filter documentation for the full API.
Logfmt formatter
Plain text is readable but loses structure. JSON preserves structure but is noisy to scan in a terminal. Logfmt splits the difference:
level=info msg="User login" user_id=123 duration=45msis both grep-friendly and parseable by log management tools.LogTape now ships
logfmtFormatteras a built-in:When you need to customize behavior, use
getLogfmtFormatter()withLogfmtFormatterOptions. There's also a#logfmtshorthand for@logtape/configconfigurations.Timezone control for timestamps
Until now, text-based formatters rendered timestamps in UTC regardless of where the application was running. The new
timeZoneoption lets you specify an IANA timezone name or a fixed UTC offset:Pass
nullto use the system's local timezone. The default behavior (notimeZoneoption) remains UTC. The same option is available ongetAnsiColorFormatter()and@logtape/pretty'sgetPrettyFormatter(). Invalid timezone values throw aTypeErrorat formatter creation time rather than silently falling back.Error logging with extra properties
Since 2.0.0, you can pass an
Errorobject directly tologger.error(),logger.warn(), andlogger.fatal(). The default message template becomes{error.message}, and the full error is available in properties.The new overload in 2.1.0 extends this to accept additional structured properties alongside the error, contributed by @fadomire:
Agent skill for AI coding assistants
The
@logtape/logtapenpm package now bundles an Agent Skills skill file that teaches AI coding assistants how to use LogTape correctly. When you use a tool like Claude Code, GitHub Copilot, or Cursor on a project that has LogTape installed, the assistant can automatically pick up the skill and apply it when writing logging code.To make the skill available to your AI tool, use skills-npm by Anthony Fu:
{ "scripts": { "prepare": "skills-npm" }, "devDependencies": { "skills-npm": "latest" } }Running
npm installthen symlinks the skill into .claude/skills/, .cursor/skills/, and other agent directories. See the LLM integration documentation for manual setup instructions.New package: @logtape/adaptor-bunyan
@logtape/adaptor-bunyanis a new package that forwards LogTape log records to Bunyan loggers. Structured properties pass through as Bunyan's merge-object, and the category formatting follows the same conventions as@logtape/adaptor-pino.This completes the picture for Node.js logging infrastructure adaptors: if you have an existing Bunyan-based application and want to adopt LogTape-instrumented libraries without changing your logging stack, this package handles the bridge.
Redaction improvements
Async redaction actions
@logtape/redactionnow supports field-based redaction actions that perform asynchronous work. The newredactByFieldAsync()function preserves record order while starting independent redaction work concurrently:HMAC pseudonymization
Replacing sensitive values with
[REDACTED]breaks log correlation: you can't trace a user's journey across log records when every user ID looks the same. The newcreateHmacPseudonymizer()replaces sensitive fields with stable keyed HMAC pseudonyms instead. The same input always produces the same output for a given key, so you can correlate records without exposing the original values:CryptoKeyinputs derive the default output prefix from the key's HMAC hash algorithm. Explicit hash mismatches are rejected.Bug fixes
Two correctness bugs in
redactByField()were fixed. Field patterns using global or sticky regular expressions now produce consistent results across repeated records (a subtle state issue withRegExp.lastIndex). Also, public fields named__proto__are now preserved as own properties rather than changing the redacted object's prototype.Hono integration improvement
@logtape/hono'sHonoContextinterface now extends Hono'sContextdirectly, contributed by @HamzaZia1. Custom formatter and skip callbacks now receive the real runtime context, which means they can read context variables viac.get().Bug fix: lazy property callbacks
Lazy property callbacks were sometimes invoked even when the log level was disabled, which defeated the purpose of lazy evaluation. This is now fixed consistently across all logging methods on both regular loggers and contextual loggers created with
Logger.with().Upgrading
There are no breaking changes in 2.1.0. See the full changelog for complete details.
All reactions