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

@accelint/logger

v1.0.0

Published

A flexible and extensible logging utility with callsite tracking and environment-aware capabilities.

Downloads

1,355

Readme

@accelint/logger

Structured logging built on LogLayer with automatic callsite tracking and environment detection.

What is @accelint/logger?

@accelint/logger is a thin wrapper around LogLayer that bakes in sensible defaults for Accelint projects. Out of the box you get:

  • Callsite tracking — every log entry includes the file and line where it was called
  • Environment detection — logs note whether they came from the browser or server
  • Pretty-printed output — readable in development, switchable to structured JSON for production pipelines
  • Error serialization — errors include full stack traces via serialize-error
  • Singleton pattern — configure once at startup, import everywhere else

It doesn't change LogLayer's API. Anything in the LogLayer docs applies here.

Table of Contents

Installation

pnpm add @accelint/logger

TypeScript types are included — no separate @types package needed.

Quick Start

Create a single logger instance in your app and import it everywhere else:

// ~/utils/logger/index.ts
import { getLogger } from '@accelint/logger';

export const logger = getLogger({
  enabled: true,
  level: 'info',
  prefix: '[MyApp]',
  env: process.env.NODE_ENV as 'production' | 'development',
});
// ~/data-access/auth/server.ts
import { logger } from '~/utils/logger';

export function login(credentials: Credentials) {
  logger.info('User login attempt');
  // ...
}

getLogger returns a singleton — call it once at startup to configure it, then import the result wherever you need it. Don't call it in multiple files with different options; only the first call's options take effect.

Configuration Options

| Option | Type | Default | Description | | --- | --- | --- | --- | | enabled | boolean | required | Enable or disable all logging output | | level | LogLevel | 'debug' | Minimum log level to output | | prefix | string | '' | String prepended to all log messages | | pretty | boolean | true | Use pretty-printed console output. Set to false for structured JSON | | env | 'production' \| 'development' | 'development' | Environment context; affects whether callsite and environment data is included | | plugins | LogLayerPlugin[] | [] | Additional LogLayer plugins applied after the built-in ones | | transports | LogLayerTransport[] | [] | Additional transports alongside the default console output | | groups | LogGroupsConfig | {} | Group-based routing for sending logs to specific transports |

Log Levels

| Level | Method | Use case | | --- | --- | --- | | trace | logger.trace() | Fine-grained debugging, very verbose | | debug | logger.debug() | Development debugging | | info | logger.info() | General information about what the app is doing | | warn | logger.warn() | Something looks wrong but execution continues | | error | logger.error() | An operation failed | | fatal | logger.fatal() | Critical failure, app likely needs to stop |

API

getLogger

function getLogger(opts: LoggerOptions): LogLayer

Returns a singleton LogLayer instance. The first call initializes the logger with the provided options. Every call after that returns the same instance regardless of what options you pass.

import { getLogger } from '@accelint/logger';

export const logger = getLogger({
  enabled: true,
  level: 'info',
});

Returns: LogLayer — see the LogLayer docs for the full instance API, including withContext, withMetadata, withError, child, withPrefix, and more.


Log Level Constants

String constants for each log level, exported for use where you need to reference a level programmatically rather than with a string literal:

import { DEBUG, INFO, WARN, ERROR, TRACE, FATAL } from '@accelint/logger';
import type { LogLevel } from '@accelint/logger';

const logger = getLogger({ enabled: true, level: WARN });

| Constant | Value | | --- | --- | | TRACE | 'trace' | | DEBUG | 'debug' | | INFO | 'info' | | WARN | 'warn' | | ERROR | 'error' | | FATAL | 'fatal' |

The LogLevel type is also exported and maps to LogLevelType from @loglayer/shared.

Examples

Adding Context and Metadata

Context persists across all logs on a logger instance. Metadata is scoped to a single log entry.

import { logger } from '~/utils/logger';

// Context: carried through all subsequent logs on this instance
const requestLogger = logger.withContext({
  requestId: req.id,
  path: req.path,
  method: req.method,
});

requestLogger.info('Request received');
await processRequest(req);
requestLogger.info('Request completed');

// Metadata: attached to this one log entry only
logger.withMetadata({ amount: payment.amount, currency: payment.currency }).info('Processing payment');

Combining both:

const orderLogger = logger.withContext({ orderId: '12345', userId: 'user_789' });

orderLogger.withMetadata({ step: 'validation' }).info('Validating order');
orderLogger.withMetadata({ step: 'payment' }).info('Processing payment');
orderLogger.withMetadata({ step: 'fulfillment' }).info('Order fulfilled');

Error Handling

Pass errors via withError() before the log level call. They're serialized with full stack traces automatically.

import { logger } from '~/utils/logger';

try {
  await riskyOperation();
} catch (error) {
  logger.withError(error).error('Operation failed');
}

With context:

async function fetchUserData(userId: string) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    return await response.json();
  } catch (error) {
    logger
      .withContext({ userId, endpoint: '/api/users' })
      .withError(error)
      .error('User fetch failed');
    throw error;
  }
}

Domain Loggers

For larger apps, it's useful to give each module its own prefixed logger so you can tell at a glance which part of the codebase a log came from. withPrefix() returns a child logger with the prefix pre-applied — you don't need to manage separate instances or thread loggers through function arguments.

Create a small utility for this:

// ~/utils/logger/domain.ts
import { logger } from '~/utils/logger';
import type { LogLevel } from '@accelint/logger';

export function createLoggerDomain(prefix: string, level?: LogLevel) {
  const child = logger.withPrefix(prefix);

  if (level) {
    child.setLevel(level);
  }

  return child;
}

Then use it per module:

// ~/data-access/payments/server.ts
import { createLoggerDomain } from '~/utils/logger/domain';

const log = createLoggerDomain('[Payments]');

export async function processPayment(payment: Payment) {
  log.info('Processing payment', payment.id);
  // Output: [Payments] Processing payment abc123
}

You can suppress noisy log levels in specific modules by passing a level:

// ~/data-access/auth/server.ts
import { createLoggerDomain } from '~/utils/logger/domain';

const log = createLoggerDomain('[Auth]', 'warn'); // debug and info are suppressed

export async function login(credentials: Credentials) {
  log.debug('Login attempt'); // suppressed
  log.warn('Rate limit approaching for user', credentials.username);
}

Each domain logger is a child of the root logger. They inherit the root's context but have independent prefixes and level settings.


Child Loggers

If you want module-specific context without a prefix, use logger.child(). Child loggers inherit the parent's configuration and any context set on the parent at the time child() is called, then maintain independent context after that.

// ~/data-access/users/server.ts
import { logger } from '~/utils/logger';

const userLogger = logger.child().withContext({
  module: 'data-access',
  domain: 'users',
});

export async function fetchUser(id: string) {
  userLogger.info('Fetching user', id);

  try {
    const user = await db.users.findOne(id);
    userLogger.info('User fetched successfully');
    return user;
  } catch (error) {
    userLogger.withError(error).error('Failed to fetch user');
    throw error;
  }
}

Adding context to userLogger won't affect the parent logger, and vice versa.


React Error Boundaries

'use client';
import 'client-only';
import { logger } from '~/utils/logger';
import { ErrorBoundary } from 'react-error-boundary';
import type { ErrorInfo, PropsWithChildren } from 'react';

function onError(err: Error, info: ErrorInfo) {
  logger
    .withContext({ componentStack: info.componentStack })
    .withError(err)
    .error('React error boundary caught error');
}

export function ErrorComponent({ children }: PropsWithChildren) {
  return (
    <ErrorBoundary fallback={<div>Error</div>} onError={onError}>
      {children}
    </ErrorBoundary>
  );
}

Custom Transports

Add transports to ship logs to external destinations alongside the default console output.

OpenTelemetry

pnpm add @loglayer/transport-opentelemetry
import { getLogger } from '@accelint/logger';
import { OpenTelemetryTransport } from '@loglayer/transport-opentelemetry';

export const logger = getLogger({
  enabled: true,
  level: 'info',
  transports: [
    new OpenTelemetryTransport({
      level: 'info',
      enabled: process.env.NODE_ENV === 'production',
      onError: (error) => console.error('OpenTelemetry error:', error),
    }),
  ],
});

When used alongside OpenTelemetry instrumentation, the transport automatically includes trace IDs and span IDs on each log entry.


Custom Plugins

Plugins let you intercept and transform log data before it reaches a transport. This example prepends a timestamp to every message:

// ~/utils/logger/plugins/timestamp.ts
import type { LogLayerPlugin, PluginBeforeMessageOutParams } from 'loglayer';

export interface TimestampPluginOptions {
  format?: 'iso' | 'locale';
}

export function timestampPlugin(options: TimestampPluginOptions = {}): LogLayerPlugin {
  return {
    onBeforeMessageOut({ messages }: PluginBeforeMessageOutParams) {
      const timestamp =
        options.format === 'locale' ? new Date().toLocaleString() : new Date().toISOString();

      return messages.map((msg) => `[${timestamp}] ${msg}`);
    },
  };
}
// ~/utils/logger/index.ts
import { getLogger } from '@accelint/logger';
import { timestampPlugin } from './plugins/timestamp';

export const logger = getLogger({
  enabled: true,
  level: 'info',
  plugins: [timestampPlugin({ format: 'iso' })],
});

See the LogLayer plugin docs for available hooks and what each can intercept.


Testing

LogLayer ships a MockLogLayer that matches the full logger API but does nothing. Use it in unit tests to silence log output and optionally assert log calls.

import { MockLogLayer } from 'loglayer';

vi.mock('~/utils/logger', () => ({
  logger: new MockLogLayer(),
}));

See the LogLayer testing docs for the full MockLogLayer API.

Built-in Features

Callsite Tracking

Every log entry automatically includes the source file and line number:

logger.warn('Something happened');
// Output includes: callSite: "src/data-access/users/server.ts:42:5"

Environment Detection

Logs include a server field showing where they came from:

logger.info('Request received');
// Output includes: server: true  (or false in the browser)

Pretty Printing

Development output is formatted for readability. Switch to structured JSON for log aggregation:

// Pretty output (default)
const logger = getLogger({ enabled: true, pretty: true });

// Structured JSON
const logger = getLogger({ enabled: true, pretty: false });

Further Reading