pax_global_header00006660000000000000000000000064140336425040014513gustar00rootroot0000000000000052 comment=be36d8f1c8620c456d6b8290198ff1bbe6ed0c30 chrome-trace-event-1.0.3/000077500000000000000000000000001403364250400152045ustar00rootroot00000000000000chrome-trace-event-1.0.3/.gitignore000066400000000000000000000001541403364250400171740ustar00rootroot00000000000000/tmp /node_modules package-lock.json yarn.lock /npm-debug.log /examples/*.log /examples/*.json *.log dist/ chrome-trace-event-1.0.3/.travis.yml000066400000000000000000000004111403364250400173110ustar00rootroot00000000000000sudo: false dist: trusty language: node_js script: - yarn build - yarn test - yarn check_format branches: only: - master cache: yarn: true matrix: include: - os: linux node_js: "8" - os: linux node_js: "6" fast_finish: true chrome-trace-event-1.0.3/CHANGES.md000066400000000000000000000005651403364250400166040ustar00rootroot00000000000000# node-trace-event changelog ## 1.3.1 (not yet released) (nothing yet) ## 1.3.0 - Add `.child()` option to `trace_event.createBunyanTracer()` object. ## 1.2.0 - Add `trace_event.createBunyanLogger()` usage for some sugar. See the README.md for details. ## 1.1.0 - Rename to 'trace-event', which is a much more accurate name. ## 1.0.0 First release. chrome-trace-event-1.0.3/LICENSE.txt000066400000000000000000000021201403364250400170220ustar00rootroot00000000000000# This is the MIT license Copyright (c) 2015 Joyent Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. chrome-trace-event-1.0.3/Makefile000066400000000000000000000020711403364250400166440ustar00rootroot00000000000000 TAPE = ./node_modules/.bin/tape JSSTYLE_FILES := $(shell find lib test -name "*.js") all $(TAPE): npm install .PHONY: clean clean: rm -rf examples/*.json examples/*.log .PHONY: distclean distclean: clean rm -rf node_modules .PHONY: test test: | $(TAPE) $(TAPE) test/*.test.js .PHONY: check-jsstyle check-jsstyle: $(JSSTYLE_FILES) ./tools/jsstyle -o indent=4,doxygen,unparenthesized-return=0,blank-after-start-comment=0,leading-right-paren-ok $(JSSTYLE_FILES) .PHONY: check check: check-jsstyle @echo "Check ok." # Ensure CHANGES.md and package.json have the same version. .PHONY: versioncheck versioncheck: @echo version is: $(shell cat package.json | json version) [[ `cat package.json | json version` == `grep '^## ' CHANGES.md | head -1 | awk '{print $$2}'` ]] .PHONY: cutarelease cutarelease: versioncheck [[ `git status | tail -n1` == "nothing to commit, working directory clean" ]] ./tools/cutarelease.py -p trace-event -f package.json .PHONY: git-hooks git-hooks: [[ -e .git/hooks/pre-commit ]] || ln -s ../../tools/pre-commit.sh .git/hooks/pre-commit chrome-trace-event-1.0.3/README.md000066400000000000000000000015751403364250400164730ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/samccone/chrome-trace-event.svg?branch=master)](https://travis-ci.org/samccone/chrome-trace-event) chrome-trace-event: A node library for creating trace event logs of program execution according to [Google's Trace Event format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU). These logs can then be visualized with [trace-viewer](https://github.com/google/trace-viewer) or chrome devtools to grok one's programs. # Install npm install chrome-trace-event # Usage ```javascript const Trace = require("chrome-trace-event").Tracer; const trace = new Trace({ noStream: true }); trace.pipe(fs.createWriteStream(outPath)); trace.flush(); ``` # Links * https://github.com/google/trace-viewer/wiki * https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU # License MIT. See LICENSE.txt. chrome-trace-event-1.0.3/examples/000077500000000000000000000000001403364250400170225ustar00rootroot00000000000000chrome-trace-event-1.0.3/examples/child.js000066400000000000000000000014231403364250400204430ustar00rootroot00000000000000/* * Show `evt.child()` usage for more practical usage. `.child(fields)` * allows you to bind common fields to emited events. */ var fs = require("fs"); var EVT = new (require("../dist/trace-event")).Tracer(); EVT.pipe(process.stdout); function doSubTaskA(opts, cb) { var evt = EVT.child({ id: opts.id, name: "doSubTaskA" }); evt.begin(); setTimeout(function() { // ... evt.end(); cb(); }, Math.floor(Math.random() * 2000)); } function doSomething(opts, cb) { var evt = EVT.child({ id: opts.id, name: "doSomething" }); evt.begin(); setTimeout(function() { // ... doSubTaskA(opts, function() { evt.end(); cb(); }); }, Math.floor(Math.random() * 2000)); } for (var i = 0; i < 5; i++) { doSomething({ id: i }, function() {}); } chrome-trace-event-1.0.3/examples/event-log.js000066400000000000000000000016621403364250400212650ustar00rootroot00000000000000/* * A simple example showing piping event traces to a 'events.log' file. * * Usage: * $ node event-log.js * hi * bye * $ cat events.log * [{"ts":213699797444,"pid":42628,"tid":42628,"ph":"b","cat":"default","args":{},"name":"doSomething","id":"abc"}, * {"ts":213700798563,"pid":42628,"tid":42628,"ph":"e","cat":"default","args":{},"name":"doSomething","id":"abc"}, */ var fs = require("fs"); var evt = new (require("../dist/trace-event")).Tracer(); evt.pipe(fs.createWriteStream("events.log")); console.log('Streaming events to "events.log"'); // Instrument code with evt.{begin|instant|end} calls. function doSomething(cb) { evt.begin({ name: "doSomething", id: "abc" }); // Takes 1s to do all this processing for "something". setTimeout(function() { evt.end({ name: "doSomething", id: "abc" }); cb(); }, 1000); } console.log("hi"); doSomething(function() { console.log("bye"); }); chrome-trace-event-1.0.3/examples/hello.js000066400000000000000000000022341403364250400204640ustar00rootroot00000000000000/* * A first example showing trace-event usage. * We emit begin/end events for a single call to `doSomething()`. */ /* * First create the tracer `evt` that we'll use for instrumenting code. * * Notes: * - More realistically we'd stream these to an event log file (see * examples/event-log.js). This just shows you the default output. * - By default the emitted 'data' events are make up a JSON array of * event objects, suitable for piping directly to stdout or a file. * This format is as expected by * [`trace2html`](https://github.com/google/trace-viewer#readme). * - See examples/object-mode.js for raw event objects. * - See examples/child.js for a larger example. */ var evt = new (require("../dist/trace-event")).Tracer(); evt.on("data", function(data) { console.log("EVENT: %j", data); }); // Instrument code with evt.{begin|instant|end} calls. function doSomething(cb) { evt.begin({ name: "doSomething", id: "1" }); // Takes 1s to do all this processing for "something". setTimeout(function() { evt.end({ name: "doSomething", id: "1" }); cb(); }, 1000); } console.log("hi"); doSomething(function() { console.log("bye"); }); chrome-trace-event-1.0.3/examples/object-mode.js000066400000000000000000000005561403364250400215560ustar00rootroot00000000000000/* * Show that `{objectMode: true}` is available on a Tracer * to get raw JSON event object output. */ var evt = new (require("../dist/trace-event")).Tracer({ objectMode: true }); evt.on("data", function(ev) { console.log('EVENT (type "%s"): %j', typeof ev, ev); }); evt.begin({ name: "doSomething", id: "abc" }); evt.end({ name: "doSomething", id: "abc" }); chrome-trace-event-1.0.3/lib/000077500000000000000000000000001403364250400157525ustar00rootroot00000000000000chrome-trace-event-1.0.3/lib/trace-event.ts000066400000000000000000000121751403364250400205450ustar00rootroot00000000000000/** * trace-event - A library to create a trace of your node app per * Google's Trace Event format: * // JSSTYLED * https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU */ import { Readable as ReadableStream, ReadableOptions } from "stream"; // ---- internal support stuff export interface Event { ts: number; pid: number; tid: number; /** event phase */ ph?: string; [otherData: string]: any; } function evCommon(): Event { var hrtime = process.hrtime(); // [seconds, nanoseconds] var ts = hrtime[0] * 1000000 + Math.round(hrtime[1] / 1000); // microseconds return { ts, pid: process.pid, tid: process.pid // no meaningful tid for node.js }; } // ---- Tracer export interface Fields { cat?: any; args?: any; [filedName: string]: any; } export interface TracerOptions { parent?: Tracer | null; fields?: Fields | null; objectMode?: boolean | null; noStream?: boolean; } export class Tracer extends ReadableStream { private _objectMode!: boolean; /** Node Stream internal APIs */ private _push: any; private firstPush?: boolean; private noStream: boolean = false; private events: Event[] = []; private parent!: Tracer | null | undefined; private fields!: Fields | null | undefined; constructor(opts: TracerOptions = {}) { super(); if (typeof opts !== "object") { throw new Error("Invalid options passed (must be an object)"); } if (opts.parent != null && typeof opts.parent !== "object") { throw new Error("Invalid option (parent) passed (must be an object)"); } if (opts.fields != null && typeof opts.fields !== "object") { throw new Error("Invalid option (fields) passed (must be an object)"); } if ( opts.objectMode != null && (opts.objectMode !== true && opts.objectMode !== false) ) { throw new Error( "Invalid option (objectsMode) passed (must be a boolean)" ); } this.noStream = opts.noStream || false; this.parent = opts.parent; if (this.parent) { this.fields = Object.assign({}, opts.parent && opts.parent.fields); } else { this.fields = {}; } if (opts.fields) { Object.assign(this.fields, opts.fields); } if (!this.fields.cat) { // trace-viewer *requires* `cat`, so let's have a fallback. this.fields.cat = "default"; } else if (Array.isArray(this.fields.cat)) { this.fields.cat = this.fields.cat.join(","); } if (!this.fields.args) { // trace-viewer *requires* `args`, so let's have a fallback. this.fields.args = {}; } if (this.parent) { // TODO: Not calling Readable ctor here. Does that cause probs? // Probably if trying to pipe from the child. // Might want a serpate TracerChild class for these guys. this._push = this.parent._push.bind(this.parent); } else { this._objectMode = Boolean(opts.objectMode); var streamOpts: ReadableOptions = { objectMode: this._objectMode }; if (this._objectMode) { this._push = this.push; } else { this._push = this._pushString; streamOpts.encoding = "utf8"; } ReadableStream.call(this, streamOpts); } } /** * If in no streamMode in order to flush out the trace * you need to call flush. */ public flush() { if (this.noStream === true) { for (const evt of this.events) { this._push(evt); } this._flush(); } } _read(_: number) {} private _pushString(ev: Event) { var separator = ""; if (!this.firstPush) { this.push("["); this.firstPush = true; } else { separator = ",\n"; } this.push(separator + JSON.stringify(ev), "utf8"); } private _flush() { if (!this._objectMode) { this.push("]"); } } public child(fields: Fields) { return new Tracer({ parent: this, fields: fields }); } public begin(fields: Fields) { return this.mkEventFunc("b")(fields); } public end(fields: Fields) { return this.mkEventFunc("e")(fields); } public completeEvent(fields: Fields) { return this.mkEventFunc("X")(fields); } public instantEvent(fields: Fields) { return this.mkEventFunc("I")(fields); } public mkEventFunc(ph: string) { return (fields: Fields) => { var ev = evCommon(); // Assign the event phase. ev.ph = ph; if (fields) { if (typeof fields === "string") { ev.name = fields; } else { for (const k of Object.keys(fields)) { if (k === "cat") { ev.cat = fields.cat.join(","); } else { ev[k] = fields[k]; } } } } if (!this.noStream) { this._push(ev); } else { this.events.push(ev); } }; } } /* * These correspond to the "Async events" in the Trace Events doc. * * Required fields: * - name * - id * * Optional fields: * - cat (array) * - args (object) * - TODO: stack fields, other optional fields? * * Dev Note: We don't explicitly assert that correct fields are * used for speed (premature optimization alert!). */ chrome-trace-event-1.0.3/package.json000066400000000000000000000014771403364250400175030ustar00rootroot00000000000000{ "name": "chrome-trace-event", "description": "A library to create a trace of your node app per Google's Trace Event format.", "license": "MIT", "version": "1.0.3", "author": "Trent Mick, Sam Saccone", "keywords": [ "trace-event", "trace", "event", "trace-viewer", "google" ], "repository": { "url": "github:samccone/chrome-trace-event" }, "main": "./dist/trace-event.js", "typings": "./dist/trace-event.d.ts", "dependencies": {}, "devDependencies": { "@types/node": "*", "prettier": "^1.12.1", "tape": "4.8.0", "typescript": "^4.2.4" }, "engines": { "node": ">=6.0" }, "files": [ "dist", "CHANGES.md" ], "scripts": { "build": "tsc", "check_format": "prettier -l lib/** test/** examples/**", "test": "tape test/*.test.js" } } chrome-trace-event-1.0.3/test/000077500000000000000000000000001403364250400161635ustar00rootroot00000000000000chrome-trace-event-1.0.3/test/basics.test.js000066400000000000000000000003371403364250400207460ustar00rootroot00000000000000/* * Catch all test file for trace-event. */ var test = require("tape"); var trace_event = require("../dist/trace-event"); // --- Tests test("exports", function(t) { t.ok(new trace_event.Tracer(), ""); t.end(); }); chrome-trace-event-1.0.3/tsconfig.json000066400000000000000000000011511403364250400177110ustar00rootroot00000000000000{ "compilerOptions": { "target": "es2015", "module": "commonjs", "lib": [ "es2015" ], "declaration": true, "sourceMap": false, "outDir": "./dist", "importHelpers": false, "strict": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, "strictPropertyInitialization": true, "noImplicitThis": true, "alwaysStrict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "types": [ "node" ], "esModuleInterop": true } }