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

@elto/telemetry

v0.1.2

Published

OpenTelemetry integration for Effect with Node.js and browser support

Readme

@elto/telemetry

OpenTelemetry integration for Effect with Node.js and browser support.

Features

  • Node.js Support: Full OpenTelemetry integration with traces, metrics, and logs
  • Browser Support: Web-optimized telemetry with traces and logs
  • Dual Mode: Browser apps can send telemetry directly to collector or proxy through server
  • Effect Integration: Built on top of @effect/opentelemetry for seamless Effect usage
  • TypeScript: Full type safety and excellent IDE support
  • Simple API: Clean, declarative configuration

Installation

pnpm add @elto/telemetry effect

Quick Start

Node.js

import { createNodeOtelLayer, createEndpoints } from "@elto/telemetry/node";

const OtelLive = createNodeOtelLayer({
  resource: {
    serviceName: "api-server",
    serviceVersion: "1.0.0",
  },
  endpoints: createEndpoints("http://localhost:4318"),
});

// Use with your Effect program
const program = Effect.gen(function* () {
  // Your telemetry-enabled code here
}).pipe(Effect.provide(OtelLive));

Browser

import { createWebOtelLayer, createModeBasedEndpoints } from "@elto/telemetry/web";

const OtelLive = createWebOtelLayer({
  resource: {
    serviceName: "web-client",
    serviceVersion: "1.0.0",
  },
  endpoints: { traces: "", logs: "" }, // fallback
  getEndpoints: createModeBasedEndpoints(
    "http://localhost:4318",
    { serverUrl: "https://api.example.com" }
  ),
});

// Use with your Effect program or RPC client
import { withOtel } from "@elto/telemetry/web";

const ClientLive = withOtel(OtelLive, RpcClientLayer);

Span Processing

@elto/telemetry applies a built-in custom span processor by default. Both createNodeOtelLayer and createWebOtelLayer wrap the batch span processor with an opinionated sanitizer before export.

Behavior:

  • Redacts user.email, note.id, and profile.id and adds <key>_hash
  • Redacts db.connection_string and adds db.connection_string_redacted
  • Shortens db.statement when it exceeds the internal length threshold
  • Strips query strings from http.url
  • Adds http.status_category when http.status_code is present
  • Adds telemetry.redactions and telemetry.transformations counters
  • Drops spans when telemetry.drop is true or "true"

Not redacted or hashed: user.id, cache.key, request.id, request.client_id.

To explicitly drop a span, annotate it:

Effect.annotateCurrentSpan({
  "telemetry.drop": true,
  "telemetry.drop_reason": "debug-only",
});

If you need full control, build your own OpenTelemetry layer using @effect/opentelemetry or wrap a processor with createCustomSpanProcessor from @elto/telemetry.

Browser Logger (Non-Effect)

For browser contexts where Effect is not available:

import { createBrowserLogger, getOtelMode } from "@elto/telemetry/web";

const getEndpoint = () =>
  getOtelMode() === "proxy"
    ? "https://api.example.com/api/signals"
    : "http://localhost:4318/v1/logs";

const logger = createBrowserLogger({
  resource: {
    serviceName: "web-client",
    serviceVersion: "1.0.0",
  },
  logsEndpoint: getEndpoint,
});

logger.info("User logged in", { userId: "123" });
logger.error("Operation failed", { operation: "checkout", error: "timeout" });
await logger.flush(); // Flush before page unload

API Reference

Common (@elto/telemetry)

createCustomSpanProcessor(delegate: SpanProcessor)

Wraps a delegate span processor (for example, BatchSpanProcessor) with the sanitization rules described above.

Node.js (@elto/telemetry/node)

createNodeOtelLayer(config: NodeSdkConfig)

Creates an Effect Layer with OpenTelemetry configured for Node.js.

Config:

  • resource.serviceName - Service name for telemetry
  • resource.serviceVersion - Service version
  • endpoints - Endpoint URLs (use createEndpoints() helper)
  • metricExportIntervalMs - Optional, default 10000ms

Returns: Effect Layer for OpenTelemetry

createEndpoints(baseUrl: string)

Generates OTLP endpoint URLs for traces, logs, and metrics.

Example:

createEndpoints("http://localhost:4318")
// Returns:
// {
//   traces: "http://localhost:4318/v1/traces",
//   logs: "http://localhost:4318/v1/logs",
//   metrics: "http://localhost:4318/v1/metrics"
// }

DEFAULT_OTEL_ENDPOINT

Default OpenTelemetry collector endpoint: "http://localhost:4318"

Browser (@elto/telemetry/web)

createWebOtelLayer(config: WebSdkConfig)

Creates an Effect Layer with OpenTelemetry configured for browsers.

Config:

  • resource.serviceName - Service name for telemetry
  • resource.serviceVersion - Service version
  • endpoints - Fallback endpoint URLs
  • getEndpoints - Optional function to dynamically get endpoints (for mode switching)

Returns: Effect Layer for OpenTelemetry

createDirectEndpoints(baseUrl: string)

Creates endpoints for direct connection to OpenTelemetry collector.

createProxyEndpoints(config: ProxyConfig)

Creates endpoints for proxy mode (telemetry sent through server).

Config:

  • serverUrl - Your server URL
  • tracesPath - Optional, defaults to "/api/events"
  • logsPath - Optional, defaults to "/api/signals"

createModeBasedEndpoints(directUrl: string, proxyConfig: ProxyConfig)

Creates a function that returns endpoints based on the current mode.

Example:

const getEndpoints = createModeBasedEndpoints(
  "http://localhost:4318",
  { serverUrl: "https://api.example.com" }
);

getOtelMode(): OtelMode

Returns the current telemetry mode from localStorage ("direct" or "proxy").

setOtelMode(mode: OtelMode): void

Sets the telemetry mode in localStorage.

withOtel(otelLayer, layer)

Helper to merge OpenTelemetry layer with another layer.

createBrowserLogger(config: BrowserLoggerConfig)

Creates a standalone logger for non-Effect browser contexts.

Config:

  • resource.serviceName - Service name
  • resource.serviceVersion - Service version
  • logsEndpoint - Endpoint URL or function that returns URL

Returns: Logger instance with methods: debug, info, warning, error, flush

Proxy Mode

Browser apps can send telemetry through your server instead of directly to the collector. This:

  • Hides OpenTelemetry infrastructure from the browser
  • Works around CORS restrictions
  • Provides obscured endpoint names (/api/events, /api/signals)

Implementation

  1. Browser: Use createModeBasedEndpoints() to support both modes
  2. Server: Add proxy endpoints that forward to your collector
  3. User Control: Use setOtelMode("proxy") to switch modes

Example server proxy (Express):

app.post("/api/events", async (req, res) => {
  // Forward to OTLP collector traces endpoint
  await fetch("http://localhost:4318/v1/traces", {
    method: "POST",
    headers: req.headers,
    body: req.body,
  });
  res.sendStatus(200);
});

app.post("/api/signals", async (req, res) => {
  // Forward to OTLP collector logs endpoint
  await fetch("http://localhost:4318/v1/logs", {
    method: "POST",
    headers: req.headers,
    body: req.body,
  });
  res.sendStatus(200);
});

TypeScript

All types are exported from the main package and subpath exports:

import type { ResourceConfig, EndpointConfig } from "@elto/telemetry";
import type { NodeSdkConfig } from "@elto/telemetry/node";
import type { WebSdkConfig, OtelMode, BrowserLogger } from "@elto/telemetry/web";

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

Apache-2.0