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

hawkly

v0.5.20

Published

An OpenTracing compatible tracer for hawkly.io

Downloads

34

Readme

hawkly tracer for javascript (opentracing)

Work in progress

This is a distrubuted tracing library that allows you to instrument your application.

yarn add --dev hawkly

// or

npm install --dev hawkly

Concepts

Briefly, at the top level we have a Trace, which is comprised of Spans. Spans represent a single unit of work. Exactly what a span is, is up to you. You want enough detail to understand your application, but no so many that it's all noise.

To make a Trace you first create a Span. If the Span has no relationship it's automatically set as the root Span. When you're ready to start another unit of work, you create another Span and link it to the parent Span.

There are two types of links (also called references):

  • childOf where the child Span depends upon the parent Span, a blocking function such as a request/response,
  • followsFrom where the child Span does not depend unpon the parent Span, a non blocking function like emitting an event.

Usage

hawkly tracer is built ontop of opentracing, so all the instrumentation you do is not unqiue to hawkly, and will work if you switch your tracer to a something else that is opentracing compatible.

In order to record spans, you need to instiate a tracer.

import Tracer from 'hawkly';

const tracer = new Tracer({
  // Get your accessToken from hawkly.io
  accessToken: 'yourAccessToken',
  // More on naming conventions below
  componentName: 'serviceName/functionName',

  // (Optional)
  // This callback is called just before sending a http request to record the span,
  // or if you passed the recordCallback callback, it's run just before that.
  // This gives you an opportunity to strip any information that should not be sent, such as
  // Personally Identifyable Information.
  // Be careful not to transform the shape of report though, as all fields are required.
  // The best approach is to replace it with 'REDACTED'.
  sanitiseCallback:(report) => {  },

  // (Optional)
  // You can provide your own recording callback.
  // This prevents a http request to hawkly.io, and lets you handle sending the spans
  // This is useful serverside as it lets you batch the requests before they're sent.
  recordCallback: (report) => {  },
});

// Create a new span, that represent a unit or work
const span = tracer.startSpan('someOperation');
// Optionally you can tag this span
span.tag('key', 'value')

// All your logging happends on the span.
// Pass an object with `event`, and `payload`, to the span.log() function, to record a log
span.log({
    event: 'read',
    payload: {duration: 1000},
})
// When the work is done, call .finish() to end the span, and send it off for recording.
span.finish();

Related Spans

At it's most basic this is how to link spans together.

Remember to always .finish() the Span at the right time, otherwise the durations for the Spans will not be accurate.

// childOf
const parentSpan = tracer.startSpan('parentOperation');
const childSpan = tracer.startSpan('childOperation', {childOf: parentSpan});
childSpan.finish();
parentSpan.finish();

// childOf
const parentSpan = tracer.startSpan('parentOperation');
const childSpan = tracer.startSpan('childOperation', {followsFrom: parentSpan});
parentSpan.finish();
childSpan.finish();

The helper for childOf is part of the spec, but followsFrom is not. If you want to write the most portable instrumentation you can alternitively write the following when you need a followsFrom, as it's part of the spec and will work with other tracers too.

// Make sure you import opentracing
import opentracing from 'opentracing';

// create a tracer as you normally would, then create your followsFrom span like this:
tracer.startSpan("operation name", {
    references: [
      opentracing.followsFrom(parentContext),
      ],
  }
)

How to cross a process boundary / Distributed Tracing

In order to maintain a trace between processes we need to inject some information your carrier on one side, and extract it into a new Span on the other side.

The carrier refers to the message that is being sent between processes. It may be a HTTP request, response, a message on a message queue, or something else.

At the moment, this tracer implementation only supports carriers that are JSON objects.

We don't inject the whole Span into the carrier, it's way to large. Instead we inject what we call the span's Context. This is essentially a bunch of id's that allow us to link the spans together.

// Process 1
const carrier: any = {};
const span: any = tracer.startSpan('someOperation');
tracer.inject(span, 'text_map', carrier);
span.finish();

// ---

// Process two

const carrier = JSON.parse(request);
const childSpan: any = tracer.join('childSpan', carrier, 'text_map');
// Do work
childSpan.finish();

When you use tracer.join() to create a new Span from the Context in the carrier;

Typescript

If you're using Typescript you can import the source directly by using the following import:

import {Tracer} from 'hawkly/src';

Global Tracer

You can take advantage of a singleton in the opentracing module as follows:

import Tracer from 'hawkly';
opentracing.initGlobalTracer(new Tracer());

const tracer = opentracing.globalTracer();

This allows you to initialise the hawkly tracer at the start of your application, and then just import opentracing everywhere else. This makes it easy for you to switch tracing implementations at a later date if you decide.

Also, by default the opentracing implementation is no-op, meaning unless you supply it a tracer with .initGlobalTracer() it will basically not do anything. This means you can disable tracing if you wish.

More information

API docs for opentracing and more information on the javascript implementation can be found here: https://github.com/opentracing/opentracing-javascript


hawkly.io Owen Kelly