UNPKG

opentsdb-client

Version:

HTTP client for querying OpenTSDB.

456 lines (400 loc) 13 kB
/** * * OPENTSDB: Client * * * DESCRIPTION: * - OpenTSDB REST API client. * * * NOTES: * [1] * * * TODO: * [1] * * * LICENSE: * MIT * * Copyright (c) 2014. Athan Reines. * * * AUTHOR: * Athan Reines. kgryte@gmail.com. * */ 'use strict'; // MODULES // var // Time format validation: validate = require( 'opentsdb-validate-time' ), // Query superclass: Query = require( 'opentsdb-query' ), // Request URL template generator: urlFactory = require( 'opentsdb-url' ), // Queries OpenTSDB: get = require( './request/get.js' ); // VARIABLES // var ANNOTATIONS = [ 'none', 'local', 'all' ], IP = /^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$|^localhost$/i; // CLIENT // /** * FUNCTION: Client() * OpenTSDB query client constructor. * * @constructor * @returns {Client} Client instance */ function Client() { this._host = '127.0.0.1'; // localhost this._port = 4242; // default OpenTSDB port // Output: (opinionated defaults) this._ms = true; this._arrays = true; this._tsuids = false; this._annotations = 'none'; // ["none","local","all"] // Time: this._start = null; // required this._end = null; // Queries: this._queries = null; // required // URL generator: this._url = urlFactory( this ); return this; } // end FUNCTION Client() /** * METHOD: host( url ) * Host URL setter and getter. If a URL is supplied, sets the host URL. If no URL is supplied, returns the host URL. * * @param {String} [url] - host URL * @returns {Client|String} Client instance or host URL */ Client.prototype.host = function( url ) { if ( !arguments.length ) { return this._host; } if ( typeof url !== 'string' ) { throw new TypeError( 'host()::invalid input argument. URL must be a string.' ); } if ( !IP.test( url ) ) { throw new Error( 'host()::invalid input argument. URL is not valid. Ensure valid IP or `localhost`.' ); } this._host = url; return this; }; // end METHOD host() /** * METHOD: port( port ) * Port setter and getter. If a port is supplied, sets the port. If no port is supplied, returns the port. * * @param {Number} [port] - TSDB port * @returns {Client|Number} Client instance or port */ Client.prototype.port = function( port ) { if ( !arguments.length ) { return this._port; } if ( typeof port !== 'number' || port !== port ) { throw new TypeError( 'port()::invalid input argument. Port must be a number.' ); } this._port = port; return this; }; // end METHOD port() /** * METHOD: ms( bool ) * Millisecond resolution setter and getter. If a boolean is provided, sets the flag. If no boolean provided, returns the flag. * * @param {Boolean} [bool] - boolean flag * @returns {Client|Boolean} Client instance or boolean flag */ Client.prototype.ms = function( bool ) { if ( !arguments.length ) { return this._ms; } if ( typeof bool !== 'boolean' ) { throw new TypeError( 'ms()::invalid input argument. Flag must be a boolean.' ); } this._ms = bool; return this; }; // end METHOD ms() /** * METHOD: arrays( bool ) * Array output setter and getter. If a boolean is provided, sets the flag. If no boolean provided, returns the flag. * * @param {Boolean} [bool] - boolean flag * @returns {Client|Boolean} Client instance or boolean flag */ Client.prototype.arrays = function( bool ) { if ( !arguments.length ) { return this._arrays; } if ( typeof bool !== 'boolean' ) { throw new TypeError( 'arrays()::invalid input argument. Flag must be a boolean.' ); } this._arrays = bool; return this; }; // end METHOD arrays() /** * METHOD: tsuids( bool ) * TSUIDs output setter and getter. If a boolean is provided, sets the flag. If no boolean provided, returns the flag. * * @param {Boolean} [bool] - boolean flag * @returns {Client|Boolean} Client instance or boolean flag */ Client.prototype.tsuids = function( bool ) { if ( !arguments.length ) { return this._tsuids; } if ( typeof bool !== 'boolean' ) { throw new TypeError( 'tsuids()::invalid input argument. Flag must be a boolean.' ); } this._tsuids = bool; return this; }; // end METHOD tsuids() /** * METHOD: annotations( value ) * Annotations output setter and getter. If a value is provided, sets the annotations option. If no value is provided, returns the flag. * * @param {String} [value] - annotations setting: ["none","local","all"], where `all` refers to both local and global annotations * @returns {Client|String} Client instance or setting */ Client.prototype.annotations = function( value ) { if ( !arguments.length ) { return this._annotations; } if ( typeof value !== 'string' ) { throw new TypeError( 'annotations()::invalid input argument. Input argument must be a string.' ); } value = value.toLowerCase(); if ( ANNOTATIONS.indexOf( value ) === -1 ) { throw new Error( 'annotations()::invalid input argument. Input argument must be one of the following: ' + JSON.stringify( ANNOTATIONS ) + '.' ); } this._annotations = value; return this; }; // end METHOD annotations() /** * METHOD: start( value ) * Query start time setter and getter. If a value is provided, sets the query start time. If no value is provided, returns the query start time. NOTE: by default, the start time is null. * * @param {String|Number} [value] - query start time; may be either a relative time string, absolute time string, or a UNIX timestamp * @returns {Client|String|Number|null} Client instance or query start time */ Client.prototype.start = function( value ) { if ( !arguments.length ) { return this._start; } if ( typeof value !== 'string' && ( typeof value !== 'number' || value !== value ) ) { throw new TypeError( 'start()::invalid input argument. Start time must be either a string or numeric.' ); } if ( !validate.format( value ) ) { throw new Error( 'start()::invalid input argument. Start time must be a valid time.' ); } this._start = value; return this; }; // end METHOD start() /** * METHOD: end( value ) * Query end time setter and getter. If a value is provided, sets the end start time. If no value is provided, returns the query end time. NOTE: setting the value to NULL means that OpenTSDB will read data from the specified start time to the time of read. * * @param {String|Number|null} [value] - query end time; a valid time may be either a relative time string, absolute time string, or a UNIX timestamp * @returns {Client|String|Number|null} Client instance or query end time */ Client.prototype.end = function( value ) { if ( !arguments.length ) { return this._end; } if ( value === null ) { this._end = value; return this; } if ( typeof value !== 'string' && ( typeof value !== 'number' || value !== value ) ) { throw new TypeError( 'end()::invalid input argument. End time must be either a string or numeric.' ); } if ( !validate.format( value ) ) { throw new Error( 'end()::invalid input argument. End time must be a valid time.' ); } this._end = value; return this; }; // end METHOD end() /** * METHOD: queries( query1[, query2, query3, ...] ) * OpenTSDB queries setter and getter. If queries are provided, sets the queries. If no queries are provided, returns the queries. Note: provided queries overwrite any existing queries. Additionally, returned queries are mutable. Modifying the query instances will affect all future data requests. By default, queries are null. * * @param {...Query} [query] - metric and/or TSUID queries * @returns {Client|Array|null} Client instance or queries */ Client.prototype.queries = function() { var numArgs = arguments.length, arg; if ( !numArgs ) { return this._queries; } for ( var i = 0; i < numArgs; i++ ) { arg = arguments[ i ]; if ( !(arg instanceof Query) ) { throw new TypeError( 'queries()::invalid input argument. Provided queries must be Query instances.' ); } } this._queries = Array.prototype.slice.call( arguments ); return this; }; // end METHOD queries() /** * METHOD: url() * Builds a request URL. * * @returns {String} request URL. */ Client.prototype.url = function() { if ( !this._start ) { throw new Error( 'url()::not initialized. Must first specify a query start time.' ); } if ( !this._queries || !this._queries.length ) { throw new Error( 'url()::not initialized. Must first set queries before building a URL.' ); } var url = this._url .template() .create( this._start, this._end ); return url; }; // end METHOD url() /** * METHOD: get( clbk ) * Queries OpenTSDB. * * @param {Function} clbk - callback to be invoked after returning a response. Function should accept two arguments: [ error, data ]. If no errors, error is null. * @returns {Client} Client instance */ Client.prototype.get = function( clbk ) { if ( typeof clbk !== 'function' ) { throw new TypeError( 'get()::invalid input argument. Callback must be a function.' ); } // Get a query function: var fcn = get( this.url(), function onData( error, data ) { if ( error ) { clbk( error ); return; } clbk( null, data ); }); // Make the request: fcn(); return this; }; // end METHOD get() /** * METHOD: aggregators( clbk ) * Queries OpenTSDB and returns a list of available aggregators. * * @param {Function} clbk - callback to invoke after returning a response. Function should accept two arguments: [ error, aggregators ]. If no errors, error is null. `aggregators` is an array. * @returns {Client} Client instance */ Client.prototype.aggregators = function( clbk ) { var url, fcn; if ( typeof clbk !== 'function' ) { throw new TypeError( 'aggregators()::invalid input argument. Callback must be a function.' ); } url = 'http://'+this._host+':'+this._port+'/api/aggregators'; fcn = get( url, function onResponse( error, aggregators ) { if ( error ) { clbk( error ); return; } clbk( null, aggregators ); }); fcn(); return this; }; // end METHOD aggregators() /** * METHOD: metrics( clbk ) * Queries OpenTSDB and returns a list of metrics. * * @param {Function} clbk - callback to invoke after returning a response. Function should accept two arguments: [ error, metrics ]. If no errors, error is null. `metrics` is an array. * @returns {Client} Client instance */ Client.prototype.metrics = function( clbk ) { var url, fcn; if ( typeof clbk !== 'function' ) { throw new TypeError( 'metrics()::invalid input argument. Callback must be a function.' ); } url = 'http://'+this._host+':'+this._port+'/api/suggest?type=metrics&max=1000000000&q='; fcn = get( url, function onResponse( error, metrics ) { if ( error ) { clbk( error ); return; } clbk( null, metrics ); }); fcn(); return this; }; // end METHOD metrics() /** * METHOD: config( clbk ) * Queries OpenTSDB for its current running configuration. * * @param {Function} clbk - callback to invoke after returning a response. Function should accept two arguments: [ error, config ]. If no errors, error is null. `config` is an object. * @returns {Client} Client instance */ Client.prototype.config = function( clbk ) { var url, fcn; if ( typeof clbk !== 'function' ) { throw new TypeError( 'config()::invalid input argument. Callback must be a function.' ); } url = 'http://'+this._host+':'+this._port+'/api/config'; fcn = get( url, function onResponse( error, config ) { if ( error ) { clbk( error ); return; } clbk( null, config ); }); fcn(); return this; }; // end METHOD config() /** * METHOD: version( clbk ) * Queries OpenTSDB and returns its version. * * @param {Function} clbk - callback to invoke after returning a response. Function should accept two arguments: [ error, version ]. If no errors, error is null. `version` is an object. * @returns {Client} Client instance */ Client.prototype.version = function( clbk ) { var url, fcn; if ( typeof clbk !== 'function' ) { throw new TypeError( 'version()::invalid input argument. Callback must be a function.' ); } url = 'http://'+this._host+':'+this._port+'/api/version'; fcn = get( url, function onResponse( error, version ) { if ( error ) { clbk( error ); return; } clbk( null, version ); }); fcn(); return this; }; // end METHOD version() /** * METHOD: dropcaches( clbk ) * Instructs OpenTSDB to purge its in-memory caches. * * @param {Function} clbk - callback to invoke after returning a response. Function should accept two arguments: [ error, body ]. If no errors, error is null. `body` is an object with `message` and `status` fields. * @returns {Client} Client instance */ Client.prototype.dropcaches = function( clbk ) { var url, fcn; if ( typeof clbk !== 'function' ) { throw new TypeError( 'dropcaches()::invalid input argument. Callback must be a function.' ); } url = 'http://'+this._host+':'+this._port+'/api/dropcaches'; fcn = get( url, function onResponse( error, body ) { if ( error ) { clbk( error ); return; } clbk( null, body ); }); fcn(); return this; }; // end METHOD dropcaches() // EXPORTS // module.exports = function createClient(){ return new Client(); };