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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@fwl/tracing

v0.10.9

Published

Tracing part of Fewlines Web Libraries

Downloads

93

Readme

FWL Tracing

Disclaimer: this package is made for our internal usage and is only open source for convenience so we might not consider Pull Requests or Issues. Feel free to fork though.

This is part of the Fewlines Web Libraries packages. It provides a simple way to do tracing with OpenTelemetry.

Installation

yarn add @fwl/tracing

Getting Started

As OpenTelemetry libraries need to monkey patch packages before them being called, starting the tracer should be the first thing you do.

Here's an example with a simple collector (e.g. Zipkin):

import { getTracer, startTracer } from "@fwl/tracing";

startTracer({
  simpleCollector: {
    serviceName: "serviceName",
    url: "http://localhost:9411/api/v2/spans",
  },
});

const tracer = getTracer();

Configure several exporters

import { getTracer, startTracer } from "@fwl/tracing";

startTracer({
  collectors: [
    {
      type: "otel",
      serviceName: "serviceName",
      url: "http://localhost:29799/v1/traces",
    },
    {
      type: "otel",
      serviceName: "serviceName",
      url: "http://localhost:8360/api/v2/otel/trace",
      authorizationHeader: {
        key: "Lightstep-Access-Token",
        value: "developer",
      },
    },
  ],
});

Note that if you configure several exporters, the serviceName property that will be used to define the service name of all exporters will be the first one.

Lightstep

And an example with a Lightstep public satellite:

import { getTracer, startTracer } from "@fwl/tracing";

startTracer({
  lightstepPublicSatelliteCollector: {
    serviceName: "serviceName",
    accessToken: process.env.LIGHTSTEP_ACCESS_TOKEN,
  },
});

const tracer = getTracer();

If you want to use Lightstep in developer mode, you could add an URL:

startTracer({
  lightstepPublicSatelliteCollector: {
    serviceName: "serviceName",
    accessToken: "",
    url: "http://localhost:8360/api/v2/otel/trace",
  },
});

Usage

Once you have a tracer (of type Tracer), you will have a span method:

import { Span, Tracer } from "@fwl/tracing";

// ...
function(tracer: Tracer) {
  tracer.span("span name", async (span: Span) => {
    // If you want to add attributes to your span with a visible value
    span.setDisclosedAttribute(key, value);

    // If you want to add attributes to your span with a redacted value
    span.setAttribute(key, value);

    // any code there that return a Promise (in this example, the callback is an `async` function so any value should do
  });
}

This way is the recommended way as it will automatically end the span for you. However, if you ever are in need to more fine grain control (for instance, in a middleware), you can use createSpan:

Here is an example of a logging middleware for Express:

import { NextFunction, Request, Response } from "express";
import { Logger } from "@fwl/logging";
import { Tracer, Span } from "@fwl/tracing";

export function loggingMiddleware(tracer: Tracer, logger: Logger) {
  function onCloseOrFinish(span: Span, startTime: bigint): () => void {
    return function () {
      const response = this as Response;
      response.removeListener("finish", onCloseOrFinish);
      const end = process.hrtime.bigint();
      logger.log(
        `${response.req.path}: ${response.statusCode} in ${end - startTime}`,
      );
      span.end();
    };
  }
  return function (
    _request: Request,
    response: Response,
    next: NextFunction,
  ): void {
    const startTime = process.hrtime.bigint();
    const span = tracer.createSpan("logging middleware");
    response.once("finish", onCloseOrFinish(span, startTime));
    next();
  };
}

Keep in mind that this method is only required because we need to call next() and we want to start the span across the whole request. The recommended method is to use tracer.span.

Tracing during tests

If you need to use the tracer in a testing environment, we provide a InMemoryTracer class that act as a regular tracer, except you won't have to launch jaeger to run your tests.InMemoryTracer also provides you with a way of testing your spans with the use of the searchSpanByName. The usage is the same, you just need to initialize InMemoryTracer instead of using startTracer().

Here is an example of use in a test file using jest:

import { InMemoryTracer } from "@fwl/tracing";

let tracer: InMemoryTracer;

beforeEach(() => {
  tracer = new InMemoryTracer();
});

test("verify span attributes", () => {
  expect.assertions(1);

  // Call the code that is using a tracer.

  const [span] = tracer.searchSpanByName("test-span");

  expect(span.attributes[0].attributeName).toBe("attribute value");
});