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

@emartech/telemetry-javascript

v1.5.2

Published

Telemetry package for Typescript/Javascript code use

Downloads

2,275

Maintainers

luca.fasolino.seluca.fasolino.sermafteiuscairmafteiuscailhammerllhammerlbencsobencsomfel0123mfel0123franziskajungfranziskajungd056437d056437ekkovatsekkovatslaralangnaularalangnauemarsys-stephen-ivesemarsys-stephen-ivestothbence8tothbence8earlpittsearlpittsiabrahamiabrahamzhollerzhollerbalintkemenyemarsysbalintkemenyemarsysccarrollemccarrollemdunaicapadunaicapabobby_russelbobby_russelsovagossovagoscyholdencyholdentothmarci25tothmarci25mariannagmariannagestefanlesnjakovicestefanlesnjakovicmrmeszarosmrmeszarosbence.tothbence.tothjason-nelson-01jason-nelson-01drahos.istvandrahos.istvanpeccpeccbirokhunbirokhunlaszlo.orilaszlo.oridpkemarsysdpkemarsysnathan-matthews-sapnathan-matthews-saptroywiegandtroywiegandnikolett.tarnikolett.tarbronikabronikacenglersapcenglersapmlesh-sapmlesh-sapgillyesgillyesdanielisapdanielisapsridevirsridevirabieler-sapabieler-sapaidanlesh-sapaidanlesh-saptonyhsaptonyhsapkarlabrandlkarlabrandlkonradschewekonradschewemanasbommakantimanasbommakantidudaaslacidudaaslacithomaskmartinthomaskmartinemarsys-securityemarsys-securitynorbert-levajsics-emarsysnorbert-levajsics-emarsysronnykrosseronnykrossevszegedivszegedisap-amsap-amnnieman-sapnnieman-sapariceemariceemdwolter_emarsysdwolter_emarsysrcsullagrcsullagttoth2ttoth2tbucsanszkitbucsanszkidszunomardszunomardschuppadschuppaandras.sarroandras.sarrondomkendomkesevket-atasevensevket-atasevenplsapplsapmattfeldhake_emarsysmattfeldhake_emarsysatittelatittelandrasp3aandrasp3amruellmruelladroszleradroszlererikpetroemarerikpetroemarrimo86rimo86tillmannrtillmannrmarkjarvismarkjarvisgeczirobertgecziroberttsiraitnpmtsiraitnpmbankyadambankyadambborsibborsizbalazszbalazsziyadgziyadgpinterapinteraapoonapoonianhelmrichianhelmrichvarszegikvarszegikrkumari03rkumari03cseby92cseby92bozsadambozsadamjfillmorejfillmoreviktor.szellviktor.szellbencekadaremarbencekadaremarroxanamsroxanamsdkocsis-emarsysdkocsis-emarsysdemajo_emsdemajo_emsmarko.fritzschemarko.fritzscheagruczaagruczadmorvaidmorvainish343nish343koloshkoloshazorahai3904azorahai3904skrivooskrivoomark.adorjanmark.adorjanburciburcidimitrovndimitrovnivanfroehlichivanfroehlichiulianmihaiiulianmihaixueboliangxuebolianggresztergreszterbercziandbercziandcrileycrileydrewhodsonsapdrewhodsonsapjviesersapjviesersapsixstepsixstepsap-jjfsap-jjfsapfssapfsattilamuller01attilamuller01scotthetrickscotthetrickoliverweisenburgeroliverweisenburgermaurogrecomaurogreconicolaeciumacnicolaeciumacasciortino1asciortino1pendicg24pendicg24marton.matusekmarton.matusekadamszabolcsadamszabolcsbtalosbtalosbence.utobence.utodaniels1404daniels1404saphendricksjoergsaphendricksjoergmmartin2mmartin2fenyopetifenyopetimmothersillmmothersillbrandon-sapbrandon-sappjohnson02pjohnson02mhunyadymhunyadyfaridtoubalfaridtoubalmengjiao.zhaomengjiao.zhaoushnpmushnpmdkorposdkorposxin.hexin.heviauviauzsomborhzsomborhmuddammuddamnvkaur2nvkaur2jbleclercjbleclercjamescockerjamescockerarnaud.buchholzarnaud.buchholzjerryrichardsonjerryrichardsonretfalvibenceretfalvibenceakapaakapamklsmklsprobalazsprobalazskaajkaajknagyknagyrehrethrehrethmhegedusmhegedusmmartinmmartinbsoosbsoosemarsys-deployeremarsys-deployerdravendravenjudgejudgedaniel.bankydaniel.bankyszeistszeistrgargyargargyamarton.papp.emarsysmarton.papp.emarsysdgyenesdgyeness.viktors.viktorm4w4q7m4w4q7david.barkoczidavid.barkocziqw3rqw3rtamas.tothtamas.tothgergaczdgergaczdgerikegerikealkraalkraepgrubmairepgrubmairmorbanmorbanettancosettancosepmartiniepmartinigabor.balla.emarsysgabor.balla.emarsysmzsombormzsomborejperssonejperssonejwalkerejwalkerllosonczyllosonczyiben12iben12kartonfarkaskartonfarkasadamoaadamoambarnambarnapevapevabforgacsbforgacskozmakozmangabor84ngabor84zerosuxxzerosuxxedosreckiedosreckieadanieleadanielselatorselatorkkimakkkimakgaborbgaborbglendvaiglendvailverasztolverasztordoczirdoczifentosifentosiboristomicboristomicmbazsombazsodmihalekdmihaleklhalaszlhalaszevspasevskievspasevskidsztankodsztankotbugartbugarfqqdkfqqdkeggarciaeggarciamenyhertfatyolmenyhertfatyolzoltanrideg-emarsyszoltanrideg-emarsyssarakollsarakollmmolnar-emarmmolnar-emarattila.galattila.galbenjamingehlbenjamingehltdorkaatdorkaalkonyalkonyagpap_emagpap_emavimtaaivimtaailloki-emarsyslloki-emarsysborziborzipmaksa_emarsyspmaksa_emarsysdfaragodfarago

Readme

telemetry-javascript

Telemetry Client Library Wrapper

Library for emitting telemetry to an OpenTelmetry Collector via StatsD.

Quickstart

Setup

Environment Variable (optional)
TELEMETRY_CONFIG = {
    'application':'personalization service', 
    'domain':'personalization', 
    'module':'compilation', 
    'metrics': {
        'client':'statsd', 
        'hostname':'127.0.0.1', 
        'port':8125, 
        'enabled':true
    }
}
  • application (default: ''): application using the library.
  • domain (default: ''): default namespace domain of the application.
  • module (default: ''): default namespace module of the applcation.
  • metrics
    • client (default: 'statsd'): statsd metrics client to use.
    • hostname (default: '127.0.0.1'): host to which the metrics client will send metrics data. If running locally in Docker this will be the name of the collector service.
      • Example
        services:
            app:
                environment:
                    - 'TELEMETRY_CONFIG={"metrics":{"hostname":"collector"}}'
    • port (default: 8125): port to which the metrics client will send metrics data.
    • enabled (default: true): true|false controls whether metris will be emitted or not.

Installation

Install the Emarsys telemetry package

npm install @emartech/telemetry-javascript

Write your first metric

import * as metrics from '@emartech/telemetry-javascript';

// With default namespace set
metrics.setDefaultNamespace('personalization', 'compilation');
metrics.incrementCounter('request_count');

Features

  • Instrument your code with OpenTelemetry-compatible metrics with an established path to Google Cloud Monitoring

  • Use out-of-the-box defaults to hook into the Emarsys OpenTelemetry pipeline automatically

  • Insulate your application code from changes to OpenTelemetry or telemetry data platforms

  • Automatically capture the duration of functions

metrics.setDefaultNamespace('personalization', 'compilation');

// Callable
const personalizationString = metrics.time(
        'total_duration',
        [500, 1000, 1500, 2000, 2500, 3000, 3500, 4000]],
        { 'attribute1': 'value1', 'attribute2': 'value2' },
        computePersonalizationString,
        'Hello <name>',
        '<name>',
        'World!',
      );

function computePersonalizationString(
    personlizationString: string, 
    token: string, 
    tokenValue: string): string {

    return personalizationString.replace(token, tokenValue);
}

/*
Result: 'Hello World!'

Metric Name: personalization_compilation_total_duration
Value: Time to execute function in milliseconds
*/

// Decorator
const myClass = new MyClass();
const result = myClass.computePersonalizationString('Hello <name>', '<name>', 'World!');

class MyClass {
    @metrics.timeDecorator('total_duration')
    function computePersonalizationString(
        personlizationString: string, 
        token: string, 
        tokenValue: string): string {

            return personalizationString.replace(token, tokenValue);
    }
}

/*
Result: 'Hello World!'

Metric Name: personalization_compilation_total_duration
Value: Time to execute function in milliseconds
*/
  • Automatically capture the duration and reliability of functions
metrics.setDefaultNamespace('personalization', 'compilation');

// Callable

// Success
const personalizationString = 'Hello <name>';
const token ='<name>';
const tokenValue = 'World!'

const result = metrics.timeAndCount(
        'total',
        () => {
            computePersonalizationString(personalizationString, token, tokenValue);
        },
        [500, 1000, 1500, 2000, 2500, 3000, 3500, 4000]],
        { 'attribute1': 'value1', 'attribute2': 'value2' },
      );

// OR

const result = metrics.metricWrapper(
        'total',
        [500, 1000, 1500, 2000, 2500, 3000, 3500, 4000]],
        { 'attribute1': 'value1', 'attribute2': 'value2' },
        computePersonalizationString,
        'Hello <name>',
        '<name>',
        'World!',
      );

function computePersonalizationString(
    personlizationString: string, 
    token: string, 
    tokenValue: string): string {

    return personalizationString.replace(token, tokenValue);
}

/*
Result: 'Hello World!'

Metric Name: personalization_compilation_total_duration
Value: Time to execute function in milliseconds
Auto-Attribute: 'success:true'

Metric Name: personalization_compilation_total_count
Value: Time to execute function in milliseconds
Auto-Attribute: 'success:true'
*/

metrics.setDefaultNamespace('personalization', 'compilation');

// Failure
const personalizationString = 'Hello <name>';
const token ='<name>';
const tokenValue = 'World!'

const result = metrics.timeAndCount(
        'total',
        () => {
            computePersonalizationString(personalizationString, token, tokenValue);
        },
        [500, 1000, 1500, 2000, 2500, 3000, 3500, 4000]],
        { 'attribute1': 'value1', 'attribute2': 'value2' },
      );

// OR

const personalizationString = metrics.metricWrapper(
        'total',
        [500, 1000, 1500, 2000, 2500, 3000, 3500, 4000]],
        { 'attribute1': 'value1', 'attribute2': 'value2' },
        computePersonalizationString,
        'Hello <name>',
        '<name>',
        'World!',
      );

function computePersonalizationString(
    personlizationString: string, 
    token: string, 
    tokenValue: string): string {
    
    throw new Error();
}

/*
Result: Error

Metric Name: personalization_compilation_total_duration
Value: Time to execute function in milliseconds
Auto-Attribute: 'success:false'

Metric Name: personalization_compilation_total_count
Value: Time to execute function in milliseconds
Auto-Attribute: 'success:false'
*/

// Decorator
const myClass = new MyClass();
const result = myClass.computePersonalizationString('Hello <name>', '<name>', 'World!');

class MyClass {
    @metrics.timeAndCountDecorator('total')
    function computePersonalizationString(
        personlizationString: string, 
        token: string, 
        tokenValue: string): string {

            return personalizationString.replace(token, tokenValue);
    }
}

/*
Result: 'Hello World!'

Metric Name: personalization_compilation_total_duration
Value: Time to execute function in milliseconds
Auto-Attribute: 'success:true'

Metric Name: personalization_compilation_total_count
Value: Time to execute function in milliseconds
Auto-Attribute: 'success:true'
*/
  • Namespace metrics into units based on module, component, or other criteria
const compilationNamespace = metrics.getNamespace(domain='personalization', module='compilation');
compilationNamespace.recordTimer('total_duration', 1000);

// Metric Name: personalization_compilation_total_duration

const executionNamespace = metrics.getNamespace(domain='personalization', module='execution');
executionNamespace.recordTimer('total_duration', 1000);

// Metric Name: personalization_execution_total_duration
  • Flexibly tag metrics at any scope to add metadata to your metrics without extra configuration
// Global attribute
metrics.setAttribute('hostname', 'server4');

// Namespace attribute
const compilationNamespace = metrics.getNamespace('personalization', 'compilation');
compilationNamespace.setAttribute('worker_type', 'reticulator');

// Dynamic attribute
const compilationNamespace = metrics.getNamespace('personalization', 'compilation');
compilationNamespace.incrementCounter(
    'completedJobs_count', 
    { 'attribute1': 'value1', 'attribute2': 'value2' }
);
  • Add metrics to shared code and see them reported independently in consuming applications

Recommended Usage

Application Startup

import * as metrics from '@emartech/telemetry-javascript';

// We will use a single namespace to cover all of the metrics generated by our application, so we set it up as the default. 
metrics.setDefaultNamespace('personalization', 'compilation');
metrics.incrementCounter('total_duration');

// We will explicitly create our metrics in order to provide a description and unit for our metrics
metrics.createCounter('request_Count', 'Number of requests the service received', 'requests');
metrics.createGauge('queue_depth', 'Number of requests currently in the queue', 'requests');

Metric Generation

// Application code - throughout the application, metrics will be generated
import * as metrics from '@emartech/telemetry-javascript';

def process_incoming_request(request):
  metrics.increment_counter('total_requests')
  generated_error = handle_request()
  
  if generated_error:
    metrics.increment_counter('error_requests')

Large, Multi-module Applications

import * as metrics from '@emartech/telemetry-javascript';

// Namespace objects can be created and stored at the module, component, or other level to create separate units for metrics
const compilationNamespace = metrics.getNamespace('personalization', 'compilation');
compilationNamespace.incrementCounter('request_count');

const executionNamespace = metrics.getNamespace('personalization', 'execution');
executionNamespace.incrementCounter('request_count');

Advanced Usage

import * as metrics from '@emartech/telemetry-javascript';

// For each default entity or setting, the deftaults can overriden by using lower-level APIs.
metrics.setDefaultClient(new StatsDClient('endpoint', 0));
metrics.setAttribute('hostname', 'server4');
​
const compilationNamespace = metrics.getNamespace('personalization', 'compilation');
compilationNamespace.setAttribute('namespace_attribute', 'foo');
​
const totalDurationMetric = compilationNamespace.createTimer('total_duration', 'Total duration of blah', 'ms');
totalDurationMetric.setAttribute('metric_attribute', 'bar');
​
totalDurationMetric.record(
    1000, 
    [200, 400, 600, 800, 1000, 1200, 1400],
    { 'attribute1': 'value1', 'attribute2': 'value2' }
);

Including Metrics in Shared Code

import * as metrics from '@emartech/telemetry-javascript';

// When instrumenting a shared library, the shared library should create it's own namespace and write it's metrics there.
// The shared library will rely upon the consuming application to attach any attributes it want's applied to the data to the default metric client.

compilationSharedLibraryNamespace = metrics.getNamespace('personalization', 'compilation_shared_library');
compilationSharedLibraryNamespace.createCounter('compilation_invocations', 'Number of compilation invocations', 'invocations');

compilationSharedLibraryNamespace.incrementCounter('compilation_invocations');

Metric Types

Four types of metrics are supported in Emarsys telemetry libraries:

  • Counters
  • Timers
  • Gauges
  • Histograms
Counter

A counter metric can be incremented or decremented over time and captures the total (sum) of all provided values.

Examples
  • Number of messages processed
  • Number of errors generated
/*
incrementCounter(
    metricName: string,
    value = 1,
    attributes: Record<string, string> = {},
): void;
*/

metrics.incrementCounter(
    'request_count', 
    100, 
    { 'attribute1': 'value1', 'attribute2': 'value2' }
);    
Gauge

A gauge metric stores the current value of something at the time that it was observed. Gauge metrics should be used for data which does not make sense to add together, but instead new measurements should replace old.

The last value of a gauge which is written during a time interval (generally every 60s) overwrites any previous values.

Examples
  • Number of items in a queue
  • Current memory usage of a process
/*
recordGauge(
    metricName: string,
    value: number,
    attributes: Record<string, string> = {},
): void;
*/

metrics.recordGauge(
    'queue_depth', 
    100000, 
    { 'attribute1': 'value1', 'attribute2': 'value2' }
);    
Histogram

A histogram metric stores a statistical summary of multiple values which are recorded within a time interval. Each observation that is recorded is counted in one of a series of “buckets” which are configured for the histogram. This storage method allows for the calculation of statistics after collection such as the minimum, maximum, median, and percentiles (P99, etc.) at a later date.

Visualization of a Histogram

Histogram chart with intervals of 100 showing numerous observations in each interval.

Examples
  • Size of incoming requests
  • Number of personalization tokens in each email
/*
recordHistogram(
    metricName: string,
    value: number,
    buckets: number[] = [0, 5, 10, 25, 50, 75, 100, 250, 500, 1000],
    attributes: Record<string, string> = {},
): void;
*/

metrics.recordHistogram(
    'total_size', 
    2500, 
    [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000],
    { 'attribute1': 'value1', 'attribute2': 'value2' },
);    
Timer

A timer metric can capture how long multiple observations of the same code or process have taken and results in a distribution of these time values. The distribution can be processed to determine the median, P99 or other values of interest.

A timer is a special case of a Histogram metric, which can store the statistical distribution of any type of data.

Examples
  • Time taken to process a message
  • Time taken to run a database query
/*
recordTimer(
    metricName: string,
    value: number,
    buckets: number[] = [0, 10, 25, 50, 75, 100, 250, 500, 1000, 5000, 10000, 30000, 60000, 240000],
    attributes: Record<string, string> = {},
): void;
*/

metrics.recordTimer(
    'total_duration', 
    850, 
    [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],
    { 'attribute1': 'value1', 'attribute2': 'value2' }
);    

Utility Methods

The Emarsys telemetry library provides utility methods

toLowerCamelCase

A hyphenated string is turned into a camel-cased string for use in GCP attribute fields

/*
toLowerCamelCase(
    name: string | undefined
): string
*/

metrics.Util.toLowerCamelCase(
    'telemetry-attribute-example'
);