@drenso/homey-log 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/index.js +5 -0
- package/lib/Log.js +236 -0
- package/package.json +59 -0
- package/tsconfig.json +10 -0
- package/types/index.d.ts +2 -0
- package/types/lib/Log.d.ts +98 -0
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Homey Log
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/homey-log) [](https://github.com/athombv/node-homey-log/actions/workflows/lint.yml) [](https://github.com/athombv/node-homey-log/actions/workflows/deploy.yml) [](https://github.com/athombv/node-homey-log/actions/workflows/docs.yml)
|
|
4
|
+
|
|
5
|
+
This module can be used in a Homey App to send events to [Sentry](http://sentry.io/).
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
Documentation is available at [https://athombv.github.io/node-homey-log/](https://athombv.github.io/node-homey-log/).
|
|
10
|
+
|
|
11
|
+
## Related Modules
|
|
12
|
+
|
|
13
|
+
* [node-homey-zwavedriver](https://athombv.github.io/node-homey-zwavedriver) — Module for Z-Wave drivers
|
|
14
|
+
* [node-homey-zigbeedriver](https://athombv.github.io/node-homey-zigbeedriver) — Module for Zigbee drivers
|
|
15
|
+
* [node-homey-rfdriver](https://athombv.github.io/node-homey-rfdriver) — Module for RF (433 Mhz, 868 MHz, Infrared) drivers
|
|
16
|
+
* [node-homey-oauth2app](https://athombv.github.io/node-homey-oauth2app) — Module for OAuth2 apps
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install --save homey-log
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Getting started
|
|
25
|
+
|
|
26
|
+
In `env.json`, add the Sentry URL. If you would like to send the logs to Sentry *also* during development, set force log to `1`.
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"HOMEY_LOG_FORCE": "0",
|
|
31
|
+
"HOMEY_LOG_URL": "https://foo:bar@sentry.io/123456"
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
In `app.js`, include the library and create a new `Log` instance:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
const { Log } = require('homey-log');
|
|
39
|
+
|
|
40
|
+
class MyApp extends Homey.App {
|
|
41
|
+
onInit() {
|
|
42
|
+
this.homeyLog = new Log({ homey: this.homey });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Notes
|
|
48
|
+
|
|
49
|
+
* When your app crashes due to an `uncaughtException` or `unhandledRejection`, this will automatically be sent to Sentry.
|
|
50
|
+
* When running your app with `homey app run` events will not be sent to Sentry.
|
|
51
|
+
|
|
52
|
+
## Changelog
|
|
53
|
+
### 2.0.0
|
|
54
|
+
|
|
55
|
+
This version is only SDK version 3 compatible. It now requires a different way of setting up the `Log` instance, see _Getting Started_.
|
package/index.js
ADDED
package/lib/Log.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const HomeyModule = require('homey');
|
|
4
|
+
|
|
5
|
+
const Raven = require('raven');
|
|
6
|
+
|
|
7
|
+
const DEFAULT_OPTIONS = {
|
|
8
|
+
// Start tracking unhandled promise rejections (not enabled by default)
|
|
9
|
+
captureUnhandledRejections: true,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
class Log {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Construct a new Log instance.
|
|
16
|
+
* @param {object} args
|
|
17
|
+
* @param {HomeyModule} args.homey - `this.homey` instance in
|
|
18
|
+
* your app (e.g. `App#homey`/`Driver#homey`/`Device#homey`).
|
|
19
|
+
*
|
|
20
|
+
* @param {object} [args.options] - Additional options for Raven
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* class MyApp extends Homey.App {
|
|
24
|
+
* onInit() {
|
|
25
|
+
* this.homeyLog = new Log({ homey: this.homey });
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
constructor({ homey, options }) {
|
|
30
|
+
this._capturedMessages = [];
|
|
31
|
+
this._capturedExceptions = [];
|
|
32
|
+
|
|
33
|
+
if (typeof homey === 'undefined') {
|
|
34
|
+
return Log._error('Error: missing `homey` constructor parameter');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!HomeyModule.env) {
|
|
38
|
+
return Log._error('Error: could not access `HomeyModule.env`');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (typeof HomeyModule.env.HOMEY_LOG_URL !== 'string') {
|
|
42
|
+
return Log._error('Error: expected `HOMEY_LOG_URL` env variable, homey-log is disabled');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check if debug mode is enabled
|
|
46
|
+
const disableRaven = process.env.DEBUG === '1' && HomeyModule.env.HOMEY_LOG_FORCE !== '1';
|
|
47
|
+
if (disableRaven) {
|
|
48
|
+
Log._log('App is running in debug mode, disabling Raven');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this._manifest = HomeyModule.manifest;
|
|
52
|
+
this._homeyVersion = homey.version;
|
|
53
|
+
this._managerCloud = homey.cloud;
|
|
54
|
+
|
|
55
|
+
// Init Raven, pass falsy value if raven is not enabled to prevent sending events upstream
|
|
56
|
+
// in debug mode
|
|
57
|
+
this.init(!disableRaven && HomeyModule.env.HOMEY_LOG_URL, { ...DEFAULT_OPTIONS, ...options });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Init Raven, provide falsy value as `url` to prevent sending events upstream in debug mode.
|
|
62
|
+
* @param {string|boolean} url
|
|
63
|
+
* @param {object} opts
|
|
64
|
+
* @param {boolean} opts.captureUnhandledRejections - Track unhandled promise rejections not
|
|
65
|
+
* enabled by default)
|
|
66
|
+
* @returns {Log}
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
init(url, opts) {
|
|
70
|
+
Raven.config(url, opts).install();
|
|
71
|
+
|
|
72
|
+
this.setTags({
|
|
73
|
+
appId: this._manifest.id,
|
|
74
|
+
appVersion: this._manifest.version,
|
|
75
|
+
homeyVersion: this._homeyVersion,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Get homey cloud id and set as tag
|
|
79
|
+
this._managerCloud.getHomeyId()
|
|
80
|
+
.then(homeyId => this.setTags({ homeyId }))
|
|
81
|
+
.catch(err => Log._error('Error: could not get `homeyId`', err));
|
|
82
|
+
|
|
83
|
+
Log._log(`App ${this._manifest.id} v${this._manifest.version} logging on Homey v${this._homeyVersion}...`);
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Set `tags` that will be send as context with every message or error. See the raven-node
|
|
89
|
+
* documentation: https://docs.sentry.io/clients/node/usage/#raven-node-additional-context.
|
|
90
|
+
* @param {object} tags
|
|
91
|
+
* @returns {Log}
|
|
92
|
+
*/
|
|
93
|
+
setTags(tags) {
|
|
94
|
+
Log._mergeContext('tags', tags);
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Set `extra` that will be send as context with every message or error. See the raven-node
|
|
100
|
+
* documentation: https://docs.sentry.io/clients/node/usage/#raven-node-additional-context.
|
|
101
|
+
* @param {object} extra
|
|
102
|
+
* @returns {Log}
|
|
103
|
+
*/
|
|
104
|
+
setExtra(extra) {
|
|
105
|
+
Log._mergeContext('extra', extra);
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Set `user` that will be send as context with every message or error. See the raven-node
|
|
111
|
+
* documentation: https://docs.sentry.io/clients/node/usage/#raven-node-additional-context.
|
|
112
|
+
* @param {object} user
|
|
113
|
+
* @returns {Log}
|
|
114
|
+
*/
|
|
115
|
+
setUser(user) {
|
|
116
|
+
Log._mergeContext('user', user);
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Create and send message event to Sentry. See the raven-node documentation:
|
|
122
|
+
* https://docs.sentry.io/clients/node/usage/#capturing-messages
|
|
123
|
+
* @param {string} message - Message to be sent
|
|
124
|
+
* @returns {Promise<string>|undefined}
|
|
125
|
+
*/
|
|
126
|
+
async captureMessage(message) {
|
|
127
|
+
Log._log('captureMessage:', message);
|
|
128
|
+
|
|
129
|
+
if (this._capturedMessages.indexOf(message) > -1) {
|
|
130
|
+
Log._log('Prevented sending a duplicate message');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this._capturedMessages.push(message);
|
|
135
|
+
|
|
136
|
+
// eslint-disable-next-line consistent-return
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
Raven.captureMessage(
|
|
139
|
+
message,
|
|
140
|
+
(err, result) => {
|
|
141
|
+
if (err) return reject(err);
|
|
142
|
+
return resolve(result);
|
|
143
|
+
},
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Create and send exception event to Sentry. See the raven-node documentation:
|
|
150
|
+
* https://docs.sentry.io/clients/node/usage/#capturing-errors
|
|
151
|
+
* @param {Error} err - Error instance to be sent
|
|
152
|
+
* @returns {Promise<string>|undefined}
|
|
153
|
+
*/
|
|
154
|
+
async captureException(err) {
|
|
155
|
+
Log._log('captureException:', err);
|
|
156
|
+
|
|
157
|
+
if (this._capturedExceptions.indexOf(err) > -1) {
|
|
158
|
+
Log._log('Prevented sending a duplicate log');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this._capturedExceptions.push(err);
|
|
163
|
+
|
|
164
|
+
// eslint-disable-next-line consistent-return
|
|
165
|
+
return new Promise((resolve, reject) => {
|
|
166
|
+
Raven.captureException(
|
|
167
|
+
err,
|
|
168
|
+
(captureErr, result) => {
|
|
169
|
+
if (captureErr) return reject(captureErr);
|
|
170
|
+
return resolve(result);
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Mimic SDK log method.
|
|
178
|
+
* @private
|
|
179
|
+
*/
|
|
180
|
+
static _log() {
|
|
181
|
+
// eslint-disable-next-line prefer-spread,prefer-rest-params,no-console
|
|
182
|
+
console.log.bind(null, Log._logTime(), '[homey-log]').apply(null, arguments);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Mimic SDK error method.
|
|
187
|
+
* @private
|
|
188
|
+
*/
|
|
189
|
+
static _error() {
|
|
190
|
+
// eslint-disable-next-line prefer-spread,prefer-rest-params,no-console
|
|
191
|
+
console.error.bind(null, Log._logTime(), '[homey-log]').apply(null, arguments);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Mimic SDK timestamp.
|
|
196
|
+
* @returns {string}
|
|
197
|
+
* @private
|
|
198
|
+
*/
|
|
199
|
+
static _logTime() {
|
|
200
|
+
const date = new Date();
|
|
201
|
+
|
|
202
|
+
let mm = date.getMonth() + 1;
|
|
203
|
+
mm = (mm < 10 ? `0${mm}` : mm);
|
|
204
|
+
let dd = date.getDate();
|
|
205
|
+
dd = (dd < 10 ? `0${dd}` : dd);
|
|
206
|
+
let hh = date.getHours();
|
|
207
|
+
hh = (hh < 10 ? `0${hh}` : hh);
|
|
208
|
+
let min = date.getMinutes();
|
|
209
|
+
min = (min < 10 ? `0${min}` : min);
|
|
210
|
+
let sec = date.getSeconds();
|
|
211
|
+
sec = (sec < 10 ? `0${sec}` : sec);
|
|
212
|
+
|
|
213
|
+
return `${date.getFullYear()}-${mm}-${dd} ${hh}:${min}:${sec}`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Raven.mergeContext covers only 1-level of the context (tags, extra, user)
|
|
218
|
+
* We need to merge a 2-level of the context
|
|
219
|
+
* see https://github.com/getsentry/raven-node/issues/228
|
|
220
|
+
* @param {string} key
|
|
221
|
+
* @param {object} value
|
|
222
|
+
* @private
|
|
223
|
+
*/
|
|
224
|
+
static _mergeContext(key, value) {
|
|
225
|
+
const context = Raven.getContext();
|
|
226
|
+
if (!context[key]) {
|
|
227
|
+
context[key] = {};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
Object.assign(context[key], value);
|
|
231
|
+
Raven.setContext(context);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
module.exports = Log;
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@drenso/homey-log",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Interface with Sentry for Homey",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"lint": "eslint .",
|
|
9
|
+
"serve": "concurrently \"serve build/\" \"npm run jsdoc:watch\"",
|
|
10
|
+
"build": "npm run jsdoc:clean; npm run jsdoc;",
|
|
11
|
+
"jsdoc": "jsdoc --configure ./docs/jsdoc.json;",
|
|
12
|
+
"jsdoc:clean": "rm -rf ./build",
|
|
13
|
+
"jsdoc:watch": "watch \"npm run jsdoc:clean && npm run jsdoc\" lib docs \"node_modules/homey-jsdoc-template\"",
|
|
14
|
+
"typings:generate": "tsc"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/athombv/node-homey-log.git"
|
|
19
|
+
},
|
|
20
|
+
"author": "Athom B.V.",
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/athombv/node-homey-log/issues"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=12"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/athombv/node-homey-log#readme",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"raven": "github:athombv/raven-node"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/homey": "npm:homey-apps-sdk-v3-types@^0.3.0",
|
|
34
|
+
"@types/node": "^12.20.55",
|
|
35
|
+
"concurrently": "^5.1.0",
|
|
36
|
+
"eslint": "^7.2.0",
|
|
37
|
+
"eslint-config-athom": "^2.1.0",
|
|
38
|
+
"homey": "^2.4.0",
|
|
39
|
+
"homey-jsdoc-template": "github:athombv/homey-jsdoc-template#1.4",
|
|
40
|
+
"jsdoc": "^3.6.6",
|
|
41
|
+
"jsdoc-ts-utils": "^1.1.2",
|
|
42
|
+
"npm-watch": "^0.6.0",
|
|
43
|
+
"serve": "^11.3.1",
|
|
44
|
+
"typescript": "^4.7.4",
|
|
45
|
+
"watch": "^1.0.2"
|
|
46
|
+
},
|
|
47
|
+
"types": "types/index.d.ts",
|
|
48
|
+
"watch": {
|
|
49
|
+
"jsdoc": {
|
|
50
|
+
"patterns": [
|
|
51
|
+
"lib",
|
|
52
|
+
"README.md"
|
|
53
|
+
],
|
|
54
|
+
"extensions": [
|
|
55
|
+
"js"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/tsconfig.json
ADDED
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export = Log;
|
|
2
|
+
declare class Log {
|
|
3
|
+
/**
|
|
4
|
+
* Mimic SDK log method.
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
private static _log;
|
|
8
|
+
/**
|
|
9
|
+
* Mimic SDK error method.
|
|
10
|
+
* @private
|
|
11
|
+
*/
|
|
12
|
+
private static _error;
|
|
13
|
+
/**
|
|
14
|
+
* Mimic SDK timestamp.
|
|
15
|
+
* @returns {string}
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
private static _logTime;
|
|
19
|
+
/**
|
|
20
|
+
* Raven.mergeContext covers only 1-level of the context (tags, extra, user)
|
|
21
|
+
* We need to merge a 2-level of the context
|
|
22
|
+
* see https://github.com/getsentry/raven-node/issues/228
|
|
23
|
+
* @param {string} key
|
|
24
|
+
* @param {object} value
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
private static _mergeContext;
|
|
28
|
+
/**
|
|
29
|
+
* Construct a new Log instance.
|
|
30
|
+
* @param {object} args
|
|
31
|
+
* @param {HomeyModule} args.homey - `this.homey` instance in
|
|
32
|
+
* your app (e.g. `App#homey`/`Driver#homey`/`Device#homey`).
|
|
33
|
+
*
|
|
34
|
+
* @param {object} [args.options] - Additional options for Raven
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* class MyApp extends Homey.App {
|
|
38
|
+
* onInit() {
|
|
39
|
+
* this.homeyLog = new Log({ homey: this.homey });
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
constructor({ homey, options }: {
|
|
44
|
+
homey: typeof HomeyModule;
|
|
45
|
+
options?: object;
|
|
46
|
+
});
|
|
47
|
+
_capturedMessages: any[];
|
|
48
|
+
_capturedExceptions: any[];
|
|
49
|
+
_manifest: any;
|
|
50
|
+
_homeyVersion: string;
|
|
51
|
+
_managerCloud: any;
|
|
52
|
+
/**
|
|
53
|
+
* Init Raven, provide falsy value as `url` to prevent sending events upstream in debug mode.
|
|
54
|
+
* @param {string|boolean} url
|
|
55
|
+
* @param {object} opts
|
|
56
|
+
* @param {boolean} opts.captureUnhandledRejections - Track unhandled promise rejections not
|
|
57
|
+
* enabled by default)
|
|
58
|
+
* @returns {Log}
|
|
59
|
+
* @private
|
|
60
|
+
*/
|
|
61
|
+
private init;
|
|
62
|
+
/**
|
|
63
|
+
* Set `tags` that will be send as context with every message or error. See the raven-node
|
|
64
|
+
* documentation: https://docs.sentry.io/clients/node/usage/#raven-node-additional-context.
|
|
65
|
+
* @param {object} tags
|
|
66
|
+
* @returns {Log}
|
|
67
|
+
*/
|
|
68
|
+
setTags(tags: object): Log;
|
|
69
|
+
/**
|
|
70
|
+
* Set `extra` that will be send as context with every message or error. See the raven-node
|
|
71
|
+
* documentation: https://docs.sentry.io/clients/node/usage/#raven-node-additional-context.
|
|
72
|
+
* @param {object} extra
|
|
73
|
+
* @returns {Log}
|
|
74
|
+
*/
|
|
75
|
+
setExtra(extra: object): Log;
|
|
76
|
+
/**
|
|
77
|
+
* Set `user` that will be send as context with every message or error. See the raven-node
|
|
78
|
+
* documentation: https://docs.sentry.io/clients/node/usage/#raven-node-additional-context.
|
|
79
|
+
* @param {object} user
|
|
80
|
+
* @returns {Log}
|
|
81
|
+
*/
|
|
82
|
+
setUser(user: object): Log;
|
|
83
|
+
/**
|
|
84
|
+
* Create and send message event to Sentry. See the raven-node documentation:
|
|
85
|
+
* https://docs.sentry.io/clients/node/usage/#capturing-messages
|
|
86
|
+
* @param {string} message - Message to be sent
|
|
87
|
+
* @returns {Promise<string>|undefined}
|
|
88
|
+
*/
|
|
89
|
+
captureMessage(message: string): Promise<string> | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Create and send exception event to Sentry. See the raven-node documentation:
|
|
92
|
+
* https://docs.sentry.io/clients/node/usage/#capturing-errors
|
|
93
|
+
* @param {Error} err - Error instance to be sent
|
|
94
|
+
* @returns {Promise<string>|undefined}
|
|
95
|
+
*/
|
|
96
|
+
captureException(err: Error): Promise<string> | undefined;
|
|
97
|
+
}
|
|
98
|
+
import HomeyModule = require("homey");
|