Skip to content

Commit 232a5a1

Browse files
committed
Merge pull request #7 from alexk-blackops/master
Debugging mode + Env option minor fix
2 parents 84faffe + 383172b commit 232a5a1

File tree

9 files changed

+139
-27
lines changed

9 files changed

+139
-27
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ The following options could be passed. 'apiKey' is the only one that required:
2828
* __env:__ environment name
2929
* __exitOnError:__ boolean flag indicating whether to shutdown the server after logging an uncaught exception, defaults to false
3030
* __proxy:__ proxy server if you want to send requests via proxy.
31+
* __debug:__ boolean flag, turning on the debug mode. When set to true the log file (`stackify-debug.log`) is created in the working directory and all of the library actions is being written to it, defaults to false.
32+
3133

3234
*Notice:* stackify-logger sends synchronous requests if you call `process.exit()`. Sending via proxy wouldn't be possible in this case.
3335

index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var api = require('./lib/api'), // wrappers for API calls
2+
debug = require('./lib/debug'), // debug mode module
23
exception = require('./lib/exception'), // exception handler module
34
logger = require('./lib/logger'), // logging methods module
45
CONFIG = require('./config/config');
@@ -7,6 +8,7 @@ module.exports = {
78
// start sending logs
89
start: function (options) {
910
CONFIG.SELECTED_LOGGER = CONFIG.LOGGER_VERSION;
11+
debug.set(options.debug);
1012
api.methods.identifyApp(options);
1113
exception.catchException(options.exitOnError || false);
1214
exception.gracefulExitHandler();
@@ -18,13 +20,14 @@ module.exports = {
1820
info: logger.methods.info,
1921
warn: logger.methods.warn,
2022
error: logger.methods.error,
21-
23+
2224
//common method for handling logged messages
2325
push: logger.methods.push,
2426
// setting logger name to Winston logger if it's used
2527
setLoggerName: function (name) {
2628
if (name === 'Winston') {
2729
CONFIG.SELECTED_LOGGER = CONFIG.WINSTON_LOGGER_VERSION;
30+
debug.write('Winston Stackify Transport added');
2831
}
2932
},
3033

lib/api.js

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@ var os = require('os'),
55
CONFIG = require('../config/config'),
66
exc = require('./exception'),
77
helpers = require('./helpers'),
8+
debug = require('./debug'),
89

910
lastApiError;
1011

1112
module.exports.lastApiError = lastApiError;
1213
module.exports.methods = {
1314

1415
identifyApp: function identifyApp(settings) {
15-
var appname = helpers.getAppName(),
16+
var options = {},
17+
appname = helpers.getAppName(),
1618
body = {
1719
DeviceName: os.hostname(),
1820
AppName: appname,
1921
ConfiguredAppName: appname,
20-
AppLocaton: process.env.PWD,
21-
ConfiguredEnvName: settings ? settings.env : (process.env.NODE_ENV || null)
22+
AppLocaton: process.env.PWD
2223
},
23-
opt = helpers.getOptions(CONFIG.IDENTIFY_PATH, body, settings ? settings.proxy : undefined),
2424
callback = function (data) {
25-
console.log('successfully identified');
25+
debug.write('Successfully identified');
2626

2727
CONFIG.APP_DETAILS = data;
2828

@@ -34,24 +34,34 @@ module.exports.methods = {
3434

3535
},
3636
fail = function () {
37+
debug.write('Identification failed');
3738
setTimeout(function () {
38-
sender.send(opt, callback, fail);
39+
sender.send(options, callback, fail);
3940
}, CONFIG.IDENTIFY_DELAY);
4041
};
4142

4243
// check that settings object is correct
4344

4445
if (!settings) {
46+
debug.write('Settings are not provided');
4547
throw new TypeError('Settings are not provided');
4648
}
4749

4850
if (settings.apiKey && typeof (settings.apiKey) === 'string') {
4951
CONFIG.APIKEY = settings.apiKey;
50-
opt.headers['X-Stackify-Key'] = settings.apiKey;
5152
CONFIG.APPNAME = appname;
52-
CONFIG.ENV = settings.env || process.env.NODE_ENV || null;
53-
sender.send(opt, callback, fail);
53+
54+
if (settings.env) {
55+
body.ConfiguredEnvName = settings.env;
56+
}
57+
58+
options = helpers.getOptions(CONFIG.IDENTIFY_PATH, body, settings ? settings.proxy : undefined);
59+
options.headers['X-Stackify-Key'] = settings.apiKey;
60+
61+
debug.write('Identifying the app');
62+
sender.send(options, callback, fail);
5463
} else {
64+
debug.write('You have to pass API key to initialize Stackify Logger');
5565
throw new TypeError('You have to pass API key');
5666
}
5767

@@ -65,12 +75,12 @@ module.exports.methods = {
6575
*/
6676
postLogs: function postLogs(messages, cb, shutdown) {
6777
var delay = 0, // scheduled delay when postLogs call failed
68-
opt = helpers.getOptions(CONFIG.LOG_SAVE_PATH, helpers.getPostBody(messages), CONFIG.PROXY),
78+
options = helpers.getOptions(CONFIG.LOG_SAVE_PATH, helpers.getPostBody(messages), CONFIG.PROXY),
6979

7080
//retry the request if it failed
7181
fail = function (code) {
7282
var sinceFirstError;
73-
83+
debug.write('Sending logs failed');
7484
if (code === 401) {
7585
delay = CONFIG.DELAY.FIVE_MINUTES;
7686
lastApiError = new Date().getTime();
@@ -81,11 +91,11 @@ module.exports.methods = {
8191
}
8292

8393
setTimeout(function () {
84-
sender.send(opt, cb, fail);
94+
sender.send(options, cb, fail);
8595
}, delay);
8696
};
87-
88-
sender.send(opt, cb, shutdown ? null : fail);
97+
debug.write('Sending logs: batch size: ' + messages.length + ' messages');
98+
sender.send(options, cb, shutdown ? null : fail);
8999
},
90100
/*
91101
*** posting logs synchronously in case if server is about to close ***

lib/debug.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
var fs = require('fs'),
2+
path = require('path'),
3+
util = require('util'),
4+
log_path = path.join(process.cwd(), 'stackify-debug.log'),
5+
debug = false,
6+
stream = false,
7+
makeMsg = function (msg) {
8+
return new Date().toString() + ' ' + msg + '\n';
9+
},
10+
// create writable stream if debug mode is turned on
11+
init = function () {
12+
stream = fs.createWriteStream(log_path, {flags: 'a'});
13+
stream.write(makeMsg('Debugging started'));
14+
stream.on('error', function (err) {
15+
console.error('Error occured during writing to the log file ', util.inspect(err));
16+
});
17+
};
18+
19+
module.exports = {
20+
21+
set: function (option) {
22+
debug = (option === true) ? true : false;
23+
if (debug) {
24+
init();
25+
}
26+
},
27+
28+
write: function (msg) {
29+
if (debug) {
30+
stream.write(makeMsg(msg));
31+
}
32+
},
33+
34+
writeResponse: function (response, close) {
35+
var body = (typeof response.body === 'object') ? JSON.stringify(response.body, null, 4) : response.body,
36+
msg = 'url: ' + response.request.uri.href + ':' + response.request.uri.port + ', method: '
37+
+ response.req.method + ', status: ' + response.statusCode + '\nresponse: ' + body;
38+
if (close) {
39+
this.close('Response received\n' + msg);
40+
} else {
41+
this.write('Response received\n' + msg);
42+
}
43+
},
44+
45+
writeRequest: function (request, close) {
46+
if (request.body.Msgs) {
47+
request.body.Msgs = request.body.Msgs.length + ' messages';
48+
}
49+
if (close) {
50+
this.close('Request sent\n' + JSON.stringify(request, null, 4));
51+
} else {
52+
this.write('Request sent\n' + JSON.stringify(request, null, 4));
53+
}
54+
},
55+
56+
// special case - write synchronously to file if synchronous request before exit failed
57+
writeSync: function (msg) {
58+
try {
59+
fs.appendFileSync(log_path, msg);
60+
} catch (err) {
61+
console.error('Error occured during writing to the log file ', util.inspect(err));
62+
}
63+
},
64+
65+
close: function (msg) {
66+
var exit_msg = 'Exiting the app',
67+
message = msg || exit_msg;
68+
69+
if (stream) {
70+
stream.end(makeMsg(message) + (msg ? makeMsg(exit_msg) : ''));
71+
}
72+
}
73+
};

lib/error.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ module.exports = {
7272
AppName: CONFIG.APPNAME,
7373
AppLocation: process.env.PWD,
7474
ConfiguredAppName: CONFIG.APPNAME,
75-
ConfiguredEnvironmentName: CONFIG.ENV
75+
ConfiguredEnvironmentName: CONFIG.APP_DETAILS ? CONFIG.APP_DETAILS.ENV : null
7676
},
7777
OccurredEpochMillis: Date.now(),
7878
Error: {

lib/helpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ module.exports.getPostBody = function getPostBody(messages) {
142142
AppNameID: CONFIG.APP_DETAILS ? CONFIG.APP_DETAILS.AppNameID : null,
143143
AppEnvID: CONFIG.APP_DETAILS ? CONFIG.APP_DETAILS.AppEnvID : null,
144144
EnvID: CONFIG.APP_DETAILS ? CONFIG.APP_DETAILS.EnvID : null,
145-
Env: CONFIG.ENV,
145+
Env: CONFIG.APP_DETAILS ? CONFIG.APP_DETAILS.ENV : null,
146146
ServerName: os.hostname(),
147147
AppName: CONFIG.APPNAME,
148148
AppLoc: process.env.PWD,

lib/logger.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ var api = require('./api'),
22
CONFIG = require('../config/config'),
33
helpers = require('./helpers'),
44
error = require('./error'),
5+
debug = require('./debug'),
56

67
storage = [],
78

@@ -29,7 +30,7 @@ var api = require('./api'),
2930
send another batch (if there are enough messages in the queue)
3031
*/
3132
success = function (response) {
32-
if (response.success) {
33+
if (response && response.success) {
3334
storage = storage.slice(chunk); // remove this chunk from the queue
3435
length -= chunk;
3536
api.lastApiError = 0; // reset the last HTTP error
@@ -50,6 +51,7 @@ var api = require('./api'),
5051
}
5152
}
5253
};
54+
debug.write('Checking the queue: ' + data.length + ' messages');
5355
// re-count the delay
5456
if (length >= CONFIG.MSG.MAX_BATCH_SIZE) {
5557
delay = Math.max(Math.round(delay / 2.0), CONFIG.DELAY.ONE_SECOND_DELAY);
@@ -138,6 +140,8 @@ module.exports.methods = {
138140
}
139141
};
140142

143+
debug.write('Exception caught');
144+
141145
clearTimeout(timeout);
142146
this.push('error', err.message, [err], req, err);
143147
check();
@@ -146,6 +150,8 @@ module.exports.methods = {
146150
drain : function drain() {
147151
if (storage.length) {
148152
api.methods.postLogsSync(storage);
153+
} else {
154+
debug.close();
149155
}
150156
},
151157

@@ -156,10 +162,12 @@ module.exports.methods = {
156162

157163
// check the message level
158164
if (levels.indexOf(level.toLowerCase()) < 0) {
165+
debug.write(level + ' level doesn\'t exist');
159166
throw new TypeError(level + ' level doesn\'t exist');
160167
}
161168
// check the message itself
162169
if (typeof msg !== 'string') {
170+
debug.write('Message must be a string');
163171
throw new TypeError('Message must be a string');
164172
}
165173
this.push(level, msg, meta);

lib/sender.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@
55
Low level function for sending http/https requests
66
*/
77
var http = require('http'),
8+
util = require('util'),
89

910
request = require('request'),
1011
requestSync = require('sync-request'),
1112

13+
debug = require('./debug'),
14+
exc = require('./exception'),
1215
logger = require('./logger'),
1316
CONFIG = require('../config/config.js');
1417

1518
module.exports.send = function send(options, cb, fail) {
16-
1719
var callback = function (error, response, body) {
20+
debug.writeResponse(response, exc.excCaught);
1821
if (!error) {
1922
if (response.statusCode === 200) {
2023
if (cb) {
@@ -26,23 +29,25 @@ module.exports.send = function send(options, cb, fail) {
2629
}
2730
}
2831
} else {
29-
console.error(error.stack);
32+
debug.write('Request failed\n', util.inspect(error.stack));
3033
logger.methods.push('error', error.message, [{error: error}]);
3134
}
3235
};
36+
3337
request(options, callback);
38+
debug.writeRequest(options);
3439
};
3540

3641
module.exports.sendSync = function sendSync(options) {
37-
3842
try {
3943
var res = requestSync('POST', options.url, {
4044
json: options.data,
4145
headers: options.headers
4246
});
47+
options.data.Msgs = options.data.Msgs.length + ' messages';
48+
debug.close('Sending logs synchronously before exiting the app\n' + JSON.stringify(options, null, 4));
4349
} catch (err) {
44-
console.error(err.stack);
50+
debug.writeSync('Sending failed. Error stack: \n' + JSON.stringify(err.stack, null, 4));
4551
process.exit(1);
4652
}
47-
4853
};

package.json

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "stackify-logger",
3-
"version": "1.0.0",
3+
"version": "1.0.2",
44
"description": "Stackify logs and errors for Node.Js",
55
"main": "index.js",
66
"scripts": {
@@ -11,16 +11,27 @@
1111
"logger",
1212
"log"
1313
],
14-
"author": "Stackify",
14+
"author": {
15+
"name": "Stackify"
16+
},
1517
"license": "Apache-2.0",
1618
"repository": {
1719
"type": "git",
18-
"url": "https://github.com/stackify/stackify-log-nodejs.git"
20+
"url": "http://github.com/stackify/stackify-log-nodejs.git"
1921
},
2022
"homepage": "https://github.com/stackify/stackify-log-nodejs",
2123
"dependencies": {
2224
"request": "~2.48.x",
2325
"stack-trace": "0.0.9",
2426
"sync-request": "^1.0.1"
25-
}
27+
},
28+
"readme": "#Stackify Log API for Node.js\n\nErrors and Logs Overview:\n\nhttp://docs.stackify.com/m/7787/l/189767\n\nSign Up for a Trial:\n\nhttp://www.stackify.com/sign-up/\n\n## Installation\n```bash\n$ npm install stackify-logger\n```\n\n## Usage\n\n```js\nvar stackify = require(‘stackify-logger’);\n```\nStart sending logs:\n```js\n// this should be executed only once in the app\nstackify.start(options);\n```\nThe following options could be passed. 'apiKey' is the only one that required:\n* __apiKey:__ client license key\n* __env:__ environment name\n* __exitOnError:__ boolean flag indicating whether to shutdown the server after logging an uncaught exception, defaults to false\n* __proxy:__ proxy server if you want to send requests via proxy.\n\n*Notice:* stackify-logger sends synchronous requests if you call `process.exit()`. Sending via proxy wouldn't be possible in this case.\n\n#### Using direct logger\n\nIf you are not using Winston logger you can use default Stackify logger. It has 5 levels of messages: `trace`, `debug`, `info`, `warn` and `error`. To send the message to Stackify API you should run one of the following methods in any place of your code where you want to track some information:\n```js\nstackify.log(level, message [, meta])\nstackify.trace(message [, meta])\nstackify.debug(message [, meta])\nstackify.info(message [, meta])\nstackify.warn(message [, meta])\nstackify.error(message [, meta])\n```\n\n**Message** must be a string.\n\n**meta** - an additional parameter of any type.\n\nExamples of usage:\n```js\n// Add the module to all the script files where you want to log any messages.\nvar stackify = require('stackify-logger');\n\nstackify.log('info', 'hey!');\nstackify.debug('any message');\nstackify.info('any message', {anything: 'this is metadata'});\nstackify.warn('attention');\nstackify.log('error', {error : new Error()});\n```\nWhen logging an error message you can pass an Error object in metadata like in the last example, so the exception details would be available.\n\n#### Exception handling\nBy executing `stackify.start()` you set a handler for uncaught exceptions.\nMake sure you run it before any methods that set exception handlers.\n\n##### Using with Express\nGlobal handler doesn't work inside Express route methods.\nYou should use error-handling middleware function `stackify.expressExceptionHandler`. Since middleware is executed serially, it's order of inclusion is important. Make sure you add it before any other error-handling middleware.\n\n```js\nvar express = require('express');\nvar app = express();\n\n/* \n*** block of route handlers ***\n*** *** **** **** **** **** ***\n*/\n\napp.use(stackify.expressExceptionHandler);\n```\n\nTo handle exceptions correctly put this right after all route handlers.\n\n## Troubleshooting\nWhen request to Stackify fails for some reason, an error message is being printed to your `process.stderr` stream \n\n## License\n\nCopyright 2014 Stackify, LLC.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
29+
"readmeFilename": "README.md",
30+
"gitHead": "d0b7a4ade02acf6dc17d5c1e96d67a78edc9ed7f",
31+
"bugs": {
32+
"url": "https://github.com/stackify/stackify-log-nodejs/issues"
33+
},
34+
35+
"_shasum": "33730db585d53b43988b359145d76629e7ec35f1",
36+
"_from": "stackify-logger@"
2637
}

0 commit comments

Comments
 (0)