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

@osrs-tracker/logger

v0.3.0

Published

Structured JSON logs for the OSRS Tracker Express and Nest apps, on pino and pino-http

Readme

@osrs-tracker/logger · NPM package GitHub license

Structured JSON logs for the Express and Nest servers of OSRS Tracker, on pino and pino-http. It replaces morgan and the hand-rolled JSON lines, so both servers write the same fields for Loki:

  • One JSON object per line, starting with level as Loki names it (info, warn, error), time as an ISO string and type.
  • The message under message; an error under error as one string, as Node's util.inspect writes it: its stack, its own fields (code, errno, …), its cause chain and an AggregateError's errors.
  • type says what the line is about: incoming (a request the server answered), outgoing (a request it made), lifecycle (startup and shutdown) or uncaught (an error that reached the error handler). An app can add its own.

Install

npm install @osrs-tracker/logger

Usage

createLogger({ context?, level?, destination? })

The base pino logger. context returns fields for every line, e.g. the page being rendered or the request ID (undefined ones are left out). level defaults to info, destination to stdout. Log through a child with a type, so every line has one. The built-in types are incoming, outgoing, lifecycle and uncaught.

import { createLogger, type LogType } from '@osrs-tracker/logger';

type AppLogType = LogType<'prerender'>; // adds an app's own types

const logger = createLogger({ context: () => ({ page: renderedPage.getStore() }) });
const lifecycle = logger.child({ type: 'lifecycle' satisfies AppLogType });

lifecycle.info('Listening on port 8080');
lifecycle.error(error, 'Shutdown failed'); // or { error }
{ "level": "info", "time": "2026-10-09T18:00:00.000Z", "type": "lifecycle", "message": "Listening on port 8080" }

requestLogger({ logger, route, fields? }) (Express)

Logs every request once it has finished, as type: 'incoming':

app.use(
  requestLogger({
    logger,
    route: (req, res) => routeLabel(req, res), // keep it low-cardinality
    fields: (req, res) => ({ cache: res.getHeader('x-cache') }), // app extras
  }),
);
{
  "level": "info",
  "time": "…",
  "type": "incoming",
  "status": "200",
  "method": "GET",
  "host": "…",
  "route": "/items/:id",
  "url": "/items/4151",
  "responseTime": "12ms",
  "userAgent": "…",
  "clientIp": "…",
  "referer": "…",
  "contentLength": "512",
  "cache": "HIT"
}

The level follows the status: 5xx error, 4xx warn, else info. A request the client closed before the headers were sent is a warn with aborted: true and no status, timed until the connection closed. responseTime runs until the response finished, in whole milliseconds (pino-http's timing). context is read when the request starts, so its fields are on the line even though it's written after the request's async context has ended.

logOutgoingRequests({ logger })

Logs every request the process makes with fetch once its body has been read, as type: 'outgoing' (status, method, url, responseTime), with the context fields of where it was made. A cancelled request is a warn with aborted: true and no status; a network error is an error with its message under error. Call it once at startup; it returns a function that stops logging.

logOutgoingRequests({ logger });

Nest

Nest has to run on its Express adapter (Nest 11 or later, for Express 5, a peer dependency). Use requestLogger as the request log middleware, after the global nestjs-cls middleware so the request ID comes from context:

import { createLogger, requestLogger } from '@osrs-tracker/logger';
import { ClsServiceManager } from 'nestjs-cls';

export const logger = createLogger({
  context: () => ({ requestId: ClsServiceManager.getClsService().getId() }),
});

// app.module.ts: consumer.apply(requestLogger({ logger, route: (req) => routeLabel(req) })).forRoutes('*')

For Nest's and the services' own lines, see osrs-tracker-api's NestLogger: it extends Nest's ConsoleLogger and overrides only printMessages, so Nest still parses the arguments and filters the levels, and writes each line through a child of the logger with a type from its context (lifecycle, uncaught or app).