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

@redthreadlabs/tracelog-client

v2.1.3

Published

Lightweight logging client for tracelog — works in React Native and browsers

Readme

@redthreadlabs/tracelog-client

The client half of tracelog: a small, dependency-free SDK that buffers structured events, transactions and spans on a device or in a browser and ships them in batches to your own server, which forwards them to the tracelog agent's client channel.

It is the same record shape end to end — the wire format is @redthreadlabs/tracelog-schema, so the server stamps the few facts it owns (the authenticated user, the source IP) and writes the records through; there is no field-by-field remapping and no unit conversion.

Works in React Native and in browsers: no window, no Node built-ins. Its one dependency is the shared schema, and that is types-only — nothing but this SDK's own code runs at runtime.

npm install @redthreadlabs/tracelog-client

Usage

import { TracelogClient } from '@redthreadlabs/tracelog-client';

const tracelog = new TracelogClient({
  endpoint: 'https://api.example.com/logs',
  getAuthHeaders: async () => ({ Authorization: `Bearer ${await getToken()}` }),
  getOrigin: () => ({ service: { name: 'acme-ios', version: '2.4.1' }, environment: 'production' }),
  getUserId: () => session?.userId,
  getLocale: () => i18n.locale,
  // Drop debug noise in production without touching call sites.
  getMinLevel: () => (__DEV__ ? 'debug' : 'info'),
  // Survive a cold start: hand the SDK your key/value store.
  persistLogs: (data) => AsyncStorage.setItem('tracelog', data),
  loadPersistedLogs: () => AsyncStorage.getItem('tracelog'),
});

Events

Events are free-form structured records — analytics, audit trails, or structured log lines — built with a small chained builder:

tracelog.event('checkout').info('user completed purchase')
  .withLabels({ sku: 'abc-123', cents: 4999 })
  .send();

tracelog.event('sync').error('inbox sync failed')
  .withLabel('attempt', 3)
  .withError(err)
  .send();

info, warn, error and debug set the level and message; withLabel, withLabels and withError add context; send() enqueues. Nothing is sent synchronously.

Transactions and spans

For timed work, either bracket it live:

const txn = tracelog.startTransaction('cold-start');
const span = tracelog.startSpan('load-dictionary', txn);
span.end();
txn.end();

…or record a duration you already measured:

tracelog.recordTransaction('cold-start', 842);

Spans nest under a transaction or another span and inherit its trace id, so a device-side trace arrives with the same shape the agent writes server-side.

Batching

Records buffer and flush on a cadence (5 s by default), when the buffer fills (100 records), or when you call await tracelog.flush(). Batches are chunked to stay under a size limit (50 records / 512 KB per request) and retried with backoff. Call dispose() on teardown to stop the timer and flush what's left.

| Option | Default | | |---|---|---| | endpoint | — | where batches are POSTed | | getAuthHeaders | — | per-request auth headers | | getOrigin | — | service + environment for this lifetime | | getUserId / getLocale / getMinLevel | — | stamped or gated per record | | flushCadenceMs | 5000 | | | maxBufferSize | 100 | records buffered before a forced flush | | maxChunkSize / maxChunkBytes | 50 / 524288 | per HTTP request | | persistLogs / loadPersistedLogs | — | survive process death |

The server side

Your endpoint receives a RecordBatch and hands it to the agent's client channel — roughly:

const apm = require('@redthreadlabs/tracelog');
const clientChannel = apm.getChannel('client');

app.post('/logs', (req, res) => {
  const batch = req.body;
  if (batch.origin) clientChannel.writeRecordOrigin({ ...batch.origin, lifetime_id: batch.lifetime_id });
  if (batch.events?.length) clientChannel.writeClientEvents(batch.events);
  for (const t of batch.transactions ?? []) clientChannel.writeTransaction(t);
  for (const s of batch.spans ?? []) clientChannel.writeSpan(s);
  res.sendStatus(200);
});

Trust the batch for content, never for identity: stamp the user from your own authenticated session rather than from anything the client claims.

License

BSD-2-Clause