Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logger refactor #436

Merged
merged 4 commits into from Dec 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 26 additions & 24 deletions docs/_reference/BaseAPIClient.md
Expand Up @@ -6,52 +6,52 @@ permalink: /reference/BaseAPIClient
**Kind**: global class

* [BaseAPIClient](#BaseAPIClient)
* [new BaseAPIClient(token, opts)](#new_BaseAPIClient_new)
* [new BaseAPIClient(token, [opts])](#new_BaseAPIClient_new)
* [.slackAPIUrl](#BaseAPIClient+slackAPIUrl) : <code>string</code>
* [.transport](#BaseAPIClient+transport) : <code>function</code>
* [.retryConfig](#BaseAPIClient+retryConfig)
* [.logger](#BaseAPIClient+logger) : <code>function</code>
* [.logger](#BaseAPIClient+logger) : <code>BaseAPIClient~logFn</code>
* [.transport](#BaseAPIClient+transport) : <code>BaseAPIClient~transportFn</code>
* [.retryConfig](#BaseAPIClient+retryConfig) : <code>Object</code>
* [._createFacets()](#BaseAPIClient+_createFacets)
* [.registerDataStore(dataStore)](#BaseAPIClient+registerDataStore)
* [._callTransport(task, queueCb)](#BaseAPIClient+_callTransport)

<a name="new_BaseAPIClient_new"></a>

### new BaseAPIClient(token, opts)
### new BaseAPIClient(token, [opts])
Base client for both the RTM and web APIs.


| Param | Type | Description |
| --- | --- | --- |
| token | <code>string</code> | The Slack API token to use with this client. |
| opts | <code>Object</code> | |
| opts.slackAPIUrl | <code>String</code> | The Slack API URL. |
| opts.transport | <code>function</code> | Function to call to make an HTTP call to the Slack API. |
| [opts.logLevel] | <code>string</code> | The log level for the logger. |
| [opts.logger] | <code>function</code> | Function to use for log calls, takes (logLevel, logString) params. |
| opts.maxRequestConcurrency | <code>Number</code> | The max # of concurrent requests to make to Slack's API's, defaults to 3. |
| opts.retryConfig | <code>Object</code> | The configuration to use for the retry operation, {@see https://github.com/SEAPUNK/node-retry} |
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| token | <code>string</code> | | The Slack API token to use with this client. |
| [opts] | <code>Object</code> | | |
| [opts.slackAPIUrl] | <code>string</code> | <code>&quot;https://slack.com/api/&quot;</code> | The Slack API URL. |
| [opts.transport] | <code>BaseAPIClient~transportFn</code> | | Function to call to make an HTTP call to the Slack API. |
| [opts.logLevel] | <code>string</code> | | The log level for the logger. |
| [opts.logger] | <code>BaseAPIClient~logFn</code> | | Function to use for log calls, takes (logLevel, logString) params. |
| opts.maxRequestConcurrency | <code>number</code> | | The max # of concurrent requests to make to Slack's API's, defaults to 3. |
| opts.retryConfig | <code>Object</code> | | The configuration to use for the retry operation, {@see https://github.com/tim-kos/node-retry} |

<a name="BaseAPIClient+slackAPIUrl"></a>

### baseAPIClient.slackAPIUrl : <code>string</code>
**Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>
<a name="BaseAPIClient+logger"></a>

### baseAPIClient.logger : <code>BaseAPIClient~logFn</code>
The logger function attached to this client.

**Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>
<a name="BaseAPIClient+transport"></a>

### baseAPIClient.transport : <code>function</code>
### baseAPIClient.transport : <code>BaseAPIClient~transportFn</code>
**Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>
<a name="BaseAPIClient+retryConfig"></a>

### baseAPIClient.retryConfig
### baseAPIClient.retryConfig : <code>Object</code>
Default to retrying forever with an exponential backoff, capped at thirty
minutes but with some randomization.

**Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>
<a name="BaseAPIClient+logger"></a>

### baseAPIClient.logger : <code>function</code>
The logger function attached to this client.

**Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>
<a name="BaseAPIClient+_createFacets"></a>

Expand All @@ -65,6 +65,8 @@ Initializes each of the API facets.
### baseAPIClient.registerDataStore(dataStore)
Attaches a data-store to the client instance.

NOTE: In next major version, remove from BaseAPIClient. Only used in RTMClient.

**Kind**: instance method of <code>[BaseAPIClient](#BaseAPIClient)</code>

| Param | Type |
Expand All @@ -83,6 +85,6 @@ This will also manage 429 responses and retry failed operations.

| Param | Type | Description |
| --- | --- | --- |
| task | <code>object</code> | The arguments to pass to the transport. |
| task | <code>Object</code> | The arguments to pass to the transport. |
| queueCb | <code>function</code> | Callback to signal to the request queue that the request has completed. |

2 changes: 1 addition & 1 deletion docs/_reference/WebAPIClient.md
Expand Up @@ -19,7 +19,7 @@ Slack Web API client.
| --- | --- | --- |
| token | | The Slack API token to use with this client. |
| [opts] | <code>Object</code> | |
| opts.retryConfig | <code>Object</code> | The configuration to use for the retry operation, {@see https://github.com/SEAPUNK/node-retry} |
| opts.retryConfig | <code>Object</code> | The configuration to use for the retry operation, {@see https://github.com/tim-kos/node-retry} |

<a name="WebAPIClient+_createFacets"></a>

Expand Down
2 changes: 2 additions & 0 deletions jsdoc.js
@@ -1,3 +1,5 @@
/* eslint-disable no-console */

var jsdoc2md = require('jsdoc-to-markdown');
var fs = require('fs');
var dmd = require('dmd');
Expand Down
82 changes: 44 additions & 38 deletions lib/clients/client.js
Expand Up @@ -13,25 +13,25 @@ var retry = require('retry');

var SlackAPIError = require('./errors').SlackAPIError;
var callTransport = require('./transports/call-transport');
var getLogger = require('../helpers').getLogger;
var helpers = require('./helpers');
var globalHelpers = require('../helpers');
var clientHelpers = require('./helpers');
var requestsTransport = require('./transports/request').requestTransport;
var retryPolicies = require('./retry-policies');


/**
* Base client for both the RTM and web APIs.
* @param {string} token The Slack API token to use with this client.
* @param {Object} opts
* @param {String} opts.slackAPIUrl The Slack API URL.
* @param {Function} opts.transport Function to call to make an HTTP call to the Slack API.
* @param {string=} opts.logLevel The log level for the logger.
* @param {Function=} opts.logger Function to use for log calls, takes (logLevel, logString) params.
* @param {Number} opts.maxRequestConcurrency The max # of concurrent requests to make to Slack's
* @param {Object} [opts]
* @param {string} [opts.slackAPIUrl=https://slack.com/api/] - The Slack API URL.
* @param {BaseAPIClient~transportFn} [opts.transport] - Function to call to make an HTTP call to
* the Slack API.
* @param {string} [opts.logLevel] The log level for the logger.
* @param {BaseAPIClient~logFn} [opts.logger] Function to use for log calls, takes (logLevel, logString) params.
* @param {number} opts.maxRequestConcurrency The max # of concurrent requests to make to Slack's
* API's, defaults to 3.
* @param {Object} opts.retryConfig The configuration to use for the retry operation,
* {@see https://github.com/SEAPUNK/node-retry}
* {@see https://github.com/tim-kos/node-retry}
* @constructor
*/
function BaseAPIClient(token, opts) {
Expand All @@ -47,57 +47,58 @@ function BaseAPIClient(token, opts) {
/** @type {string} */
this.slackAPIUrl = clientOpts.slackAPIUrl || 'https://slack.com/api/';

/** @type {Function} */
/**
* The logger function attached to this client.
* @type {BaseAPIClient~logFn}
*/
this.logger = clientOpts.logger || globalHelpers.getLogger(clientOpts.logLevel);

/** @type {BaseAPIClient~transportFn} */
this.transport = clientOpts.transport || requestsTransport;

/**
* Default to retrying forever with an exponential backoff, capped at thirty
* minutes but with some randomization.
* @type {Object}
*/
this.retryConfig = clientOpts.retryConfig ||
retryPolicies.RETRY_FOREVER_EXPONENTIAL_CAPPED_RANDOM;

/**
*
* @type {Object}
* @type {AsyncQueue}
* @private
*/
this.requestQueue = async.queue(
bind(this._callTransport, this),
clientOpts.maxRequestConcurrency || 3
);

/**
* The logger function attached to this client.
* @type {Function}
*/
this.logger = clientOpts.logger || getLogger(clientOpts.logLevel);

this._createFacets();

this.logger('debug', 'BaseAPIClient initialized');
}

inherits(BaseAPIClient, EventEmitter);

BaseAPIClient.prototype.emit = function emit() {
BaseAPIClient.super_.prototype.emit.apply(this, arguments);
this.logger('debug', arguments);
};


/**
* Initializes each of the API facets.
* @protected
*/
BaseAPIClient.prototype._createFacets = function _createFacets() {
this.logger('debug', 'BaseAPIClient _createFacets end');
};


/**
* Attaches a data-store to the client instance.
*
* NOTE: In next major version, remove from BaseAPIClient. Only used in RTMClient.
*
* @param {SlackDataStore} dataStore
*/
BaseAPIClient.prototype.registerDataStore = function registerDataStore(dataStore) {
this.dataStore = dataStore;
this.logger('debug', 'BaseAPIClient registerDataStore end');
};


Expand All @@ -106,41 +107,43 @@ BaseAPIClient.prototype.registerDataStore = function registerDataStore(dataStore
*
* This will also manage 429 responses and retry failed operations.
*
* @param {object} task The arguments to pass to the transport.
* @param {Object} task The arguments to pass to the transport.
* @param {function} queueCb Callback to signal to the request queue that the request has completed.
* @protected
*/
BaseAPIClient.prototype._callTransport = function _callTransport(task, queueCb) {
var _this = this;
var retryOp = retry.operation(_this.retryConfig);
var self = this;
var retryOp = retry.operation(self.retryConfig);
var retryArgs = {
client: _this,
client: self,
task: task,
queueCb: queueCb,
retryOp: retryOp
};

retryOp.attempt(function attemptTransportCall() {
_this.logger('verbose', 'Retrying', pick(task.args, 'url'));
_this.transport(task.args, partial(callTransport.handleTransportResponse, retryArgs));
self.logger('verbose', 'BaseAPIClient _callTransport - Retrying ' + pick(task.args, 'url'));
self.transport(task.args, partial(callTransport.handleTransportResponse, retryArgs));
});
this.logger('debug', 'BaseAPIClient _callTransport end');
};


/**
* Makes a call to the Slack API.
*
* @param {String} endpoint The API endpoint to send to.
* @param {string} endpoint The API endpoint to send to.
* @param {Object} apiArgs
* @param {Object} apiOptArgs
* @param {Function} optCb The callback to run on completion.
* @param {function} optCb The callback to run on completion.
* @private
*/
BaseAPIClient.prototype._makeAPICall = function _makeAPICall(endpoint, apiArgs, apiOptArgs, optCb) {
var apiCallArgs = helpers.getAPICallArgs(
this._token,
var self = this;
var apiCallArgs = clientHelpers.getAPICallArgs(
self._token,
globalHelpers.getVersionString(),
this.slackAPIUrl,
self.slackAPIUrl,
endpoint,
apiArgs,
apiOptArgs,
Expand All @@ -149,16 +152,18 @@ BaseAPIClient.prototype._makeAPICall = function _makeAPICall(endpoint, apiArgs,
var cb = apiCallArgs.cb;
var args = apiCallArgs.args;
var promise;
var _this = this;

if (!cb) {
promise = new Promise(function makeAPICallPromiseResolver(resolve, reject) {
_this.requestQueue.push({
self.requestQueue.push({
args: args,
cb: function makeAPICallPromiseResolverInner(err, res) {
if (err) {
reject(err);
} else {
// NOTE: inspecting the contents of the response and semantically mapping that to an
// error should probably be some in one place for both callback based invokations, and
// promise based invokations.
if (!res.ok) {
reject(new SlackAPIError(res.error));
} else {
Expand All @@ -169,12 +174,13 @@ BaseAPIClient.prototype._makeAPICall = function _makeAPICall(endpoint, apiArgs,
});
});
} else {
this.requestQueue.push({
self.requestQueue.push({
args: args,
cb: cb
});
}

this.logger('debug', 'BaseAPIClient _makeAPICall end');
return promise;
};

Expand Down
4 changes: 3 additions & 1 deletion lib/clients/rtm/client.js
Expand Up @@ -77,7 +77,7 @@ function RTMClient(token, opts) {
/**
* @type {Function}
*/
this._socketFn = clientOpts.socketFn || wsSocketFn;
this._socketFn = clientOpts.socketFn || wsSocketFn.factory(this.logger);

/**
* The active websocket.
Expand Down Expand Up @@ -135,6 +135,8 @@ function RTMClient(token, opts) {
this.WS_PING_INTERVAL = clientOpts.wsPingInterval || 5000;

this.autoReconnect = clientOpts.autoReconnect !== false;

this.logger('debug', 'RTMClient initialized');
}

inherits(RTMClient, BaseAPIClient);
Expand Down
38 changes: 23 additions & 15 deletions lib/clients/transports/ws.js
Expand Up @@ -6,28 +6,36 @@ var HttpsProxyAgent = require('https-proxy-agent');
var WebSocket = require('ws');
var globalHelpers = require('../../helpers');

var factory = function wsTransportFactory(logger) {
return function wsTransport(socketUrl, opts) {
var wsTransportOpts = opts || {};
var wsOpts = {};
var proxyURL = wsTransportOpts.proxyURL || process.env.https_proxy;

if (proxyURL) {
if (logger) {
logger('info', 'Using https proxy: ' + proxyURL);
}
wsOpts.agent = new HttpsProxyAgent(proxyURL);
}

wsOpts.headers = {
'User-Agent': globalHelpers.getVersionString()
};

return new WebSocket(socketUrl, wsOpts);
};
};

/**
*
* @param {String} socketUrl
* @param {Object=} opts
* @param {String} opts.proxyURL
* @returns {*}
*/
var wsTransport = function wsTransport(socketUrl, opts) {
var wsTransportOpts = opts || {};
var wsOpts = {};
var proxyURL = wsTransportOpts.proxyURL || process.env.https_proxy;

if (proxyURL) {
console.log('Using https proxy: ' + proxyURL);
wsOpts.agent = new HttpsProxyAgent(proxyURL);
}

wsOpts.headers = {
'User-Agent': globalHelpers.getVersionString()
};
var wsTransport = factory();

return new WebSocket(socketUrl, wsOpts);
};

module.exports = wsTransport;
module.exports.factory = factory;
1 change: 1 addition & 0 deletions lib/clients/web/client.js
Expand Up @@ -22,6 +22,7 @@ var facets = require('./facets/index');
function WebAPIClient(token, opts) {
var clientOpts = opts || {};
BaseAPIClient.call(this, token, clientOpts);
this.logger('debug', 'WebAPIClient initialized');
}

inherits(WebAPIClient, BaseAPIClient);
Expand Down