npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lazslov/telemetry

v1.1.4

Published

Estate telemetry for the Lamido services: the canonical log envelope, the batched log sink, the Telegram alert channel and the request middleware (observability house rules OB-1…OB-15).

Readme

@lazslov/telemetry

Estate telemetry for the Lamido services. One shared implementation of the observability house rules (OB-1…OB-15):

  • The envelope — structured JSON to stdout, one object per line. Every line carries time, service, env, level, message; level and message always win over call-site metadata. A deny-list redacts sensitive keys at emit time.
  • The sink — an additive, batched, fire-and-forget copy of the stdout stream. stdout is the record; the sink is lossy by design. Configured from LOG_SINK, LOG_SINK_URL, LOG_SINK_USER, LOG_SINK_TOKEN, read at call time so a bad value can never break the service. The first adapter is Grafana Loki; labels are exactly service, env, level.
  • Alertsalert(severity, key, fields) posts to Telegram (TELEGRAM_ALERT_BOT_TOKEN, TELEGRAM_ALERT_CHAT_ID) and always also logs a line with alert: true as the sink-side backstop. Never throws.
  • Request middleware — accepts or mints the X-Request-Id, binds request_id onto the request logger, runs the handler inside an ambient scope so every line written during the request carries the id, emits one http.request summary line per request, and schedules the sink flush off the response path.

Usage

import { createTelemetry } from "@lazslov/telemetry";

const telemetry = createTelemetry({ service: "payment-service", env: "production" });
export const { logger, alert, flush } = telemetry;
export const createLogger = telemetry.createLogger;

The request scope (OB-2)

requestMiddleware runs the handler inside an ambient scope carrying request_id, so every line written while a request is in flight carries it — including lines written through the module-scope logger by a helper that never saw the request context:

// A helper three files from the route. No context, no signature change.
import { logger } from "./logger.js";

logger.warn("last_used_at refresh failed", { error: err.name });
// → { level: "warn", service, env, request_id: "…", … }

Three things to know:

  • Outside a request there is no id, and no error either. A cron, a CLI and a queue drain write exactly the line they write without the middleware.
  • An explicit binding wins. A logger built with createLogger({ request_id }) keeps its own value; the scope only fills in what nothing else set.
  • c.get("log") is still correct and still the right thing to use where the context is in hand. The scope is for the code that cannot reach it.

If your service wraps the logger, pass createLogger

Required whenever lib/logger.ts wraps the logger, which is every service enforcing OB-6 item 2 — the container strip that replaces body, values, variables and payload wholesale, and which this package does not carry:

export const createLogger = (b?: LogMeta): Logger => guarded(telemetry.createLogger(b));

// Without the hook the middleware builds the request logger from this package's own
// factory, and `guarded` never runs on a single request-scoped line.
export const requestId = telemetry.requestMiddleware({ createLogger });

The logger the hook returns is used for the log context key and for the http.request summary line, so one argument covers both. telemetry.logger is a different seam: wrap that one in your own file and export the wrapped value.

The scope and the strip were mutually exclusive until this option existed, and four of the five services on this package chose the strip — so the scope reached nobody.

Vendoring

The whole SDK is deliberately a single self-contained file (src/index.ts) with no static imports. A service that cannot take the npm dependency may vendor that file verbatim, per OB-7 — if a test pins the copy byte-identical against this source. Drift without a failing test is the one outcome that rule exists to prevent.

The one dynamic import is node:async_hooks, behind the request scope. It is guarded, so a runtime without the module gets a no-op scope rather than a throw, and the file still vendors as one file.