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

@expresso/tracing

v1.0.7

Published

@expresso tracing tools

Downloads

10

Readme

Tracing

Distributed tracing toolset for expresso. Traces requests using Jaeger.

Summary

How this works

The tracer file will hook in require('http') to auto-instrument every request that is either coming in or going out of the service. This is done by @opentelemetry/node and @opentelemetry/plugin-http.

Meanwhile, the middleware will add some extra info to the traced requests (request/response body, headers and query). This is done using express-mung

Basic Usage

Installing:

$ npm install @expresso/tracing

Tracer

The tracer module is responsible for adding the required headers to all outgoing requests, plus reading headers from and logging incoming requests.

IMPORTANT: This should be intialized on the entrypoint of your application, before you require @expresso/app or any other module that requires node's native http module.

Modules required before the initializing the tracer will not be instrumented

Initialization

import tracer, { IExpressoTracerConfig } from '@expresso/tracer'

const tracerConfig: IExpressoTracerConfig = {
  jaeger: {
    serviceName: process.env.JAEGER_SERVICE_NAME,
    host: process.env.JAEGER.HOST
  }
}

tracer.init(config)

To know more about the config object, see Configuration Object

Middleware

The middleware is used to gather some more information from the request and response objects (body, headers and query) and add it to the jaeger span. This will also add a Jaeger-Trace-Id header to all of your responses.

Usage

import expresso from '@expresso/app'
import tracing from '@expresso/tracing'

export const app = expresso((app, config) => {
  app.use(tracing.factory({
    before: (body, req, res, span, tracer) => { /* do something with the parameters here */ },
    after: (body, req, res, span, tracer) => { /* do something with the parameters here */ }
  }))

  /**
   * All of your enpoints must come after the middleware
   * Endpoints registered before the middleware will not have
   * info about their request and response bodies, headers and queries
  */

  app.get('/endpoint', routes.endpoint.factory(config))
})

Hooks

The middleware factory receives an object with two properties. Both properties are functions that receive the response body,current request, response, span an tracer.

  • before: Will be ran before the middleware does anything to the span. Usefor for removing fields you don't want to be logged to jaeger.

  • after: Will be ran after the span is processed by the middleware, but before it is sent to Jeager.

Configuration Object

The configuration object has the following type:

export type IExpressoTracerConfig = {
  jaeger: {
    // Functions to use for logging
    logger?: types.Logger;
    // Name of the service (this appears on jaeger)
    serviceName: string;
    // Tags to refer to when searching
    tags?: Tag[];
    // Jaeeger host
    host?: string;
    // Jaeger port
    port?: number;
    maxPacketSize?: number;
    /** Force a flush on shutdown */
    forceFlush?: boolean;
    /** Time to wait for an onShutdown flush to finish before closing the sender */
    flushTimeout?: number;
  },
  tracer?: {
    /**
     * Binary formatter which can serialize/deserialize Spans.
     */
    binaryFormat?: BinaryFormat;
    /**
     * Attributed that will be applied on every span created by Tracer.
     * Useful to add infrastructure and environment information to your spans.
     */
    defaultAttributes?: Attributes;
    /**
     * HTTP text formatter which can inject/extract Spans.
     */
    httpTextFormat?: HttpTextFormat;
    /**
     * User provided logger.
     */
    logger?: Logger;
    /** level of logger.  */
    logLevel?: LogLevel;
    /**
     * Sampler determines if a span should be recorded or should be a NoopSpan.
     */
    sampler?: Sampler;
    /**
     * Scope manager keeps context across in-process operations.
     */
    scopeManager?: ScopeManager;
    /** Trace Parameters */
    traceParams?: TraceParams;
  }
}

Adding additional data to spans

Because this uses opentracing's module, you are able to get the tracer and, consequently, the curren span:

import * as opentracing

() => { // suppose this is yout route
  const tracer = opentracing.getTracer() // returns the global tracer
  const span = tracer.getCurrentSpan() // This might return undefined. Be careful!

  span?.addEvent('findUser', { userId: 'some-user-id' })
}

More than that, you can create child spans:

import * as opentracing
import database from './database' // supose this is your db layer

() => { // suppose this is yout route
  const tracer = opentracing.getTracer() // returns the global tracer
  const parent = tracer.getCurrentSpan() // This might return undefined. Be careful!

  const span = tracer.startSpan('find user', { parent })
  span.setAttribute('userId', 'some-user-id')

  await database.findUser('some-user-id')

  span.end()
}

Easy, right? That way you can track any sort of event or operation you want.