Dynamic tracing for javascript, in javascript (similar dtrace, ktap etc)

Overview

jstrace

Dynamic tracing for JavaScript, written in JavaScript, providing you insight into your live nodejs applications, at the process, machine, or cluster level.

Similar to systems like dtrace or ktap, the goal of dynamic tracing is to enable a rich set of debugging information in live processes, often in production in order to help discover the root of an issue. These libraries have very minimal overhead when disabled, and may be enabled externally when needed.

View the wiki for additional information and libraries which may be helpful.

Installation

Library:

$ npm install jstrace

Client:

$ npm install -g jstrace

Features

  • dynamic tracing :)
  • local / remote execution support
  • minimal overhead when idle
  • flexible scripting capabilities
  • probe name filtering
  • pid, process title, and hostname filtering
  • remote messaging for map/reduce style reporting
  • multi-process support, inspect your cluster in realtime
  • binds to 0.0.0.0:4322 (may need this for firewalls)

Usage


  Usage: jstrace [options] <script>

  Options:

    -h, --help             output usage information
    -V, --version          output the version number
    -p, --pid <pid>        trace with the given <pid>
    -t, --title <pattern>  trace with title matching <pattern>
    -H, --host <pattern>   trace with hostname matching <pattern>

Example

Instrumentation

Suppose for example you have probes set up to mark the start and end of an http request, you may want to quickly tap into the process and see which part of the request/response cycle is hindering latency.

This contrived example isn't very exciting, and only has two probes, but it illustrates the capabilites. We simply mark the start and end of the request, as well as providing the request id.

var trace = require('jstrace');
var http = require('http');

var ids = 0;

var server = http.createServer(function(req, res){
  var id = ++ids;

  trace('request:start', { id: id });
  setTimeout(function(){

    res.end('hello world');
    trace('request:end', { id: id });
  }, Math.random() * 250 | 0);
});

server.listen(3000);

Local analysis

jstrace-local analysis is performed by exporting a .local function; When you invoke .on() jstrace internally broadcasts this information to the remotes when they connect and filters probes accordingly. The data is transmitted as-is from the remote for analysis.

exports.local = function(traces){
  traces.on('request:*', function(trace){
    console.log(trace);
  });
};

Local analysis can be expensive since entire objects are transferred, if you need less information or would prefer to distribute the load you can use the remote analysis feature.

Remote analysis

Remote analysis serializes the .remote function to the target processes for remote execution. This can be great for reporting on data that would be too expensive to transfer over the wire to jstrace(1). For example suppose you just want to know the lengths of BLOBs sent to your API:

exports.remote = function(traces){
  traces.on('api:buffer', function(trace){
    console.log(trace.buffer.length);
  });
};

Note the use of console.log(), jstrace provides custom console.log(), console.error(), and console.dir() methods which report back to jstrace(1). You'll now receive something like the following:

12323
232
32423
2321

When analysing a machine or cluster it's useful to know which machine did what, so the console.dir() method prefixes with the hostname, process title, and pid:

api-1/api/1234 >> 123132
api-1/api/1234 >> 3212
api-2/api/1200 >> 4324

Note that unlike .local you need to require() your modules from within the .remote function.

Remote cleanup

When you perform evented operations in your remote function, like setInterval() or listening for events on emitters other than traces, listen for the "cleanup" event in order to finish the trace script completely once the cli exits:

exports.remote = function(traces){
  traces.on('api:buffer', function(trace){
    // will automatically be cleaned up
  });

  var id = setInterval(function(){
    console.log(Date.now());
  });

  traces.on('cleanup', function(){
    clearInterval(id);
  });
};

Local & remote analysis

Local and remote methods may be used in tandem for map/reduce style reporting. Using traces.emit() in the .remote function you can transmit custom information back to jstrace for display or further analysis.

var bytes = require('bytes');

exports.remote = function(traces){
  traces.on('api:buffer', function(trace){
    traces.emit('buffer size', trace.buffer.length);
  });
};

exports.local = function(traces){
  traces.on('buffer size', function(n){
    console.log('buffer %s', bytes(n));
  });
};

It's worth noting that .on() in .local is used for both remote probe subscription, and events emitted by the .remote. Since they share this space you wouldn't want to emit similar names, for example traces.emit('api:buffer', ...) would be bad, since local would actually end up subscribing to the original trace instead of the data emitted. This is rarely an issue but something to be aware of.

Full analysis example

The jstrace(1) executable accepts a script which exports functions with trace patterns to match. These function names tell jstrace which traces to subscribe to. The trace object passed contains the information given to the in-processe trace() call, along with additional metadata such as .timestamp, .hostname, .pid, and .title.

We can use this data to add anything we like, here we're simply mapping the requset ids to output deltas between the two. Note that we export the function named .local, there are two functions supported by jstrace, however .local means that the trace objects are sent over the wire and analysis is performed local to jstrace(1).

var m = {};

exports.local = function(traces){
  traces.on('request:start', function(trace){
    m[trace.id] = trace.timestamp;
  });

  traces.on('request:end', function(trace){
    var d = Date.now() - m[trace.id];
    console.log('%s -> %sms', trace.id, d);
  });
};

To run the script just pass it to jstrace(1) and watch the output flow!

$ jstrace response-duration.js

298 -> 50ms
302 -> 34ms
299 -> 112ms
287 -> 184ms
289 -> 188ms
297 -> 124ms
286 -> 218ms
295 -> 195ms
300 -> 167ms
304 -> 161ms
307 -> 116ms
301 -> 206ms
305 -> 136ms
314 -> 19ms

Plotting distribution

Using node modules such as bars can aid in analysis, for exmaple plotting the distribution of response status codes over time.

var clear = require('clear');
var bars = require('bars');

var m = {};

exports.local = function(traces){
  traces.on('request:end', function(trace){
    m[trace.status] = m[trace.status] || 0;
    m[trace.status]++;
  });
};

setInterval(function(){
  clear();
  console.log();
  console.log(bars(m, { bar: '=', width: 30 }));
}, 1000);
  200 | ============================== | 6
  404 | ====================           | 4
  500 | ====================           | 4
  505 | ===============                | 3
  400 | ==========                     | 2
  201 | =====                          | 1


  201 | ============================== | 19
  500 | ===========================    | 17
  505 | =====================          | 13
  200 | ===================            | 12
  404 | ===================            | 12
  400 | =================              | 11


  500 | ============================== | 19
  201 | ========================       | 15
  200 | ===================            | 12
  404 | ===================            | 12
  505 | =================              | 11
  400 | ===========                    | 7

...

To reset the data per-interval tick all you'd have to do is add m = {}; at the end of the setInterval() callback to refresh the data!

Charting

Create realtime charts using chart to monitor changes over time:

var chart = require('chart');
var clear = require('clear');

var data = [];
var n = 0;

exports.local = function(traces){
  traces.on('request:end', function(trace){ n++ });
};

setInterval(function(){
  data.push(n);
  n = 0;
  clear();
  console.log(chart(data));
}, 1000);

Conventions

Naming probes

In general you should use ":" as a separator for pattern matching, and prefix with something relevant for your module, such as the module's name. Here are some examples:

  • express:request:start
  • express:socket:error
  • koa:request:start
  • koa:request:end
  • myapp:login
  • myapp:logout

You should also consider listing probe names with descriptions in your library or application readme file.

Dependency injection

If your library supports tracing, it's best that you do not add jstrace as a dependency, instead you should provide a trace option to let the user pass in jstrace if they wish. Some people call this "dependency injection". For example:

function MyLib(opts) {
  opts = opts || {};
  this.trace = opts.trace || function(){};
  this.trace('something', { some: 'data' });
}

The premise here is that the community should start instrumenting libraries with this functionality so that node becomes easier to profile, monitor, and debug. This is especially important for detecting latency issues across async boundaries, as they not necessarily CPU-bound and may not show up in profiles at all.

Trace object

The trace object sent to both local and remote subscription handlers.

  • timestamp timestamp at the time of invocation
  • hostname machine hostname
  • title process title
  • pid process id
  • name trace name
  • * all other properties given

Authors

  • TJ Holowaychuk
  • Julian Gruber

License

MIT

Comments
  • Add remote cleanup

    Add remote cleanup

    Example:

    exports.remote = function(trace){
      var id = setInterval(function(){
        // ...
      });
    
      return function unsubscribe(){
        clearInterval(id);
      };
    };
    

    If this looks good, I'll add docs

    opened by juliangruber 6
  • statsd style reporting

    statsd style reporting

    I know it goes against the intended design of being mostly idle, so close if no - however, would (batched?) transmission of trace data (during low cpu time?) over udp to a remote server ever be in scope? What's your solution for historical data?

    opened by jpillora 6
  • halt remote execution

    halt remote execution

    Once you start a script with remote execution it will run forever in the host process.

    To reproduce:

    • start a server
    • start remote tracing script
    • ^C
    • start remote tracing script
    • see double output
    opened by juliangruber 4
  • Add faster trace() api

    Add faster trace() api

    Creating objects for trace probes, like

    trace('foo', { bar: 'baz' })
    

    is by no means a noop when tracing is off.

    This api would be way faster:

    trace('foo', 'bar', 'baz')
    trace('probe', 'keyA', objA, 'keyB', objB)
    

    I created a jsperf case for this: http://jsperf.com/noop-object I suggest adding this as an alternate api.

    What do you think?

    opened by juliangruber 2
  • fix sometimes off server.title

    fix sometimes off server.title

    although I had process.title = 'appname' in my bin script, after all the require()s, the server's title was still the old value, therefore process title filtering didn't work

    opened by juliangruber 2
  • Fix reserved properties

    Fix reserved properties

    If you do trace('foo', { name: 'bar' }) that overrides an internally property, but you're not notified of that.

    The first commit implements warning on the server's stderr, if you just want to merge that.

    However, the client should ultimately print the error, so the client is the only site jstrace ever prints something on.

    server.error(str) and remote.error(str) could probably be combined somehow...

    opened by juliangruber 2
  • remote: add process.{stdout,stderr}

    remote: add process.{stdout,stderr}

    First I refactored the actor protocol to take stdio data as argument and not member of an object (like {stream:'stdout',val:"foo"}) so it works with buffers too.

    Then i added process.{stdout,stderr} as through streams for remote scripts.

    • [ ] Should I swap require('stream').Transform with require('readable-stream').Transform, for 0.8.x support?
    • [ ] Should the remote fn actually override process.{stdout,stderr} instead of just using the passed in process, so node modules like clear, which are not in the same scope, also get to use the patched stdio streams?
    opened by juliangruber 2
  • shared SIGUSR[n] lib instead of polling

    shared SIGUSR[n] lib instead of polling

    need moar user signals! but I was thinking maybe a shared USR module would be handy, you could send SIGUSR2 to a process immediately after say populating some file with the type of event, effectively giving you infinite user signals.

    alternatively we could just watch a file for touches, that might be a better way to go

    enhancement 
    opened by tj 1
  • improve perf

    improve perf

    in some cases we could even just send the script to the process so we're just shipping the output back for display. json serialization for really hot code is no good

    opened by tj 0
  • support DEBUG

    support DEBUG

    I find myself doing this lots in dev since it's faster than writing scripts:

        debug('unsupported %j', msg);
        trace('unsupported', { msg: msg });
    
    enhancement 
    opened by tj 9
  • better connection strategy

    better connection strategy

    constantly trying to connect with the 5s max backoff is kind of lame, we could increase it and make that even more lame, or come up with a different strategy. Maybe fire off UDP packets to wake things up

    opened by tj 0
Owner
null
A project to showcase a poc of distributed systems with message queue, graphql, grpc, http server with added monitoring and tracing capabilities.

trace-sandbox Trace sandbox is a project to showcase a poc of distributed systems with message queue, graphql, grpc, http server with added monitoring

Alfian Pramudita 6 Jun 24, 2021
A tiny JavaScript debugging utility modelled after Node.js core's debugging technique. Works in Node.js and web browsers

debug A tiny JavaScript debugging utility modelled after Node.js core's debugging technique. Works in Node.js and web browsers. Installation $ npm ins

Sloth 10.5k Dec 30, 2022
A pretty darn cool JavaScript debugger for Brackets

Theseus Theseus is a new type of JavaScript debugger for Node.js, Chrome, and both simultaneously. It is an extension for the Brackets code editor. Th

Adobe Research 1.3k Dec 20, 2022
An lldb plugin for Node.js and V8, which enables inspection of JavaScript states for insights into Node.js processes and their core dumps.

Node.js v10.x+ C++ plugin for the LLDB debugger. The llnode plugin adds the ability to inspect JavaScript stack frames, objects, source code and more

Node.js 1k Dec 14, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
A Node.js tracing and instrumentation utility

njsTrace - Instrumentation and Tracing njstrace lets you easily instrument and trace you code, see all function calls, arguments, return values, as we

Yuval 354 Dec 29, 2022
A project to showcase a poc of distributed systems with message queue, graphql, grpc, http server with added monitoring and tracing capabilities.

trace-sandbox Trace sandbox is a project to showcase a poc of distributed systems with message queue, graphql, grpc, http server with added monitoring

Alfian Pramudita 6 Jun 24, 2021
Tracing the easy way using JSON.

MikroTrace Tracing the easy way using JSON. JSON tracer that tries to emulate OpenTelemetry semantics and behavior. Built as a ligher-weight way to ha

Mikael Vesavuori 11 Nov 14, 2022
An Amazon Kendra REST API CDK example with an API Gateway, including authentication with AWS Cognito and AWS X-Ray Tracing

Amazon Kendra Web Service CDK Sample Amazon Kendra has a robust JSON API for use with the AWS SDK (software development kit), but does not expose endp

AWS Samples 8 Nov 28, 2022
Dynamic-web-development - Dynamic web development used CSS and HTML

Dynamic-web-development ASSISNMENT I just used CSS and HTML to make a mobile int

null 1 Feb 8, 2022
dynamic-component-app is an angular application for dynamic component template creation

MyApp This project was generated with Angular CLI version 14.1.0. Development server Run ng serve for a dev server. Navigate to http://localhost:4200/

Aniket Muruskar 7 Aug 26, 2022
we learn the whole concept of JS including Basics like Object, Functions, Array etc. And Advance JS - Understanding DOMs, JQuery, Ajax, Prototypes etc.

JavaScript-for-Complete-Web Development. we learn the whole concept of JS including Basics like Object, Functions, Array etc. And Advance JS - Underst

prasam jain 2 Jul 22, 2022
A bot Similar to the reaction roles discord bot, but free. Written in JavaScript, and uses MongoDB.

Discord Reaction Roles bot About • Features • Installation • Setting Up About An open source reaction roles bot to anyone who needs one in their serve

null 52 Dec 22, 2022
An in-browser JavaScript variable dumper, similar in functionality to ColdFusion's cfdump tag.

prettyPrint.js © James Padolsey prettyPrint.js is an in-browser JavaScript variable dumper, similar in functionality to ColdFusion's cfdump tag. First

Padolsey (Archived Projects) 655 Sep 18, 2022
Colr Pickr, a vanilla JavaScript color picker component built with SVGs, with features like saving colors. Similar design to the chrome-dev-tools color picker.

Colr Pickr Colr Pickr, a vanilla JavaScript color picking component built with SVGs, with features like saving colors. Similar design to the chrome-de

TEK 27 Jun 27, 2022
Detect copy-pasted and structurally similar code

Detect copy-pasted and structurally similar JavaScript code. Requires Node.js 6.0+, and supports ES6, JSX as well as Flow. Note: the project has been

Daniel St. Jules 3.5k Dec 26, 2022
MyDrive is an Open Source cloud file storage server (Similar To Google Drive)

MyDrive is an Open Source cloud file storage server (Similar To Google Drive). Host myDrive on your own server or trusted platform and then access myDrive through your web browser. MyDrive uses mongoDB to store file/folder metadata, and supports multiple databases to store the file chunks, such as Amazon S3, the Filesystem, or just MongoDB. MyDrive is built using Node.js, and Typescript. The service now even supports Docker images!

null 2.8k Dec 30, 2022
A jQuery plugin that displays a thumbnail grid expanding preview similar to the effect seen on Google Images.

jQuery GRIDDER 1.4.2 ======= A jQuery plugin that displays a thumbnail grid expanding preview similar to the effect seen on Google Images. We have all

Orion Gunning 455 Nov 6, 2022