diff --git a/clients/nodejs/README.md b/clients/nodejs/README.md new file mode 100644 index 0000000..4bd1925 --- /dev/null +++ b/clients/nodejs/README.md @@ -0,0 +1,9 @@ +To build tsd-metrics-client.ts: +1 - Install Typesript compiler + + npm install -g typescript + +2 - Compile tsd-metrics-client.ts using the following command + + tsc tsd-metrics-client.ts --module commonjs + diff --git a/clients/nodejs/compile b/clients/nodejs/compile new file mode 100755 index 0000000..ab27b75 --- /dev/null +++ b/clients/nodejs/compile @@ -0,0 +1,2 @@ +#!/bin/bash +tsc tsd-metrics-client.ts --outDir lib --module commonjs diff --git a/clients/nodejs/lib/tsd-metrics-client.js b/clients/nodejs/lib/tsd-metrics-client.js new file mode 100644 index 0000000..503c5a7 --- /dev/null +++ b/clients/nodejs/lib/tsd-metrics-client.js @@ -0,0 +1,309 @@ +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var log4js = require("log4js"); +var events = require("events"); + +/** +* Class for managing samples for a counter +*/ +var CounterSamples = (function () { + function CounterSamples() { + this.samples = new Array(); + this.lastIndex = 0; + this.reset(); + } + /** + * Create a new sample for the counter with value of zero + */ + CounterSamples.prototype.reset = function () { + this.lastIndex = this.samples.push(0) - 1; + }; + + /** + * Increment the current sample + * @param value Signed value to increment the sample byt + */ + CounterSamples.prototype.increment = function (value) { + this.samples[this.lastIndex] += value; + }; + + CounterSamples.prototype.toJSON = function () { + return this.samples; + }; + return CounterSamples; +})(); + +/** +* Class for creating duration sample for a timer +*/ +var TimerSamples = (function () { + function TimerSamples() { + this.durations = new Array(); + } + /** + * Add explicit timer duration + * @param duration + */ + TimerSamples.prototype.addDuration = function (duration) { + this.durations.push(duration); + }; + + /** + * Start a new timer + */ + TimerSamples.prototype.start = function () { + this.startTime = Date.now(); + }; + + /** + * Stop the current timer + */ + TimerSamples.prototype.stop = function () { + if (this.startTime != undefined) { + this.addDuration(Date.now() - this.startTime); + } + this.startTime = undefined; + }; + + TimerSamples.prototype.toJSON = function () { + return this.durations; + }; + return TimerSamples; +})(); + +var Lazy = (function () { + function Lazy(factory) { + this.factory = factory; + } + Lazy.prototype.getValue = function () { + if (this.value == undefined) { + this.value = this.factory(); + } + return this.value; + }; + return Lazy; +})(); + +/** +* Node JS class for publishing metrics as time series data (TSD). +* For more information see: +* +* https://wiki.groupondev.com/TsdAggregator +*/ +var TsdMetrics = (function (_super) { + __extends(TsdMetrics, _super); + function TsdMetrics() { + _super.call(this); + /** + * + */ + this.isOpen = true; + //anonymous type for representing the final json blob + this.logEntry = { + annotations: {}, + counters: {}, + gauges: {}, + timers: {}, + version: "2c" + }; + + //according to http://nodejs.org/docs/v0.3.5/api/events.html#events.EventEmitter + //if an error event is emitted and nothing was listening, the process will exist, so we are adding this + //do-nothing listener in order not to exist the process + this.addListener("error", function (error) { + }); + this.annotate("initTimestamp", (Date.now() / 1000.0).toString()); + } + /** + * Assert that a condition is true and emit an error event and + * @param condition + * @param message + * @returns {boolean} + */ + TsdMetrics.prototype.assert = function (condition, message) { + if (!condition) { + this.emit("error", new Error(message)); + return false; + } + return true; + }; + + TsdMetrics.prototype.assertIsOpen = function () { + return this.assert(this.isOpen, "Metrics object was not opened or it's already closed"); + }; + + /** + * Increment the specified counter by the specified amount. All counters are + * initialized to zero. + * + * @param name The name of the counter. + * @param value The amount to increment by. + */ + TsdMetrics.prototype.incrementCounter = function (name, value) { + if (typeof value === "undefined") { value = 1; } + this.assertIsOpen(); + if (this.logEntry.counters[name] == undefined) { + this.logEntry.counters[name] = new CounterSamples(); + } + this.logEntry.counters[name].increment(value); + }; + + /** + * Decrement the specified counter by the specified amount. All counters are + * initialized to zero. + * + * @param name The name of the counter. + * @param value The amount to decrement by. + */ + TsdMetrics.prototype.decrementCounter = function (name, value) { + if (typeof value === "undefined") { value = 1; } + this.incrementCounter(name, -value); + }; + + /** + * Reset the counter to zero. This most commonly used to record a zero-count + * for a particular counter. If clients wish to record set count metrics + * then all counters should be reset before conditionally invoking increment + * and/or decrement. + * + * @param name The name of the counter. + */ + TsdMetrics.prototype.resetCounter = function (name) { + if (this.assertIsOpen()) { + if (this.logEntry.counters[name] == undefined) { + this.logEntry.counters[name] = new CounterSamples(); + } else { + this.logEntry.counters[name].reset(); + } + } + }; + + /** + * Start the specified timer measurement. + * + * @param name The name of the timer. + */ + TsdMetrics.prototype.startTimer = function (name) { + if (this.assertIsOpen()) { + if (this.logEntry.timers[name] == undefined) { + this.logEntry.timers[name] = new TimerSamples(); + } + this.logEntry.timers[name].start(); + } + }; + + /** + * Stop the specified timer measurement. + * + * @param name The name of the timer. + */ + TsdMetrics.prototype.stopTimer = function (name) { + if (this.assertIsOpen()) { + this.assert(this.logEntry.timers[name] != undefined, "Timer does not exist; you must start the timer first"); + this.logEntry.timers[name].stop(); + } + }; + + /** + * Set the timer to the specified value. This is most commonly used to + * record timers from external sources that are not integrated with metrics. + * + * @param name The name of the timer. + * @param duration The duration of the timer in milliseconds. + */ + TsdMetrics.prototype.setTimer = function (name, durationMilliseconds) { + if (this.assertIsOpen()) { + if (this.logEntry.timers[name] == undefined) { + this.logEntry.timers[name] = new TimerSamples(); + } + this.logEntry.timers[name].addDuration(durationMilliseconds); + } + }; + + /** + * Set the specified gauge reading. + * + * @param name The name of the gauge. + * @param value The reading on the gauge + */ + TsdMetrics.prototype.setGauge = function (name, value) { + if (this.assertIsOpen()) { + if (this.logEntry.gauges[name] == undefined) { + this.logEntry.gauges[name] = new Array(); + } + this.logEntry.gauges[name].push(value); + } + }; + + /** + * Add an attribute that describes the captured metrics or context. + * + * @param key The name of the attribute. + * @param value The value of the attribute. + */ + TsdMetrics.prototype.annotate = function (key, value) { + if (this.assertIsOpen()) { + this.logEntry.annotations[key] = value; + } + }; + + /** + * Close the metrics object. This should complete publication of metrics to + * the underlying data store. Once the metrics object is closed, no further + * metrics can be recorded. + */ + TsdMetrics.prototype.close = function () { + if (this.assertIsOpen()) { + this.annotate("finalTimestamp", (Date.now() / 1000.0).toString()); + for (var timer in this.logEntry.timers) { + this.logEntry.timers[timer].stop(); + } + TsdMetrics.LOGGER.getValue().info(JSON.stringify(this.logEntry)); + this.isOpen = false; + } + }; + TsdMetrics.MAX_LOG_SIZE = 32 * 1024 * 1024; + + TsdMetrics.LOG_BACKUPS = 10; + + TsdMetrics.CONSOLE_ECHO = false; + + TsdMetrics.LOGGER = new Lazy(function () { + var appendersArray = [ + { + type: "file", + filename: "tsd-query.log", + maxLogSize: TsdMetrics.MAX_LOG_SIZE, + backups: TsdMetrics.LOG_BACKUPS, + layout: { + type: "pattern", + pattern: "%m" + }, + category: "tsd-client" + } + ]; + if (TsdMetrics.CONSOLE_ECHO) { + appendersArray.push({ + type: "console", + layout: { + type: "pattern", + pattern: "%m" + }, + category: "tsd-client" + }); + } + var config = { + appenders: appendersArray + }; + + log4js.configure(config, {}); + + return log4js.getLogger("tsd-client"); + }); + return TsdMetrics; +})(events.EventEmitter); +exports.TsdMetrics = TsdMetrics; diff --git a/clients/nodejs/log4js.d.ts b/clients/nodejs/log4js.d.ts new file mode 100644 index 0000000..fc61af6 --- /dev/null +++ b/clients/nodejs/log4js.d.ts @@ -0,0 +1,10 @@ +declare module "log4js" { + function configure(appenders:any, options:any); + function getLogger(name:string):Logger; + + export interface Logger{ + info(message:string); + } + +} + diff --git a/clients/nodejs/metrics.d.ts b/clients/nodejs/metrics.d.ts new file mode 100644 index 0000000..2357b1b --- /dev/null +++ b/clients/nodejs/metrics.d.ts @@ -0,0 +1,101 @@ +declare module "tsd" { + /** + * Interface for logging metrics: timers, counters and gauges for TSD Aggregator + * + * @author mkamel + * + */ + export interface Metrics { + + /** + * Increment the specified counter by 1. All counters are initialized to + * zero. + * + * @param name The name of the counter. + */ + incrementCounter(name:string): void; + + /** + * Increment the specified counter by the specified amount. All counters are + * initialized to zero. + * + * @param name The name of the counter. + * @param value The amount to increment by. + */ + incrementCounter(name:string, value:number): void ; + + /** + * Decrement the specified counter by 1. All counters are initialized to + * zero. + * + * @param name The name of the counter. + */ + decrementCounter(name:string): void; + + /** + * Decrement the specified counter by the specified amount. All counters are + * initialized to zero. + * + * @param name The name of the counter. + * @param value The amount to decrement by. + */ + decrementCounter(name:string, value:number): void ; + + /** + * Reset the counter to zero. This most commonly used to record a zero-count + * for a particular counter. If clients wish to record set count metrics + * then all counters should be reset before conditionally invoking increment + * and/or decrement. + * + * @param name The name of the counter. + */ + resetCounter(name:string): void; + + /** + * Start the specified timer measurement. + * + * @param name The name of the timer. + */ + startTimer(name:string): void; + + /** + * Stop the specified timer measurement. + * + * @param name The name of the timer. + */ + stopTimer(name:string): void; + + /** + * Set the timer to the specified value. This is most commonly used to + * record timers from external sources that are not integrated with metrics. + * + * @param name The name of the timer. + * @param duration The duration of the timer in milliseconds. + */ + setTimer(name:string, durationMilliseconds:number): void; + + /** + * Set the specified gauge reading. + * + * @param name The name of the gauge. + * @param value The reading on the gauge + */ + setGauge(name:string, value:number): void; + + /** + * Add an attribute that describes the captured metrics or context. + * + * @param key The name of the attribute. + * @param value The value of the attribute. + */ + annotate(key:string, value:string): void; + + /** + * Close the metrics object. This should complete publication of metrics to + * the underlying data store. Once the metrics object is closed, no further + * metrics can be recorded. + */ + close(): void; + } +} + diff --git a/clients/nodejs/node.d.ts b/clients/nodejs/node.d.ts new file mode 100644 index 0000000..8801de5 --- /dev/null +++ b/clients/nodejs/node.d.ts @@ -0,0 +1,1231 @@ +// Type definitions for Node.js v0.10.1 +// Project: http://nodejs.org/ +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/************************************************ +* * +* Node.js v0.10.1 API * +* * +************************************************/ + +/************************************************ +* * +* GLOBAL * +* * +************************************************/ +declare var process: NodeProcess; +declare var global: any; + +declare var __filename: string; +declare var __dirname: string; + +declare function setTimeout(callback: (...args: any[]) => void , ms: number , ...args: any[]): NodeTimer; +declare function clearTimeout(timeoutId: NodeTimer): void; +declare function setInterval(callback: (...args: any[]) => void , ms: number , ...args: any[]): NodeTimer; +declare function clearInterval(intervalId: NodeTimer): void; +declare function setImmediate(callback: (...args: any[]) => void , ...args: any[]): any; +declare function clearImmediate(immediateId: any): void; + +declare var require: { + (id: string): any; + resolve(id:string): string; + cache: any; + extensions: any; + main: any; +} + +declare var module: { + exports: any; + require(id: string): any; + id: string; + filename: string; + loaded: boolean; + parent: any; + children: any[]; +} + +// Same as module.exports +declare var exports: any; +declare var SlowBuffer: { + new (str: string, encoding?: string): NodeBuffer; + new (size: number): NodeBuffer; + new (array: any[]): NodeBuffer; + prototype: NodeBuffer; + isBuffer(obj: any): boolean; + byteLength(string: string, encoding?: string): number; + concat(list: NodeBuffer[], totalLength?: number): NodeBuffer; +}; +declare var Buffer: { + new (str: string, encoding?: string): NodeBuffer; + new (size: number): NodeBuffer; + new (array: any[]): NodeBuffer; + prototype: NodeBuffer; + isBuffer(obj: any): boolean; + byteLength(string: string, encoding?: string): number; + concat(list: NodeBuffer[], totalLength?: number): NodeBuffer; +} + +/************************************************ +* * +* INTERFACES * +* * +************************************************/ + +interface ErrnoException extends Error { + errno?: any; + code?: string; + path?: string; + syscall?: string; +} + +interface NodeEventEmitter { + addListener(event: string, listener: Function): NodeEventEmitter; + on(event: string, listener: Function): NodeEventEmitter; + once(event: string, listener: Function): NodeEventEmitter; + removeListener(event: string, listener: Function): NodeEventEmitter; + removeAllListeners(event?: string): NodeEventEmitter; + setMaxListeners(n: number): void; + listeners(event: string): Function[]; + emit(event: string, ...args: any[]): boolean; +} + +interface ReadableStream extends NodeEventEmitter { + readable: boolean; + read(size?: number): any; + setEncoding(encoding: string): void; + pause(): void; + resume(): void; + pipe(destination: T, options?: { end?: boolean; }): T; + unpipe(destination?: T): void; + unshift(chunk: string): void; + unshift(chunk: NodeBuffer): void; + wrap(oldStream: ReadableStream): ReadableStream; +} + +interface WritableStream extends NodeEventEmitter { + writable: boolean; + write(buffer: NodeBuffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: NodeBuffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; +} + +interface ReadWriteStream extends ReadableStream, WritableStream { } + +interface NodeProcess extends NodeEventEmitter { + stdout: WritableStream; + stderr: WritableStream; + stdin: ReadableStream; + argv: string[]; + execPath: string; + abort(): void; + chdir(directory: string): void; + cwd(): string; + env: any; + exit(code?: number): void; + getgid(): number; + setgid(id: number): void; + setgid(id: string): void; + getuid(): number; + setuid(id: number): void; + setuid(id: string): void; + version: string; + versions: { http_parser: string; node: string; v8: string; ares: string; uv: string; zlib: string; openssl: string; }; + config: { + target_defaults: { + cflags: any[]; + default_configuration: string; + defines: string[]; + include_dirs: string[]; + libraries: string[]; + }; + variables: { + clang: number; + host_arch: string; + node_install_npm: boolean; + node_install_waf: boolean; + node_prefix: string; + node_shared_openssl: boolean; + node_shared_v8: boolean; + node_shared_zlib: boolean; + node_use_dtrace: boolean; + node_use_etw: boolean; + node_use_openssl: boolean; + target_arch: string; + v8_no_strict_aliasing: number; + v8_use_snapshot: boolean; + visibility: string; + }; + }; + kill(pid: number, signal?: string): void; + pid: number; + title: string; + arch: string; + platform: string; + memoryUsage(): { rss: number; heapTotal: number; heapUsed: number; }; + nextTick(callback: Function): void; + umask(mask?: number): number; + uptime(): number; + hrtime(time?:number[]): number[]; + + // Worker + send?(message: any, sendHandle?: any): void; +} + +// Buffer class +interface NodeBuffer { + [index: number]: number; + write(string: string, offset?: number, length?: number, encoding?: string): number; + toString(encoding?: string, start?: number, end?: number): string; + length: number; + copy(targetBuffer: NodeBuffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; + slice(start?: number, end?: number): NodeBuffer; + readUInt8(offset: number, noAsset?: boolean): number; + readUInt16LE(offset: number, noAssert?: boolean): number; + readUInt16BE(offset: number, noAssert?: boolean): number; + readUInt32LE(offset: number, noAssert?: boolean): number; + readUInt32BE(offset: number, noAssert?: boolean): number; + readInt8(offset: number, noAssert?: boolean): number; + readInt16LE(offset: number, noAssert?: boolean): number; + readInt16BE(offset: number, noAssert?: boolean): number; + readInt32LE(offset: number, noAssert?: boolean): number; + readInt32BE(offset: number, noAssert?: boolean): number; + readFloatLE(offset: number, noAssert?: boolean): number; + readFloatBE(offset: number, noAssert?: boolean): number; + readDoubleLE(offset: number, noAssert?: boolean): number; + readDoubleBE(offset: number, noAssert?: boolean): number; + writeUInt8(value: number, offset: number, noAssert?: boolean): void; + writeUInt16LE(value: number, offset: number, noAssert?: boolean): void; + writeUInt16BE(value: number, offset: number, noAssert?: boolean): void; + writeUInt32LE(value: number, offset: number, noAssert?: boolean): void; + writeUInt32BE(value: number, offset: number, noAssert?: boolean): void; + writeInt8(value: number, offset: number, noAssert?: boolean): void; + writeInt16LE(value: number, offset: number, noAssert?: boolean): void; + writeInt16BE(value: number, offset: number, noAssert?: boolean): void; + writeInt32LE(value: number, offset: number, noAssert?: boolean): void; + writeInt32BE(value: number, offset: number, noAssert?: boolean): void; + writeFloatLE(value: number, offset: number, noAssert?: boolean): void; + writeFloatBE(value: number, offset: number, noAssert?: boolean): void; + writeDoubleLE(value: number, offset: number, noAssert?: boolean): void; + writeDoubleBE(value: number, offset: number, noAssert?: boolean): void; + fill(value: any, offset?: number, end?: number): void; +} + +interface NodeTimer { + ref() : void; + unref() : void; +} + +/************************************************ +* * +* MODULES * +* * +************************************************/ +declare module "querystring" { + export function stringify(obj: any, sep?: string, eq?: string): string; + export function parse(str: string, sep?: string, eq?: string, options?: { maxKeys?: number; }): any; + export function escape(): any; + export function unescape(): any; +} + +declare module "events" { + export class EventEmitter implements NodeEventEmitter { + static listenerCount(emitter: EventEmitter, event: string): number; + + addListener(event: string, listener: Function): EventEmitter; + on(event: string, listener: Function): EventEmitter; + once(event: string, listener: Function): EventEmitter; + removeListener(event: string, listener: Function): EventEmitter; + removeAllListeners(event?: string): EventEmitter; + setMaxListeners(n: number): void; + listeners(event: string): Function[]; + emit(event: string, ...args: any[]): boolean; + } +} + +declare module "http" { + import events = require("events"); + import net = require("net"); + import stream = require("stream"); + + export interface Server extends NodeEventEmitter { + listen(port: number, hostname?: string, backlog?: number, callback?: Function): void; + listen(path: string, callback?: Function): void; + listen(handle: any, listeningListener?: Function): void; + close(cb?: any): void; + maxHeadersCount: number; + } + export interface ServerRequest extends NodeEventEmitter, ReadableStream { + method: string; + url: string; + headers: any; + trailers: string; + httpVersion: string; + setEncoding(encoding?: string): void; + pause(): void; + resume(): void; + connection: net.NodeSocket; + } + export interface ServerResponse extends NodeEventEmitter, WritableStream { + // Extended base methods + write(str: string, encoding?: string, fd?: string): boolean; + write(buffer: NodeBuffer): boolean; + + writeContinue(): void; + writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void; + writeHead(statusCode: number, headers?: any): void; + statusCode: number; + setHeader(name: string, value: string): void; + sendDate: boolean; + getHeader(name: string): string; + removeHeader(name: string): void; + write(chunk: any, encoding?: string): any; + addTrailers(headers: any): void; + end(data?: any, encoding?: string): void; + } + export interface ClientRequest extends NodeEventEmitter, WritableStream { + // Extended base methods + write(str: string, encoding?: string, fd?: string): boolean; + write(buffer: NodeBuffer): boolean; + + write(chunk: any, encoding?: string): void; + end(data?: any, encoding?: string): void; + abort(): void; + setTimeout(timeout: number, callback?: Function): void; + setNoDelay(noDelay?: Function): void; + setSocketKeepAlive(enable?: boolean, initialDelay?: number): void; + } + export interface ClientResponse extends NodeEventEmitter, ReadableStream { + statusCode: number; + httpVersion: string; + headers: any; + trailers: any; + setEncoding(encoding?: string): void; + pause(): void; + resume(): void; + } + export interface Agent { maxSockets: number; sockets: any; requests: any; } + + export var STATUS_CODES: any; + export function createServer(requestListener?: (request: ServerRequest, response: ServerResponse) =>void ): Server; + export function createClient(port?: number, host?: string): any; + export function request(options: any, callback?: Function): ClientRequest; + export function get(options: any, callback?: Function): ClientRequest; + export var globalAgent: Agent; +} + +declare module "cluster" { + import child = require("child_process"); + import events = require("events"); + + export interface ClusterSettings { + exec?: string; + args?: string[]; + silent?: boolean; + } + + export class Worker extends events.EventEmitter { + id: string; + process: child.ChildProcess; + suicide: boolean; + send(message: any, sendHandle?: any): void; + kill(signal?: string): void; + destroy(signal?: string): void; + disconnect(): void; + } + + export var settings: ClusterSettings; + export var isMaster: boolean; + export var isWorker: boolean; + export function setupMaster(settings?: ClusterSettings): void; + export function fork(env?: any): Worker; + export function disconnect(callback?: Function): void; + export var worker: Worker; + export var workers: Worker[]; + + // Event emitter + export function addListener(event: string, listener: Function): void; + export function on(event: string, listener: Function): any; + export function once(event: string, listener: Function): void; + export function removeListener(event: string, listener: Function): void; + export function removeAllListeners(event?: string): void; + export function setMaxListeners(n: number): void; + export function listeners(event: string): Function[]; + export function emit(event: string, ...args: any[]): boolean; +} + +declare module "zlib" { + import stream = require("stream"); + export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; } + + export interface Gzip extends ReadWriteStream { } + export interface Gunzip extends ReadWriteStream { } + export interface Deflate extends ReadWriteStream { } + export interface Inflate extends ReadWriteStream { } + export interface DeflateRaw extends ReadWriteStream { } + export interface InflateRaw extends ReadWriteStream { } + export interface Unzip extends ReadWriteStream { } + + export function createGzip(options?: ZlibOptions): Gzip; + export function createGunzip(options?: ZlibOptions): Gunzip; + export function createDeflate(options?: ZlibOptions): Deflate; + export function createInflate(options?: ZlibOptions): Inflate; + export function createDeflateRaw(options?: ZlibOptions): DeflateRaw; + export function createInflateRaw(options?: ZlibOptions): InflateRaw; + export function createUnzip(options?: ZlibOptions): Unzip; + + export function deflate(buf: NodeBuffer, callback: (error: Error, result: any) =>void ): void; + export function deflateRaw(buf: NodeBuffer, callback: (error: Error, result: any) =>void ): void; + export function gzip(buf: NodeBuffer, callback: (error: Error, result: any) =>void ): void; + export function gunzip(buf: NodeBuffer, callback: (error: Error, result: any) =>void ): void; + export function inflate(buf: NodeBuffer, callback: (error: Error, result: any) =>void ): void; + export function inflateRaw(buf: NodeBuffer, callback: (error: Error, result: any) =>void ): void; + export function unzip(buf: NodeBuffer, callback: (error: Error, result: any) =>void ): void; + + // Constants + export var Z_NO_FLUSH: number; + export var Z_PARTIAL_FLUSH: number; + export var Z_SYNC_FLUSH: number; + export var Z_FULL_FLUSH: number; + export var Z_FINISH: number; + export var Z_BLOCK: number; + export var Z_TREES: number; + export var Z_OK: number; + export var Z_STREAM_END: number; + export var Z_NEED_DICT: number; + export var Z_ERRNO: number; + export var Z_STREAM_ERROR: number; + export var Z_DATA_ERROR: number; + export var Z_MEM_ERROR: number; + export var Z_BUF_ERROR: number; + export var Z_VERSION_ERROR: number; + export var Z_NO_COMPRESSION: number; + export var Z_BEST_SPEED: number; + export var Z_BEST_COMPRESSION: number; + export var Z_DEFAULT_COMPRESSION: number; + export var Z_FILTERED: number; + export var Z_HUFFMAN_ONLY: number; + export var Z_RLE: number; + export var Z_FIXED: number; + export var Z_DEFAULT_STRATEGY: number; + export var Z_BINARY: number; + export var Z_TEXT: number; + export var Z_ASCII: number; + export var Z_UNKNOWN: number; + export var Z_DEFLATED: number; + export var Z_NULL: number; +} + +declare module "os" { + export function tmpDir(): string; + export function hostname(): string; + export function type(): string; + export function platform(): string; + export function arch(): string; + export function release(): string; + export function uptime(): number; + export function loadavg(): number[]; + export function totalmem(): number; + export function freemem(): number; + export function cpus(): { model: string; speed: number; times: { user: number; nice: number; sys: number; idle: number; irq: number; }; }[]; + export function networkInterfaces(): any; + export var EOL: string; +} + +declare module "https" { + import tls = require("tls"); + import events = require("events"); + import http = require("http"); + + export interface ServerOptions { + pfx?: any; + key?: any; + passphrase?: string; + cert?: any; + ca?: any; + crl?: any; + ciphers?: string; + honorCipherOrder?: boolean; + requestCert?: boolean; + rejectUnauthorized?: boolean; + NPNProtocols?: any; + SNICallback?: (servername: string) => any; + } + + export interface RequestOptions { + host?: string; + hostname?: string; + port?: number; + path?: string; + method?: string; + headers?: any; + auth?: string; + agent?: any; + pfx?: any; + key?: any; + passphrase?: string; + cert?: any; + ca?: any; + ciphers?: string; + rejectUnauthorized?: boolean; + } + + export interface NodeAgent { + maxSockets: number; + sockets: any; + requests: any; + } + export var Agent: { + new (options?: RequestOptions): NodeAgent; + }; + export interface Server extends tls.Server { } + export function createServer(options: ServerOptions, requestListener?: Function): Server; + export function request(options: RequestOptions, callback?: (res: NodeEventEmitter) =>void ): http.ClientRequest; + export function get(options: RequestOptions, callback?: (res: NodeEventEmitter) =>void ): http.ClientRequest; + export var globalAgent: NodeAgent; +} + +declare module "punycode" { + export function decode(string: string): string; + export function encode(string: string): string; + export function toUnicode(domain: string): string; + export function toASCII(domain: string): string; + export var ucs2: ucs2; + interface ucs2 { + decode(string: string): string; + encode(codePoints: number[]): string; + } + export var version: any; +} + +declare module "repl" { + import stream = require("stream"); + import events = require("events"); + + export interface ReplOptions { + prompt?: string; + input?: ReadableStream; + output?: WritableStream; + terminal?: boolean; + eval?: Function; + useColors?: boolean; + useGlobal?: boolean; + ignoreUndefined?: boolean; + writer?: Function; + } + export function start(options: ReplOptions): NodeEventEmitter; +} + +declare module "readline" { + import events = require("events"); + import stream = require("stream"); + + export interface ReadLine extends NodeEventEmitter { + setPrompt(prompt: string, length: number): void; + prompt(preserveCursor?: boolean): void; + question(query: string, callback: Function): void; + pause(): void; + resume(): void; + close(): void; + write(data: any, key?: any): void; + } + export interface ReadLineOptions { + input: ReadableStream; + output: WritableStream; + completer?: Function; + terminal?: boolean; + } + export function createInterface(options: ReadLineOptions): ReadLine; +} + +declare module "vm" { + export interface Context { } + export interface Script { + runInThisContext(): void; + runInNewContext(sandbox?: Context): void; + } + export function runInThisContext(code: string, filename?: string): void; + export function runInNewContext(code: string, sandbox?: Context, filename?: string): void; + export function runInContext(code: string, context: Context, filename?: string): void; + export function createContext(initSandbox?: Context): Context; + export function createScript(code: string, filename?: string): Script; +} + +declare module "child_process" { + import events = require("events"); + import stream = require("stream"); + + export interface ChildProcess extends NodeEventEmitter { + stdin: WritableStream; + stdout: ReadableStream; + stderr: ReadableStream; + pid: number; + kill(signal?: string): void; + send(message: any, sendHandle: any): void; + disconnect(): void; + } + + export function spawn(command: string, args?: string[], options?: { + cwd?: string; + stdio?: any; + custom?: any; + env?: any; + detached?: boolean; + }): ChildProcess; + export function exec(command: string, options: { + cwd?: string; + stdio?: any; + customFds?: any; + env?: any; + encoding?: string; + timeout?: number; + maxBuffer?: number; + killSignal?: string; + }, callback: (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) =>void ): ChildProcess; + export function exec(command: string, callback: (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) =>void ): ChildProcess; + export function execFile(file: string, args: string[], options: { + cwd?: string; + stdio?: any; + customFds?: any; + env?: any; + encoding?: string; + timeout?: number; + maxBuffer?: string; + killSignal?: string; + }, callback: (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) =>void ): ChildProcess; + export function fork(modulePath: string, args?: string[], options?: { + cwd?: string; + env?: any; + encoding?: string; + }): ChildProcess; +} + +declare module "url" { + export interface Url { + href: string; + protocol: string; + auth: string; + hostname: string; + port: string; + host: string; + pathname: string; + search: string; + query: string; + slashes: boolean; + } + + export interface UrlOptions { + protocol?: string; + auth?: string; + hostname?: string; + port?: string; + host?: string; + pathname?: string; + search?: string; + query?: any; + } + + export function parse(urlStr: string, parseQueryString?: boolean , slashesDenoteHost?: boolean ): Url; + export function format(url: UrlOptions): string; + export function resolve(from: string, to: string): string; +} + +declare module "dns" { + export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) =>void ): string; + export function lookup(domain: string, callback: (err: Error, address: string, family: number) =>void ): string; + export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolve(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolve4(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolve6(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveMx(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function reverse(ip: string, callback: (err: Error, domains: string[]) =>void ): string[]; +} + +declare module "net" { + import stream = require("stream"); + + export interface NodeSocket extends ReadWriteStream { + // Extended base methods + write(str: string, encoding?: string, fd?: string): boolean; + write(buffer: NodeBuffer): boolean; + + connect(port: number, host?: string, connectionListener?: Function): void; + connect(path: string, connectionListener?: Function): void; + bufferSize: number; + setEncoding(encoding?: string): void; + write(data: any, encoding?: string, callback?: Function): void; + end(data?: any, encoding?: string): void; + destroy(): void; + pause(): void; + resume(): void; + setTimeout(timeout: number, callback?: Function): void; + setNoDelay(noDelay?: boolean): void; + setKeepAlive(enable?: boolean, initialDelay?: number): void; + address(): { port: number; family: string; address: string; }; + remoteAddress: string; + remotePort: number; + bytesRead: number; + bytesWritten: number; + } + + export var Socket: { + new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): NodeSocket; + }; + + export interface Server extends NodeSocket { + listen(port: number, host?: string, backlog?: number, listeningListener?: Function): void; + listen(path: string, listeningListener?: Function): void; + listen(handle: any, listeningListener?: Function): void; + close(callback?: Function): void; + address(): { port: number; family: string; address: string; }; + maxConnections: number; + connections: number; + } + export function createServer(connectionListener?: (socket: NodeSocket) =>void ): Server; + export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: NodeSocket) =>void ): Server; + export function connect(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): NodeSocket; + export function connect(port: number, host?: string, connectionListener?: Function): NodeSocket; + export function connect(path: string, connectionListener?: Function): NodeSocket; + export function createConnection(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): NodeSocket; + export function createConnection(port: number, host?: string, connectionListener?: Function): NodeSocket; + export function createConnection(path: string, connectionListener?: Function): NodeSocket; + export function isIP(input: string): number; + export function isIPv4(input: string): boolean; + export function isIPv6(input: string): boolean; +} + +declare module "dgram" { + import events = require("events"); + + export function createSocket(type: string, callback?: Function): Socket; + + interface Socket extends NodeEventEmitter { + send(buf: NodeBuffer, offset: number, length: number, port: number, address: string, callback?: Function): void; + bind(port: number, address?: string): void; + close(): void; + address: { address: string; family: string; port: number; }; + setBroadcast(flag: boolean): void; + setMulticastTTL(ttl: number): void; + setMulticastLoopback(flag: boolean): void; + addMembership(multicastAddress: string, multicastInterface?: string): void; + dropMembership(multicastAddress: string, multicastInterface?: string): void; + } +} + +declare module "fs" { + import stream = require("stream"); + + interface Stats { + isFile(): boolean; + isDirectory(): boolean; + isBlockDevice(): boolean; + isCharacterDevice(): boolean; + isSymbolicLink(): boolean; + isFIFO(): boolean; + isSocket(): boolean; + dev: number; + ino: number; + mode: number; + nlink: number; + uid: number; + gid: number; + rdev: number; + size: number; + blksize: number; + blocks: number; + atime: Date; + mtime: Date; + ctime: Date; + } + + interface FSWatcher extends NodeEventEmitter { + close(): void; + } + + export interface ReadStream extends ReadableStream { } + export interface WriteStream extends WritableStream { } + + export function rename(oldPath: string, newPath: string, callback?: (err?: ErrnoException) => void): void; + export function renameSync(oldPath: string, newPath: string): void; + export function truncate(path: string, callback?: (err?: ErrnoException) => void): void; + export function truncate(path: string, len: number, callback?: (err?: ErrnoException) => void): void; + export function truncateSync(path: string, len?: number): void; + export function ftruncate(fd: number, callback?: (err?: ErrnoException) => void): void; + export function ftruncate(fd: number, len: number, callback?: (err?: ErrnoException) => void): void; + export function ftruncateSync(fd: number, len?: number): void; + export function chown(path: string, uid: number, gid: number, callback?: (err?: ErrnoException) => void): void; + export function chownSync(path: string, uid: number, gid: number): void; + export function fchown(fd: number, uid: number, gid: number, callback?: (err?: ErrnoException) => void): void; + export function fchownSync(fd: number, uid: number, gid: number): void; + export function lchown(path: string, uid: number, gid: number, callback?: (err?: ErrnoException) => void): void; + export function lchownSync(path: string, uid: number, gid: number): void; + export function chmod(path: string, mode: number, callback?: (err?: ErrnoException) => void): void; + export function chmod(path: string, mode: string, callback?: (err?: ErrnoException) => void): void; + export function chmodSync(path: string, mode: number): void; + export function chmodSync(path: string, mode: string): void; + export function fchmod(fd: number, mode: number, callback?: (err?: ErrnoException) => void): void; + export function fchmod(fd: number, mode: string, callback?: (err?: ErrnoException) => void): void; + export function fchmodSync(fd: number, mode: number): void; + export function fchmodSync(fd: number, mode: string): void; + export function lchmod(path: string, mode: number, callback?: (err?: ErrnoException) => void): void; + export function lchmod(path: string, mode: string, callback?: (err?: ErrnoException) => void): void; + export function lchmodSync(path: string, mode: number): void; + export function lchmodSync(path: string, mode: string): void; + export function stat(path: string, callback?: (err: ErrnoException, stats: Stats) => any): void; + export function lstat(path: string, callback?: (err: ErrnoException, stats: Stats) => any): void; + export function fstat(fd: number, callback?: (err: ErrnoException, stats: Stats) => any): void; + export function statSync(path: string): Stats; + export function lstatSync(path: string): Stats; + export function fstatSync(fd: number): Stats; + export function link(srcpath: string, dstpath: string, callback?: (err?: ErrnoException) => void): void; + export function linkSync(srcpath: string, dstpath: string): void; + export function symlink(srcpath: string, dstpath: string, type?: string, callback?: (err?: ErrnoException) => void): void; + export function symlinkSync(srcpath: string, dstpath: string, type?: string): void; + export function readlink(path: string, callback?: (err: ErrnoException, linkString: string) => any): void; + export function readlinkSync(path: string): string; + export function realpath(path: string, callback?: (err: ErrnoException, resolvedPath: string) => any): void; + export function realpath(path: string, cache: {[path: string]: string}, callback: (err: ErrnoException, resolvedPath: string) =>any): void; + export function realpathSync(path: string, cache?: {[path: string]: string}): void; + export function unlink(path: string, callback?: (err?: ErrnoException) => void): void; + export function unlinkSync(path: string): void; + export function rmdir(path: string, callback?: (err?: ErrnoException) => void): void; + export function rmdirSync(path: string): void; + export function mkdir(path: string, callback?: (err?: ErrnoException) => void): void; + export function mkdir(path: string, mode: number, callback?: (err?: ErrnoException) => void): void; + export function mkdir(path: string, mode: string, callback?: (err?: ErrnoException) => void): void; + export function mkdirSync(path: string, mode?: number): void; + export function mkdirSync(path: string, mode?: string): void; + export function readdir(path: string, callback?: (err: ErrnoException, files: string[]) => void): void; + export function readdirSync(path: string): string[]; + export function close(fd: number, callback?: (err?: ErrnoException) => void): void; + export function closeSync(fd: number): void; + export function open(path: string, flags: string, callback?: (err: ErrnoException, fd: number) => any): void; + export function open(path: string, flags: string, mode: number, callback?: (err: ErrnoException, fd: number) => any): void; + export function open(path: string, flags: string, mode: string, callback?: (err: ErrnoException, fd: number) => any): void; + export function openSync(path: string, flags: string, mode?: number): number; + export function openSync(path: string, flags: string, mode?: string): number; + export function utimes(path: string, atime: number, mtime: number, callback?: (err?: ErrnoException) => void): void; + export function utimesSync(path: string, atime: number, mtime: number): void; + export function futimes(fd: number, atime: number, mtime: number, callback?: (err?: ErrnoException) => void): void; + export function futimesSync(fd: number, atime: number, mtime: number): void; + export function fsync(fd: number, callback?: (err?: ErrnoException) => void): void; + export function fsyncSync(fd: number): void; + export function write(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: ErrnoException, written: number, buffer: NodeBuffer) => void): void; + export function writeSync(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number): number; + export function read(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: ErrnoException, bytesRead: number, buffer: NodeBuffer) => void): void; + export function readSync(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number): number; + export function readFile(filename: string, options: { encoding?: string; flag?: string; }, callback: (err: ErrnoException, data: any) => void): void; + export function readFile(filename: string, callback: (err: ErrnoException, data: NodeBuffer) => void ): void; + export function readFileSync(filename: string, options?: { flag?: string; }): NodeBuffer; + export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string; + export function writeFile(filename: string, data: any, callback?: (err: ErrnoException) => void): void; + export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: ErrnoException) => void): void; + export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: ErrnoException) => void): void; + export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; + export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; + export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: ErrnoException) => void): void; + export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: ErrnoException) => void): void; + export function appendFile(filename: string, data: any, callback?: (err: ErrnoException) => void): void; + export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; + export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; + export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void; + export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats) => void): void; + export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats) => void): void; + export function watch(filename: string, listener?: (event: string, filename: string) => any): FSWatcher; + export function watch(filename: string, options: { persistent?: boolean; }, listener?: (event: string, filename: string) => any): FSWatcher; + export function exists(path: string, callback?: (exists: boolean) => void): void; + export function existsSync(path: string): boolean; + export function createReadStream(path: string, options?: { + flags?: string; + encoding?: string; + fd?: string; + mode?: number; + bufferSize?: number; + }): ReadStream; + export function createReadStream(path: string, options?: { + flags?: string; + encoding?: string; + fd?: string; + mode?: string; + bufferSize?: number; + }): ReadStream; + export function createWriteStream(path: string, options?: { + flags?: string; + encoding?: string; + string?: string; + }): WriteStream; +} + +declare module "path" { + export function normalize(p: string): string; + export function join(...paths: any[]): string; + export function resolve(...pathSegments: any[]): string; + export function relative(from: string, to: string): string; + export function dirname(p: string): string; + export function basename(p: string, ext?: string): string; + export function extname(p: string): string; + export var sep: string; +} + +declare module "string_decoder" { + export interface NodeStringDecoder { + write(buffer: NodeBuffer): string; + detectIncompleteChar(buffer: NodeBuffer): number; + } + export var StringDecoder: { + new (encoding: string): NodeStringDecoder; + }; +} + +declare module "tls" { + import crypto = require("crypto"); + import net = require("net"); + import stream = require("stream"); + + var CLIENT_RENEG_LIMIT: number; + var CLIENT_RENEG_WINDOW: number; + + export interface TlsOptions { + pfx?: any; //string or buffer + key?: any; //string or buffer + passphrase?: string; + cert?: any; + ca?: any; //string or buffer + crl?: any; //string or string array + ciphers?: string; + honorCipherOrder?: any; + requestCert?: boolean; + rejectUnauthorized?: boolean; + NPNProtocols?: any; //array or Buffer; + SNICallback?: (servername: string) => any; + } + + export interface ConnectionOptions { + host?: string; + port?: number; + socket?: net.NodeSocket; + pfx?: any; //string | Buffer + key?: any; //string | Buffer + passphrase?: string; + cert?: any; //string | Buffer + ca?: any; //Array of string | Buffer + rejectUnauthorized?: boolean; + NPNProtocols?: any; //Array of string | Buffer + servername?: string; + } + + export interface Server extends net.Server { + // Extended base methods + listen(port: number, host?: string, backlog?: number, listeningListener?: Function): void; + listen(path: string, listeningListener?: Function): void; + listen(handle: any, listeningListener?: Function): void; + + listen(port: number, host?: string, callback?: Function): void; + close(): void; + address(): { port: number; family: string; address: string; }; + addContext(hostName: string, credentials: { + key: string; + cert: string; + ca: string; + }): void; + maxConnections: number; + connections: number; + } + + export interface ClearTextStream extends ReadWriteStream { + authorized: boolean; + authorizationError: Error; + getPeerCertificate(): any; + getCipher: { + name: string; + version: string; + }; + address: { + port: number; + family: string; + address: string; + }; + remoteAddress: string; + remotePort: number; + } + + export interface SecurePair { + encrypted: any; + cleartext: any; + } + + export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) =>void ): Server; + export function connect(options: TlsOptions, secureConnectionListener?: () =>void ): ClearTextStream; + export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; + export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; + export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair; +} + +declare module "crypto" { + export interface CredentialDetails { + pfx: string; + key: string; + passphrase: string; + cert: string; + ca: any; //string | string array + crl: any; //string | string array + ciphers: string; + } + export interface Credentials { context?: any; } + export function createCredentials(details: CredentialDetails): Credentials; + export function createHash(algorithm: string): Hash; + export function createHmac(algorithm: string, key: string): Hmac; + interface Hash { + update(data: any, input_encoding?: string): Hash; + digest(encoding?: string): string; + } + interface Hmac { + update(data: any): void; + digest(encoding?: string): void; + } + export function createCipher(algorithm: string, password: any): Cipher; + export function createCipheriv(algorithm: string, key: any, iv: any): Cipher; + interface Cipher { + update(data: any, input_encoding?: string, output_encoding?: string): string; + final(output_encoding?: string): string; + setAutoPadding(auto_padding: boolean): void; + createDecipher(algorithm: string, password: any): Decipher; + createDecipheriv(algorithm: string, key: any, iv: any): Decipher; + } + interface Decipher { + update(data: any, input_encoding?: string, output_encoding?: string): void; + final(output_encoding?: string): string; + setAutoPadding(auto_padding: boolean): void; + } + export function createSign(algorithm: string): Signer; + interface Signer { + update(data: any): void; + sign(private_key: string, output_format: string): string; + } + export function createVerify(algorith: string): Verify; + interface Verify { + update(data: any): void; + verify(object: string, signature: string, signature_format?: string): boolean; + } + export function createDiffieHellman(prime_length: number): DiffieHellman; + export function createDiffieHellman(prime: number, encoding?: string): DiffieHellman; + interface DiffieHellman { + generateKeys(encoding?: string): string; + computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string; + getPrime(encoding?: string): string; + getGenerator(encoding: string): string; + getPublicKey(encoding?: string): string; + getPrivateKey(encoding?: string): string; + setPublicKey(public_key: string, encoding?: string): void; + setPrivateKey(public_key: string, encoding?: string): void; + } + export function getDiffieHellman(group_name: string): DiffieHellman; + export function pbkdf2(password: string, salt: string, iterations: number, keylen: number, callback: (err: Error, derivedKey: string) => any): void; + export function randomBytes(size: number): NodeBuffer; + export function randomBytes(size: number, callback: (err: Error, buf: NodeBuffer) =>void ): void; + export function pseudoRandomBytes(size: number): NodeBuffer; + export function pseudoRandomBytes(size: number, callback: (err: Error, buf: NodeBuffer) =>void ): void; +} + +declare module "stream" { + import events = require("events"); + + export interface ReadableOptions { + highWaterMark?: number; + encoding?: string; + objectMode?: boolean; + } + + export class Readable extends events.EventEmitter implements ReadableStream { + readable: boolean; + constructor(opts?: ReadableOptions); + _read(size: number): void; + read(size?: number): any; + setEncoding(encoding: string): void; + pause(): void; + resume(): void; + pipe(destination: T, options?: { end?: boolean; }): T; + unpipe(destination?: T): void; + unshift(chunk: string): void; + unshift(chunk: NodeBuffer): void; + wrap(oldStream: ReadableStream): ReadableStream; + push(chunk: any, encoding?: string): boolean; + } + + export interface WritableOptions { + highWaterMark?: number; + decodeStrings?: boolean; + } + + export class Writable extends events.EventEmitter implements WritableStream { + writable: boolean; + constructor(opts?: WritableOptions); + _write(data: NodeBuffer, encoding: string, callback: Function): void; + _write(data: string, encoding: string, callback: Function): void; + write(buffer: NodeBuffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: NodeBuffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + } + + export interface DuplexOptions extends ReadableOptions, WritableOptions { + allowHalfOpen?: boolean; + } + + // Note: Duplex extends both Readable and Writable. + export class Duplex extends Readable implements ReadWriteStream { + writable: boolean; + constructor(opts?: DuplexOptions); + _write(data: NodeBuffer, encoding: string, callback: Function): void; + _write(data: string, encoding: string, callback: Function): void; + write(buffer: NodeBuffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: NodeBuffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + } + + export interface TransformOptions extends ReadableOptions, WritableOptions {} + + // Note: Transform lacks the _read and _write methods of Readable/Writable. + export class Transform extends events.EventEmitter implements ReadWriteStream { + readable: boolean; + writable: boolean; + constructor(opts?: TransformOptions); + _transform(chunk: NodeBuffer, encoding: string, callback: Function): void; + _transform(chunk: string, encoding: string, callback: Function): void; + _flush(callback: Function): void; + read(size?: number): any; + setEncoding(encoding: string): void; + pause(): void; + resume(): void; + pipe(destination: T, options?: { end?: boolean; }): T; + unpipe(destination?: T): void; + unshift(chunk: string): void; + unshift(chunk: NodeBuffer): void; + wrap(oldStream: ReadableStream): ReadableStream; + push(chunk: any, encoding?: string): boolean; + write(buffer: NodeBuffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: NodeBuffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + } + + export class PassThrough extends Transform {} +} + +declare module "util" { + export interface InspectOptions { + showHidden?: boolean; + depth?: number; + colors?: boolean; + customInspect?: boolean; + } + + export function format(format: any, ...param: any[]): string; + export function debug(string: string): void; + export function error(...param: any[]): void; + export function puts(...param: any[]): void; + export function print(...param: any[]): void; + export function log(string: string): void; + export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string; + export function inspect(object: any, options: InspectOptions): string; + export function isArray(object: any): boolean; + export function isRegExp(object: any): boolean; + export function isDate(object: any): boolean; + export function isError(object: any): boolean; + export function inherits(constructor: any, superConstructor: any): void; +} + +declare module "assert" { + function internal (value: any, message?: string): void; + module internal { + export class AssertionError implements Error { + name: string; + message: string; + actual: any; + expected: any; + operator: string; + generatedMessage: boolean; + + constructor(options?: {message?: string; actual?: any; expected?: any; + operator?: string; stackStartFunction?: Function}); + } + + export function fail(actual?: any, expected?: any, message?: string, operator?: string): void; + export function ok(value: any, message?: string): void; + export function equal(actual: any, expected: any, message?: string): void; + export function notEqual(actual: any, expected: any, message?: string): void; + export function deepEqual(actual: any, expected: any, message?: string): void; + export function notDeepEqual(acutal: any, expected: any, message?: string): void; + export function strictEqual(actual: any, expected: any, message?: string): void; + export function notStrictEqual(actual: any, expected: any, message?: string): void; + export var throws: { + (block: Function, message?: string): void; + (block: Function, error: Function, message?: string): void; + (block: Function, error: RegExp, message?: string): void; + (block: Function, error: (err: any) => boolean, message?: string): void; + } + + export var doesNotThrow: { + (block: Function, message?: string): void; + (block: Function, error: Function, message?: string): void; + (block: Function, error: RegExp, message?: string): void; + (block: Function, error: (err: any) => boolean, message?: string): void; + } + + export function ifError(value: any): void; + } + + export = internal; +} + +declare module "tty" { + import net = require("net"); + + export function isatty(fd: number): boolean; + export interface ReadStream extends net.NodeSocket { + isRaw: boolean; + setRawMode(mode: boolean): void; + } + export interface WriteStream extends net.NodeSocket { + columns: number; + rows: number; + } +} + +declare module "domain" { + import events = require("events"); + + export class Domain extends events.EventEmitter { + run(fn: Function): void; + add(emitter: NodeEventEmitter): void; + remove(emitter: NodeEventEmitter): void; + bind(cb: (err: Error, data: any) => any): any; + intercept(cb: (data: any) => any): any; + dispose(): void; + + addListener(event: string, listener: Function): Domain; + on(event: string, listener: Function): Domain; + once(event: string, listener: Function): Domain; + removeListener(event: string, listener: Function): Domain; + removeAllListeners(event?: string): Domain; + } + + export function create(): Domain; +} diff --git a/clients/nodejs/package.json b/clients/nodejs/package.json new file mode 100644 index 0000000..43cd755 --- /dev/null +++ b/clients/nodejs/package.json @@ -0,0 +1,44 @@ +{ + "name": "tsd-metrics-client", + "preferGlobal": false, + "version": "2.0.3", + "author": "Mohammed Kamel ", + "description": "Node JS class for publishing metrics as time series data (TSD). (2c)", + "contributors": [ + { + "name": "Mohammed Kamel", + "email": "cyber.maak@gmail.com" + } + ], + "scripts": { + "test": "node test/test.js" + }, + "main": "./lib/tsd-metrics-client", + "repository": { + "type": "git", + "url": "git@github.com:BrandonArp/tsdaggregator.git" + }, + "directories": { + "test": "test", + "lib": "lib" + }, + "keywords": [ + "tsd", + "aggregator", + "metrics", + "client", + "2c" + ], + "dependencies": { + "log4js": "*" + }, + "analyze": false, + "devDependencies": { + "colors": "*", + "typescript": "0.9.1-1" + }, + "license": "MIT", + "engines": { + "node": ">=0.6" + } +} \ No newline at end of file diff --git a/clients/nodejs/test/test.js b/clients/nodejs/test/test.js new file mode 100644 index 0000000..bdff93a --- /dev/null +++ b/clients/nodejs/test/test.js @@ -0,0 +1,116 @@ +tsd = require('../lib/tsd-metrics-client') +colors = require('colors'); + +tsd.TsdMetrics.CONSOLE_ECHO = true; +function defaultLog(message) { + if (Object.keys(arguments).length === 1) { + console.log(message.yellow); + } else { + var args = arguments; + delete args[0]; + console.log(message.yellow, args); + } +} +var tests = [ + function test1(done) { + var m = new tsd.TsdMetrics(); + + defaultLog("start timer1"); + m.startTimer("timer1"); + + var tmp = Math.floor(Math.random() * 50.0); + defaultLog("increment counter 'hello' by " + tmp) + m.incrementCounter("hello", tmp); + + defaultLog("decrement counter 'world'") + m.decrementCounter("world"); + + defaultLog("reset counter 'world'") + m.resetCounter("world"); + + tmp = Math.floor(Math.random() * 50.0); + defaultLog("decrement counter 'world' by " + tmp) + m.decrementCounter("world", tmp); + + tmp = Math.random() * 1000; + defaultLog("set gauge 'gg' to " + tmp) + m.setGauge("gg", tmp); + + tmp = Math.random() * 1000; + defaultLog("set gauge 'gg' to " + tmp) + m.setGauge("gg", tmp); + + setTimeout(function () { + defaultLog("stop timer1 after ~750ms"); + m.stopTimer("timer1"); + m.close(); + done(); + }, 750); + }, + + function test2(done) { + var m = new tsd.TsdMetrics(); + + defaultLog("start timer1"); + m.startTimer("timer1"); + + defaultLog("start timer2"); + m.startTimer("timer2"); + + defaultLog("start timer3"); + m.startTimer("timer3"); + + setTimeout(function () { + defaultLog("stop timer1 after ~750ms"); + m.stopTimer("timer1"); + defaultLog("start timer1"); + m.startTimer("timer1"); + setTimeout(function () { + defaultLog("stop timer2 after ~" + (750 + 150) + "ms"); + m.stopTimer("timer2"); + setTimeout(function () { + defaultLog("stop timer2 after ~" + (450 + 150) + "ms"); + m.stopTimer("timer1") + defaultLog("close and auto stop timer3 after ~" + (750 + 150 + 450) + "ms") + m.close(); + done(); + }, 450); + }, 150); + }, 750); + }, + function test3(done) { + var m = new tsd.TsdMetrics(); + m.addListener("error", function(err){console.log(err.toString().red)}); + + var tmp = Math.floor(Math.random() * 50.0); + defaultLog("increment counter 'hello' by " + tmp) + m.incrementCounter("hello", tmp); + + tmp = Math.random() * 1000; + defaultLog("set gauge 'gg' to " + tmp) + m.setGauge("gg", tmp); + + defaultLog("closing"); + m.close(); + defaultLog("closing again"); + m.close(); + done(); + } +]; + +var count = 0; +function functionName(fun) { + var ret = fun.toString(); + ret = ret.substr('function '.length); + ret = ret.substr(0, ret.indexOf('(')); + return ret; +} +function executeTests() { + if (count < tests.length) { + defaultLog('=========================================='); + defaultLog(("Executing " + functionName(tests[count]))); + defaultLog("=========================================="); + tests[count++](executeTests); + } +} +executeTests(); \ No newline at end of file diff --git a/clients/nodejs/tsd-metrics-client.ts b/clients/nodejs/tsd-metrics-client.ts new file mode 100644 index 0000000..9189919 --- /dev/null +++ b/clients/nodejs/tsd-metrics-client.ts @@ -0,0 +1,337 @@ +/// +/// +/// +import tsdDef = require("tsd"); +import log4js = require("log4js"); +import events = require("events"); + +/** + * Class for managing samples for a counter + */ +class CounterSamples { + private samples:number[] = new Array < number >(); + private lastIndex:number = 0; + + constructor() { + this.reset(); + } + + /** + * Create a new sample for the counter with value of zero + */ + public reset():void { + this.lastIndex = this.samples.push(0) - 1 + } + + /** + * Increment the current sample + * @param value Signed value to increment the sample byt + */ + public increment(value:number):void { + this.samples[this.lastIndex] += value; + } + + public toJSON() { + return this.samples; + } +} + +/** + * Class for creating duration sample for a timer + */ +class TimerSamples { + private durations:number[] = new Array < number >(); + private startTime:number; + + /** + * Add explicit timer duration + * @param duration + */ + public addDuration(duration:number):void { + this.durations.push(duration); + } + + /** + * Start a new timer + */ + public start():void { + this.startTime = Date.now(); + } + + /** + * Stop the current timer + */ + public stop():void { + if (this.startTime != undefined) { + this.addDuration(Date.now() - this.startTime) + } + this.startTime = undefined; + } + + public toJSON() { + return this.durations; + } +} + +class Lazy { + private factory:()=>T; + private value:T; + + constructor(factory:()=>T) { + this.factory = factory; + } + + public getValue():T { + if (this.value == undefined) { + this.value = this.factory(); + } + return this.value; + } +} + +/** + * Node JS class for publishing metrics as time series data (TSD). + * For more information see: + * + * https://wiki.groupondev.com/TsdAggregator + */ +export class TsdMetrics extends events.EventEmitter implements tsdDef.Metrics { + /** + * Sets the maximums size of log in bytes before rolling a new file + * Default: 32 MB + * @type {number} + */ + public static MAX_LOG_SIZE:number = 32 * 1024 * 1024; + /** + * Sets the maximum number of log files backup to retain. + * Default: 10 + * @type {number} + */ + public static LOG_BACKUPS:number = 10; + /** + * Sets a flag to output the metrics to console in addition to the query file + * Default: false + * @type {boolean} + */ + public static CONSOLE_ECHO:boolean = false; + + /** + * Singleton instance of the + */ + private static LOGGER:Lazy = + new Lazy(() => { + var appendersArray:any = [ + { + type: "file", + filename: "tsd-query.log", + maxLogSize: TsdMetrics.MAX_LOG_SIZE, + backups: TsdMetrics.LOG_BACKUPS, + layout: { + type: "pattern", + pattern: "%m" + }, + category: "tsd-client" + } + ]; + if (TsdMetrics.CONSOLE_ECHO) { + appendersArray.push( + { + type: "console", + layout: { + type: "pattern", + pattern: "%m" + }, + category: "tsd-client" + } + ); + } + var config = { + appenders: appendersArray + }; + + log4js.configure(config, {}); + + return log4js.getLogger("tsd-client"); + }); + + /** + * + */ + private isOpen:boolean = true; + + /** + * Assert that a condition is true and emit an error event and + * @param condition + * @param message + * @returns {boolean} + */ + private assert(condition:boolean, message:string):boolean { + if (!condition) { + this.emit("error", new Error(message)); + return false; + } + return true; + } + + //anonymous type for representing the final json blob + private logEntry:{ + annotations:{[name:string]: string + }; + counters:{[name:string]: CounterSamples + }; + gauges:{[name:string]: number[] + }; + timers:{[name:string]: TimerSamples + }; + version:string; + } = { + annotations: {}, + counters: {}, + gauges: {}, + timers: {}, + version: "2c" + }; + + private assertIsOpen():boolean { + return this.assert(this.isOpen, "Metrics object was not opened or it's already closedo"); + } + + constructor() { + super(); + //according to http://nodejs.org/docs/v0.3.5/api/events.html#events.EventEmitter + //if an error event is emitted and nothing was listening, the process will exist, so we are adding this + //do-nothing listener in order not to exist the process + this.addListener("error", (error)=> { + }); + this.annotate("initTimestamp", (Date.now() / 1000.0).toString()) + } + + /** + * Increment the specified counter by the specified amount. All counters are + * initialized to zero. + * + * @param name The name of the counter. + * @param value The amount to increment by. + */ + public incrementCounter(name:string, value:number = 1):void { + this.assertIsOpen(); + if (this.logEntry.counters[name] == undefined) { + this.logEntry.counters[name] = new CounterSamples(); + } + this.logEntry.counters[name].increment(value); + } + + /** + * Decrement the specified counter by the specified amount. All counters are + * initialized to zero. + * + * @param name The name of the counter. + * @param value The amount to decrement by. + */ + public decrementCounter(name:string, value:number = 1) { + this.incrementCounter(name, -value); + } + + /** + * Reset the counter to zero. This most commonly used to record a zero-count + * for a particular counter. If clients wish to record set count metrics + * then all counters should be reset before conditionally invoking increment + * and/or decrement. + * + * @param name The name of the counter. + */ + public resetCounter(name:string) { + if (this.assertIsOpen()) { + if (this.logEntry.counters[name] == undefined) { + this.logEntry.counters[name] = new CounterSamples(); + } else { + this.logEntry.counters[name].reset(); + } + } + } + + /** + * Start the specified timer measurement. + * + * @param name The name of the timer. + */ + public startTimer(name:string) { + if (this.assertIsOpen()) { + if (this.logEntry.timers[name] == undefined) { + this.logEntry.timers[name] = new TimerSamples(); + } + this.logEntry.timers[name].start(); + } + } + + /** + * Stop the specified timer measurement. + * + * @param name The name of the timer. + */ + public stopTimer(name:string) { + if (this.assertIsOpen()) { + this.assert(this.logEntry.timers[name] != undefined, "Timer does not exist; you must start the timer first") + this.logEntry.timers[name].stop(); + } + } + + /** + * Set the timer to the specified value. This is most commonly used to + * record timers from external sources that are not integrated with metrics. + * + * @param name The name of the timer. + * @param duration The duration of the timer in milliseconds. + */ + public setTimer(name:string, durationMilliseconds:number) { + if (this.assertIsOpen()) { + if (this.logEntry.timers[name] == undefined) { + this.logEntry.timers[name] = new TimerSamples(); + } + this.logEntry.timers[name].addDuration(durationMilliseconds); + } + } + + /** + * Set the specified gauge reading. + * + * @param name The name of the gauge. + * @param value The reading on the gauge + */ + public setGauge(name:string, value:number) { + if (this.assertIsOpen()) { + if (this.logEntry.gauges[name] == undefined) { + this.logEntry.gauges[name] = new Array < number >(); + } + this.logEntry.gauges[name].push(value); + } + } + + /** + * Add an attribute that describes the captured metrics or context. + * + * @param key The name of the attribute. + * @param value The value of the attribute. + */ + public annotate(key:string, value:string) { + if (this.assertIsOpen()) { + this.logEntry.annotations[key] = value; + } + } + + /** + * Close the metrics object. This should complete publication of metrics to + * the underlying data store. Once the metrics object is closed, no further + * metrics can be recorded. + */ + public close() { + if (this.assertIsOpen()) { + this.annotate("finalTimestamp", (Date.now() / 1000.0).toString()); + for (var timer in this.logEntry.timers) { + this.logEntry.timers[timer].stop(); + } + TsdMetrics.LOGGER.getValue().info(JSON.stringify(this.logEntry)); + this.isOpen = false; + } + } +}