@webos-tools/cli 3.0.6 → 3.1.0
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/.eslintignore +1 -1
- package/.eslintrc.js +52 -52
- package/APIs.js +79 -79
- package/CHANGELOG.md +152 -138
- package/LICENSE +201 -201
- package/README.md +218 -218
- package/bin/ares-config.js +199 -199
- package/bin/ares-device-info.js +30 -30
- package/bin/ares-device.js +219 -219
- package/bin/ares-generate.js +274 -270
- package/bin/ares-inspect.js +179 -179
- package/bin/ares-install.js +223 -223
- package/bin/ares-launch.js +318 -318
- package/bin/ares-log.js +255 -255
- package/bin/ares-novacom.js +220 -223
- package/bin/ares-package.js +336 -336
- package/bin/ares-pull.js +156 -156
- package/bin/ares-push.js +155 -155
- package/bin/ares-server.js +174 -174
- package/bin/ares-setup-device.js +528 -520
- package/bin/ares-shell.js +132 -132
- package/bin/ares.js +166 -166
- package/files/conf/ares.json +49 -49
- package/files/conf/command-service.json +73 -73
- package/files/conf/config.json +31 -22
- package/files/conf/ipk.json +30 -30
- package/files/conf/novacom-devices.json +35 -35
- package/files/conf/query/query-app.json +14 -14
- package/files/conf/query/query-hosted.json +18 -18
- package/files/conf/query/query-package.json +10 -10
- package/files/conf/query/query-service.json +6 -6
- package/files/conf/sdk.json +8 -8
- package/files/conf/template.json +57 -57
- package/files/conf/webos_emul +27 -27
- package/files/conf-base/env/sdk-ose.json +8 -8
- package/files/conf-base/env/sdk-tv.json +8 -8
- package/files/conf-base/profile/config-ose.json +29 -21
- package/files/conf-base/profile/config-tv.json +31 -22
- package/files/conf-base/query/query-app.json +14 -14
- package/files/conf-base/query/query-hosted.json +18 -18
- package/files/conf-base/query/query-package.json +10 -10
- package/files/conf-base/query/query-service.json +6 -6
- package/files/conf-base/template-conf/ose-templates.json +67 -67
- package/files/conf-base/template-conf/tv-sdk-templates.json +57 -57
- package/files/help/ares-config.help +43 -43
- package/files/help/ares-device.help +94 -94
- package/files/help/ares-generate.help +65 -65
- package/files/help/ares-inspect.help +70 -70
- package/files/help/ares-install.help +90 -90
- package/files/help/ares-launch.help +100 -100
- package/files/help/ares-log-pmlogd.help +84 -84
- package/files/help/ares-log.help +101 -101
- package/files/help/ares-novacom.help +68 -68
- package/files/help/ares-package.help +101 -101
- package/files/help/ares-pull.help +38 -38
- package/files/help/ares-push.help +38 -38
- package/files/help/ares-server.help +39 -39
- package/files/help/ares-setup-device.help +116 -75
- package/files/help/ares-shell.help +42 -42
- package/files/help/ares.help +47 -47
- package/files/help/readme.help +23 -23
- package/files/schema/ApplicationDescription.schema +319 -319
- package/files/schema/NovacomDevices.schema +61 -61
- package/files/templates/ose-sdk-templates/appinfo/appinfo.json +10 -10
- package/files/templates/ose-sdk-templates/bootplate-web/index.html +88 -88
- package/files/templates/ose-sdk-templates/hosted-webapp/index.html +13 -13
- package/files/templates/ose-sdk-templates/icon/icon.png +0 -0
- package/files/templates/ose-sdk-templates/js-service/helloclient.js +31 -31
- package/files/templates/ose-sdk-templates/js-service/helloworld_webos_service.js +188 -188
- package/files/templates/ose-sdk-templates/qml-app/main.qml +68 -68
- package/files/templates/ose-sdk-templates/qmlappinfo/appinfo.json +10 -10
- package/files/templates/ose-sdk-templates/serviceinfo/package.json +11 -11
- package/files/templates/ose-sdk-templates/serviceinfo/services.json +8 -8
- package/files/templates/tv-sdk-templates/appinfo/appinfo.json +10 -10
- package/files/templates/tv-sdk-templates/bootplate-web/index.html +58 -58
- package/files/templates/tv-sdk-templates/bootplate-web/webOSTVjs-1.2.10/LICENSE-2.0.txt +202 -202
- package/files/templates/tv-sdk-templates/hosted-webapp/index.html +14 -14
- package/files/templates/tv-sdk-templates/js-service/helloworld_service.js +39 -39
- package/files/templates/tv-sdk-templates/packageinfo/packageinfo.json +3 -3
- package/files/templates/tv-sdk-templates/serviceinfo/package.json +11 -11
- package/files/templates/tv-sdk-templates/serviceinfo/services.json +8 -8
- package/files/templates/tv-sdk-templates/webicon/icon.png +0 -0
- package/files/templates/tv-sdk-templates/webicon/largeIcon.png +0 -0
- package/lib/base/ares.html +40 -40
- package/lib/base/cli-appdata.js +290 -290
- package/lib/base/cli-control.js +44 -44
- package/lib/base/common-tools.js +29 -29
- package/lib/base/error-handler.js +265 -265
- package/lib/base/file-watcher.js +155 -155
- package/lib/base/help-format.js +147 -147
- package/lib/base/luna.js +178 -178
- package/lib/base/novacom.js +1191 -1191
- package/lib/base/sdkenv.js +59 -59
- package/lib/base/server.js +137 -137
- package/lib/base/setup-device.js +335 -328
- package/lib/base/version-tools.js +79 -79
- package/lib/device.js +1419 -1419
- package/lib/generator.js +377 -377
- package/lib/inspect.js +494 -494
- package/lib/install.js +463 -463
- package/lib/launch.js +605 -605
- package/lib/log.js +584 -584
- package/lib/package.js +2147 -2129
- package/lib/pull.js +231 -231
- package/lib/pusher.js +210 -210
- package/lib/session.js +74 -74
- package/lib/shell.js +193 -193
- package/lib/tar-filter-pack.js +62 -62
- package/lib/util/copy.js +31 -31
- package/lib/util/createFileName.js +40 -40
- package/lib/util/eof.js +30 -30
- package/lib/util/json.js +63 -63
- package/lib/util/merge.js +14 -14
- package/lib/util/objclone.js +40 -40
- package/lib/util/spinner.js +37 -37
- package/npm-shrinkwrap.json +9242 -9116
- package/package.json +100 -100
- package/scripts/postinstall.js +24 -24
- package/spec/helpers/reporter.js +65 -65
- package/spec/jsSpecs/apiTest/generator.spec.js +372 -372
- package/spec/jsSpecs/apiTest/inspector.spec.js +89 -89
- package/spec/jsSpecs/apiTest/installer.spec.js +67 -67
- package/spec/jsSpecs/apiTest/launcher.spec.js +150 -150
- package/spec/jsSpecs/apiTest/packager.spec.js +194 -194
- package/spec/jsSpecs/apiTest/puller.spec.js +101 -101
- package/spec/jsSpecs/apiTest/pusher.spec.js +103 -103
- package/spec/jsSpecs/apiTest/server.spec.js +115 -115
- package/spec/jsSpecs/apiTest/setupDevice.spec.js +93 -93
- package/spec/jsSpecs/apiTest/shell.spec.js +49 -49
- package/spec/jsSpecs/ares-config.spec.js +78 -78
- package/spec/jsSpecs/ares-device.spec.js +443 -443
- package/spec/jsSpecs/ares-generate.spec.js +397 -397
- package/spec/jsSpecs/ares-inspect.spec.js +252 -252
- package/spec/jsSpecs/ares-install.spec.js +150 -150
- package/spec/jsSpecs/ares-launch.spec.js +301 -301
- package/spec/jsSpecs/ares-log.spec.js +824 -824
- package/spec/jsSpecs/ares-novacom.spec.js +149 -149
- package/spec/jsSpecs/ares-package.spec.js +1211 -1211
- package/spec/jsSpecs/ares-pull.spec.js +157 -157
- package/spec/jsSpecs/ares-push.spec.js +146 -146
- package/spec/jsSpecs/ares-server.spec.js +160 -160
- package/spec/jsSpecs/ares-setup-device.spec.js +300 -281
- package/spec/jsSpecs/ares-shell.spec.js +220 -220
- package/spec/jsSpecs/ares.spec.js +83 -83
- package/spec/jsSpecs/common-spec.js +169 -169
- package/spec/support/jasmine.json +22 -22
- package/spec/tempFiles/nativeApp/auto/pkg_arm64/GLES2 +0 -0
- package/spec/tempFiles/nativeApp/auto/pkg_arm64/appinfo.json +9 -9
- package/spec/tempFiles/nativeApp/ose/pkg_arm/Hello +0 -0
- package/spec/tempFiles/nativeApp/ose/pkg_arm/appinfo.json +8 -8
- package/spec/tempFiles/nativeApp/ose/pkg_arm/package.properties +2 -2
- package/spec/tempFiles/nativeApp/oseEmul/pkg_x86/Hello +0 -0
- package/spec/tempFiles/nativeApp/oseEmul/pkg_x86/appinfo.json +9 -9
- package/spec/tempFiles/nativeApp/rsi/pkg_x86/GLES2 +0 -0
- package/spec/tempFiles/nativeApp/rsi/pkg_x86/appinfo.json +9 -9
- package/spec/tempFiles/sign/sign.crt +32 -32
- package/spec/tempFiles/sign/signPriv.key +52 -52
- package/spec/test_data/ares-generate.json +41 -41
- package/spec/test_data/ares.json +33 -33
package/lib/device.js
CHANGED
|
@@ -1,1419 +1,1419 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020-2024 LG Electronics Inc.
|
|
3
|
-
*
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const async = require('async'),
|
|
8
|
-
chalk = require('chalk'),
|
|
9
|
-
createCsvWriter = require('csv-writer').createObjectCsvWriter,
|
|
10
|
-
fs = require('fs'),
|
|
11
|
-
npmlog = require('npmlog'),
|
|
12
|
-
path = require('path'),
|
|
13
|
-
streamBuffers = require('stream-buffers'),
|
|
14
|
-
Table = require('easy-table'),
|
|
15
|
-
util = require('util'),
|
|
16
|
-
pullLib = require('./pull'),
|
|
17
|
-
errHndl = require('./base/error-handler'),
|
|
18
|
-
luna = require('./base/luna'),
|
|
19
|
-
novacom = require('./base/novacom'),
|
|
20
|
-
createDateFileName = require('./util/createFileName').createDateFileName,
|
|
21
|
-
convertJsonToList = require('./util/json').convertJsonToList;
|
|
22
|
-
|
|
23
|
-
(function() {
|
|
24
|
-
const log = npmlog;
|
|
25
|
-
log.heading = 'device';
|
|
26
|
-
log.level = 'warn';
|
|
27
|
-
|
|
28
|
-
const device = {
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @property {Object} log an npm log instance
|
|
32
|
-
*/
|
|
33
|
-
log: log,
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Print system information of the given device
|
|
37
|
-
* @property options {String} device the device to connect to
|
|
38
|
-
*/
|
|
39
|
-
systemInfo: function(options, next) {
|
|
40
|
-
if (typeof next !== 'function') {
|
|
41
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
42
|
-
}
|
|
43
|
-
options = options || {};
|
|
44
|
-
async.series([
|
|
45
|
-
_makeSession,
|
|
46
|
-
_getOsInfo,
|
|
47
|
-
_getDeviceInfo,
|
|
48
|
-
_getChromiumVersion,
|
|
49
|
-
_getQtbaseVersion,
|
|
50
|
-
_getSoftwareInfo
|
|
51
|
-
], function(err, results) {
|
|
52
|
-
log.silly("device#systemInfo()", "err:", err, ", results:", results);
|
|
53
|
-
let resultTxt = "";
|
|
54
|
-
for (let i = 1; i < results.length; i++) {
|
|
55
|
-
resultTxt += results[i] + "\n";
|
|
56
|
-
}
|
|
57
|
-
next(err, {msg: resultTxt.trim()});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
function _makeSession(next) {
|
|
61
|
-
makeSession(options, next);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function _getOsInfo(next) {
|
|
65
|
-
log.info("device#systemInfo()#_getOsInfo()");
|
|
66
|
-
const target = options.session.getDevice(),
|
|
67
|
-
addr = target.lunaAddr.osInfo,
|
|
68
|
-
param = {
|
|
69
|
-
// luna param
|
|
70
|
-
parameters:["webos_build_id","webos_imagename","webos_name","webos_release",
|
|
71
|
-
"webos_manufacturing_version", "core_os_kernel_version"],
|
|
72
|
-
subscribe: false
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
luna.send(options, addr, param, function(lineObj, next) {
|
|
76
|
-
const resultValue = lineObj;
|
|
77
|
-
|
|
78
|
-
if (resultValue.returnValue) {
|
|
79
|
-
log.verbose("device#systemInfo()#_getOsInfo()", "success");
|
|
80
|
-
delete resultValue.returnValue; // remove unnecessary data
|
|
81
|
-
next(null, _makeReturnTxt(resultValue));
|
|
82
|
-
} else {
|
|
83
|
-
log.verbose("device#systemInfo()#_getOsInfo()", "failure");
|
|
84
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
85
|
-
}
|
|
86
|
-
}, next);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function _getDeviceInfo(next) {
|
|
90
|
-
log.info("device#systemInfo()#_getDeviceInfo()");
|
|
91
|
-
const target = options.session.getDevice(),
|
|
92
|
-
addr = target.lunaAddr.deviceInfo,
|
|
93
|
-
param = {
|
|
94
|
-
// luna param
|
|
95
|
-
subscribe: false
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
luna.send(options, addr, param, function(lineObj, next) {
|
|
99
|
-
const resultValue = lineObj,
|
|
100
|
-
returnObj ={};
|
|
101
|
-
|
|
102
|
-
if (resultValue.returnValue) {
|
|
103
|
-
log.verbose("device#systemInfo()#_getDeviceInfo()", "success");
|
|
104
|
-
returnObj.device_name = resultValue.device_name;
|
|
105
|
-
returnObj.device_id = resultValue.device_id;
|
|
106
|
-
next(null, _makeReturnTxt(returnObj));
|
|
107
|
-
} else {
|
|
108
|
-
log.verbose("device#systemInfo()#_getDeviceInfo()", "failure");
|
|
109
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
110
|
-
}
|
|
111
|
-
}, next);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function _getChromiumVersion(next) {
|
|
115
|
-
log.info("device#systemInfo()#_getChromiumInfo()");
|
|
116
|
-
|
|
117
|
-
// opkg is required permission as root.
|
|
118
|
-
if (options.session.getDevice().username !== 'root') {
|
|
119
|
-
return next(null, "chromium_version : " + "not supported");
|
|
120
|
-
} else {
|
|
121
|
-
const cmd = '/usr/bin/opkg list-installed webruntime*';
|
|
122
|
-
options.session.run(cmd, null, __data, null, function(err) {
|
|
123
|
-
if (err) {
|
|
124
|
-
return next(err);
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
function __data(data) {
|
|
129
|
-
const str = (Buffer.isBuffer(data)) ? data.toString() : data,
|
|
130
|
-
exp = /\d*\.\d*\.\d*\.\d*/,
|
|
131
|
-
version = str.match(exp);
|
|
132
|
-
|
|
133
|
-
next(null, "chromium_version : " + version);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function _getQtbaseVersion(next) {
|
|
138
|
-
log.info("device#systemInfo()#_getQtbaseInfo()");
|
|
139
|
-
|
|
140
|
-
// opkg is required permission as root.
|
|
141
|
-
if (options.session.getDevice().username !== 'root') {
|
|
142
|
-
return next(null, "qt_version : " + "not supported");
|
|
143
|
-
} else {
|
|
144
|
-
const cmd = '/usr/bin/opkg list-installed qtbase';
|
|
145
|
-
options.session.run(cmd, null, __data, null, function(err) {
|
|
146
|
-
if (err) {
|
|
147
|
-
return next(err);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
function __data(data) {
|
|
152
|
-
const str = (Buffer.isBuffer(data)) ? data.toString() : data,
|
|
153
|
-
exp = /\d*\.\d*\.\d*/,
|
|
154
|
-
version = str.match(exp);
|
|
155
|
-
next(null, "qt_version : " + version);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function _getSoftwareInfo(next) {
|
|
160
|
-
log.info("device#systemInfo#_getSoftwareInfo()");
|
|
161
|
-
const target = options.session.getDevice(),
|
|
162
|
-
addr = target.lunaAddr.softwareInfo,
|
|
163
|
-
param = {
|
|
164
|
-
parameters: ["nodejs_versions"]
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
luna.sendWithoutErrorHandle(options, addr, param, function(lineObj, next) {
|
|
168
|
-
log.silly("device#systemInfo#_getSoftwareInfo():", "lineObj:", lineObj);
|
|
169
|
-
|
|
170
|
-
const resultValue = lineObj,
|
|
171
|
-
returnObj ={};
|
|
172
|
-
|
|
173
|
-
if (resultValue.returnValue) {
|
|
174
|
-
log.verbose("device#systemInfo#_getSoftwareInfo():", "success");
|
|
175
|
-
returnObj.nodejs_versions = resultValue.nodejs_versions;
|
|
176
|
-
next(null, _makeReturnTxt(returnObj));
|
|
177
|
-
} else {
|
|
178
|
-
// handle if the target device does not support softwareInfo/query
|
|
179
|
-
return next(null, "nodejs_versions : " + "not supported");
|
|
180
|
-
}
|
|
181
|
-
}, next);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function _makeReturnTxt(resultValue) {
|
|
185
|
-
let returnTxt = "";
|
|
186
|
-
|
|
187
|
-
for (const key in resultValue) {
|
|
188
|
-
if (resultValue[key] === undefined) {
|
|
189
|
-
resultValue[key] = "(unknown)";
|
|
190
|
-
}
|
|
191
|
-
returnTxt += key + " : " + resultValue[key] + "\n";
|
|
192
|
-
}
|
|
193
|
-
return returnTxt.trim();
|
|
194
|
-
}
|
|
195
|
-
},
|
|
196
|
-
/**
|
|
197
|
-
* Print session information of the given device
|
|
198
|
-
* @property options {String} device the device to connect to
|
|
199
|
-
*/
|
|
200
|
-
sessionInfo: function(options, next) {
|
|
201
|
-
if (typeof next !== 'function') {
|
|
202
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
203
|
-
}
|
|
204
|
-
options = options || {};
|
|
205
|
-
async.series([
|
|
206
|
-
_makeSession,
|
|
207
|
-
_getSessionList
|
|
208
|
-
], function(err, results) {
|
|
209
|
-
log.silly("device#sessionInfo()", "err:", err, ", results:", results);
|
|
210
|
-
let resultTxt = "";
|
|
211
|
-
|
|
212
|
-
if (results[1] !== undefined) {
|
|
213
|
-
if (typeof results[1] === "object") {
|
|
214
|
-
if (results[1].length === 0) {
|
|
215
|
-
return next(errHndl.getErrMsg("SELECT_PROFILE"));
|
|
216
|
-
}
|
|
217
|
-
for (let i = 0; i < results[1].length; i++) {
|
|
218
|
-
resultTxt += convertJsonToList(results[1][i], 0) + '\n';
|
|
219
|
-
}
|
|
220
|
-
} else {
|
|
221
|
-
resultTxt = results[1];
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
next(err, {msg: resultTxt.trim()});
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
function _makeSession(next) {
|
|
228
|
-
makeSession(options, next);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function _getSessionList(next) {
|
|
232
|
-
log.info("device#sessionInfo#_getSessionList()");
|
|
233
|
-
const target = options.session.getDevice(),
|
|
234
|
-
addr = target.lunaAddr.getSessionList,
|
|
235
|
-
param = {
|
|
236
|
-
// luna param
|
|
237
|
-
subscribe: false
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
luna.send(options, addr, param, function(lineObj, next) {
|
|
241
|
-
if (lineObj.returnValue) {
|
|
242
|
-
log.verbose("device#sessionInfo()#_getSessionList()", "success");
|
|
243
|
-
next(null, lineObj.sessionList);
|
|
244
|
-
} else {
|
|
245
|
-
log.verbose("device#sessionInfo()#_getSessionList()", "failure");
|
|
246
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
247
|
-
}
|
|
248
|
-
}, next);
|
|
249
|
-
}
|
|
250
|
-
},
|
|
251
|
-
/**
|
|
252
|
-
* Print system information of the given device
|
|
253
|
-
* @property options {String} device the device to connect to
|
|
254
|
-
*/
|
|
255
|
-
tvSystemInfo: function(options, next) {
|
|
256
|
-
if (typeof next !== 'function') {
|
|
257
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
258
|
-
}
|
|
259
|
-
options = options || {};
|
|
260
|
-
async.series([
|
|
261
|
-
_makeSession,
|
|
262
|
-
_getSystemInfo,
|
|
263
|
-
], function(err, results) {
|
|
264
|
-
log.silly("device#tvSystemInfo()", "err:", err, ", results:", results);
|
|
265
|
-
next(err, {msg: results[1]});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
function _makeSession(next) {
|
|
269
|
-
makeSession(options, next);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function _getSystemInfo(next) {
|
|
273
|
-
log.info("device#tvSystemInfo#_getSystemInfo()");
|
|
274
|
-
const target = options.session.getDevice(),
|
|
275
|
-
addr = target.lunaAddr.deviceInfoSystem,
|
|
276
|
-
param = {
|
|
277
|
-
// luna param
|
|
278
|
-
keys: ["modelName", "sdkVersion", "firmwareVersion", "boardType", "otaId"],
|
|
279
|
-
subscribe: false
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
luna.sendWithoutErrorHandle(options, addr, param, function (lineObj, next) {
|
|
283
|
-
if (lineObj) {
|
|
284
|
-
log.verbose("deviceInfo#systemInfo#_getSystemInfo():", "success");
|
|
285
|
-
next(null, __makeReturnObj(lineObj, param.keys));
|
|
286
|
-
} else {
|
|
287
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
288
|
-
}
|
|
289
|
-
}, next);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function __makeReturnObj(resultValue, paramkey) {
|
|
293
|
-
let returnTxt = "";
|
|
294
|
-
|
|
295
|
-
for (const key in paramkey) {
|
|
296
|
-
if (Object.hasOwnProperty.call(resultValue, paramkey[key]))
|
|
297
|
-
returnTxt += paramkey[key] + " : " + resultValue[paramkey[key]] + "\n";
|
|
298
|
-
}
|
|
299
|
-
log.verbose("deviceInfo#systemInfo#__makeReturnObj():", returnTxt);
|
|
300
|
-
return returnTxt.trim();
|
|
301
|
-
}
|
|
302
|
-
},
|
|
303
|
-
/**
|
|
304
|
-
* Get all CPUs and memories usage of target device
|
|
305
|
-
* @property options {String} device, interval
|
|
306
|
-
*/
|
|
307
|
-
systemResource: function(options, next) {
|
|
308
|
-
if (typeof next !== 'function') {
|
|
309
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
310
|
-
}
|
|
311
|
-
const systemGroup = {};
|
|
312
|
-
systemGroup.initialExecution = true;
|
|
313
|
-
options = options || {};
|
|
314
|
-
options.destinationPath = "";
|
|
315
|
-
options.fileName = "";
|
|
316
|
-
options.csvPath = "";
|
|
317
|
-
async.series([
|
|
318
|
-
_createOutputPath,
|
|
319
|
-
_makeSession,
|
|
320
|
-
_getSystemResouceInfo
|
|
321
|
-
], function(err, results) {
|
|
322
|
-
log.silly("device#systemResource()", "err:", err, ", results:", results);
|
|
323
|
-
next(err);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
function _createOutputPath(next) {
|
|
327
|
-
if (options.save && options.csvPath === "") {
|
|
328
|
-
makeCSVOutputPath(options, next);
|
|
329
|
-
} else {
|
|
330
|
-
next();
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
function _makeSession(next) {
|
|
335
|
-
makeSession(options, next);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function _getSystemResouceInfo(next) {
|
|
339
|
-
log.info("device#systemResource()#_getSystemResouceInfo()");
|
|
340
|
-
|
|
341
|
-
let timerId;
|
|
342
|
-
if (!options.interval) {
|
|
343
|
-
// If interval option is not given, call timer logic 2 times
|
|
344
|
-
const defaultRepeat = 2;
|
|
345
|
-
let repeatCount = 0;
|
|
346
|
-
try {
|
|
347
|
-
timerId = setTimeout(function repeat() {
|
|
348
|
-
if (repeatCount < defaultRepeat) {
|
|
349
|
-
_callSystemResourceInfoCmd();
|
|
350
|
-
repeatCount++;
|
|
351
|
-
timerId = setTimeout(repeat, 1000);
|
|
352
|
-
} else {
|
|
353
|
-
clearTimeout(timerId);
|
|
354
|
-
return next();
|
|
355
|
-
}
|
|
356
|
-
}, 100);
|
|
357
|
-
} catch (err) {
|
|
358
|
-
log.silly("device#systemResource()#_getSystemResouceInfo()", "one timer. err:", err.toString());
|
|
359
|
-
clearTimeout(timerId);
|
|
360
|
-
// ignore timer logic error
|
|
361
|
-
return next();
|
|
362
|
-
}
|
|
363
|
-
} else {
|
|
364
|
-
try {
|
|
365
|
-
// when interval option is given, print initial data at first
|
|
366
|
-
const defaultRepeat = 1;
|
|
367
|
-
let repeatCount = 0;
|
|
368
|
-
timerId = setTimeout(function repeat() {
|
|
369
|
-
if (repeatCount < defaultRepeat) {
|
|
370
|
-
_callSystemResourceInfoCmd();
|
|
371
|
-
repeatCount++;
|
|
372
|
-
timerId = setTimeout(repeat, 1000);
|
|
373
|
-
} else {
|
|
374
|
-
_callSystemResourceInfoCmd();
|
|
375
|
-
timerId = setTimeout(repeat, options.interval * 1000);
|
|
376
|
-
}
|
|
377
|
-
}, 100);
|
|
378
|
-
} catch (err) {
|
|
379
|
-
log.silly("device#systemResource()#_getSystemResouceInfo()", "repeat timer. err:", err.toString());
|
|
380
|
-
clearTimeout(timerId);
|
|
381
|
-
// ignore timer logic error
|
|
382
|
-
return next();
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function _callSystemResourceInfoCmd() {
|
|
388
|
-
log.info("device#systemResource()#_callSystemResourceInfoCmd()");
|
|
389
|
-
|
|
390
|
-
const wStream = new streamBuffers.WritableStreamBuffer();
|
|
391
|
-
const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep -c ^processor /proc/cpuinfo; grep "cpu *" /proc/stat; free -k';
|
|
392
|
-
try {
|
|
393
|
-
options.session.run(cmd, null, wStream, null, function(err) {
|
|
394
|
-
if (err) {
|
|
395
|
-
// do not print error message to user
|
|
396
|
-
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
397
|
-
log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "ssh call. err:"+ err.toString());
|
|
398
|
-
return next();
|
|
399
|
-
} else {
|
|
400
|
-
const result = wStream.getContentsAsString();
|
|
401
|
-
_setSystemResouceInfo(result);
|
|
402
|
-
systemGroup.initialExecution = false;
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
} catch (err) {
|
|
406
|
-
// do not print error message to user
|
|
407
|
-
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
408
|
-
log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "in try-catch. err:", err.toString());
|
|
409
|
-
return next();
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function _setSystemResouceInfo(systemData) {
|
|
414
|
-
log.info("device#systemResource()#_callSystemResourceInfoCmd()");
|
|
415
|
-
|
|
416
|
-
const CPU_PATTERN = /\s+/,
|
|
417
|
-
cpuinfo = {},
|
|
418
|
-
meminfo = {};
|
|
419
|
-
let sysinfo = {};
|
|
420
|
-
try {
|
|
421
|
-
const allvalues = systemData.split("\n"),
|
|
422
|
-
date = allvalues[0], // Setup date
|
|
423
|
-
pcore = +allvalues[1] * 100;
|
|
424
|
-
let index,
|
|
425
|
-
columns,
|
|
426
|
-
isBuff_Cached = false; // This is to check the format version of kernel to find system memory parameter
|
|
427
|
-
for (index = 2; index < (allvalues.length - 1); index++) {
|
|
428
|
-
columns = allvalues[index].split(CPU_PATTERN);
|
|
429
|
-
// setup CPU information
|
|
430
|
-
if (columns[0].indexOf("cpu") === 0) {
|
|
431
|
-
const prevTotal = "prev" + columns[0] + "Total",
|
|
432
|
-
prevIdle = "prev" + columns[0] + "Idle",
|
|
433
|
-
prevUser = "prev" + columns[0] + "User",
|
|
434
|
-
prevkernel = "prev" + columns[0] + "Kernel",
|
|
435
|
-
prevOther = "prev" + columns[0] + "Other";
|
|
436
|
-
if (!systemGroup[prevTotal]) {
|
|
437
|
-
systemGroup[prevTotal] = 0;
|
|
438
|
-
systemGroup[prevIdle] = 0;
|
|
439
|
-
systemGroup[prevUser] = 0;
|
|
440
|
-
systemGroup[prevkernel] = 0;
|
|
441
|
-
systemGroup[prevOther] = 0;
|
|
442
|
-
}
|
|
443
|
-
const user = parseInt(columns[1]),
|
|
444
|
-
nice = parseInt(columns[2]),
|
|
445
|
-
kernel = parseInt(columns[3]),
|
|
446
|
-
idle = parseInt(columns[4]),
|
|
447
|
-
other = nice + parseInt(columns[5]) + parseInt(columns[6]) + parseInt(columns[7]) + parseInt(columns[8]) +
|
|
448
|
-
parseInt(columns[9]) + parseInt(columns[10]),
|
|
449
|
-
subTotal = user + nice + kernel + idle + other;
|
|
450
|
-
|
|
451
|
-
if (!systemGroup.initialExecution) {
|
|
452
|
-
const diffIdle = idle - systemGroup[prevIdle],
|
|
453
|
-
diffUser = user - systemGroup[prevUser],
|
|
454
|
-
diffKernel = kernel - systemGroup[prevkernel],
|
|
455
|
-
diffOther = other - systemGroup[prevOther],
|
|
456
|
-
diffTotal = subTotal - systemGroup[prevTotal];
|
|
457
|
-
|
|
458
|
-
let userModeCpuOccupation = (diffUser/diffTotal) * 100,
|
|
459
|
-
kernelModeCpuOccupation = (diffKernel/diffTotal) * 100,
|
|
460
|
-
otherModeCpuOccupation = (diffOther/diffTotal) * 100,
|
|
461
|
-
overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
|
|
462
|
-
|
|
463
|
-
userModeCpuOccupation < 0 ? (userModeCpuOccupation = 0) : userModeCpuOccupation;
|
|
464
|
-
userModeCpuOccupation > pcore ? (userModeCpuOccupation = pcore) : userModeCpuOccupation;
|
|
465
|
-
kernelModeCpuOccupation < 0 ? (kernelModeCpuOccupation = 0) : kernelModeCpuOccupation;
|
|
466
|
-
kernelModeCpuOccupation > pcore ? (kernelModeCpuOccupation = pcore) : kernelModeCpuOccupation;
|
|
467
|
-
otherModeCpuOccupation < 0 ? (otherModeCpuOccupation = 0) : otherModeCpuOccupation;
|
|
468
|
-
otherModeCpuOccupation > pcore ? (otherModeCpuOccupation = pcore) : otherModeCpuOccupation;
|
|
469
|
-
overallCpuOccupation < 0 ? (overallCpuOccupation = 0) : overallCpuOccupation;
|
|
470
|
-
overallCpuOccupation > pcore ? (overallCpuOccupation = pcore) : overallCpuOccupation;
|
|
471
|
-
|
|
472
|
-
cpuinfo[columns[0]] = {
|
|
473
|
-
"overall": +overallCpuOccupation.toFixed(2),
|
|
474
|
-
"usermode": +userModeCpuOccupation.toFixed(2),
|
|
475
|
-
"kernelmode": +kernelModeCpuOccupation.toFixed(2),
|
|
476
|
-
"others": +otherModeCpuOccupation.toFixed(2)
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
systemGroup[prevIdle] = idle;
|
|
480
|
-
systemGroup[prevUser] = user;
|
|
481
|
-
systemGroup[prevkernel] = kernel;
|
|
482
|
-
systemGroup[prevOther] = other;
|
|
483
|
-
systemGroup[prevTotal] = subTotal;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
if (!systemGroup.initialExecution) {
|
|
487
|
-
// setup memory infomation
|
|
488
|
-
if (columns[5] && columns[5].indexOf('buff/cache') !== -1) {
|
|
489
|
-
isBuff_Cached = true;
|
|
490
|
-
}
|
|
491
|
-
if (columns[0].indexOf('Mem:') === 0) {
|
|
492
|
-
meminfo['memory'] = !isBuff_Cached ? {
|
|
493
|
-
"total": +columns[1],
|
|
494
|
-
"used": +columns[2],
|
|
495
|
-
"free": +columns[3],
|
|
496
|
-
"shared": +columns[4],
|
|
497
|
-
"buffers": +columns[5],
|
|
498
|
-
"cached": +columns[6]
|
|
499
|
-
} : {
|
|
500
|
-
"total": +columns[1],
|
|
501
|
-
"used": +columns[2],
|
|
502
|
-
"free": +columns[3],
|
|
503
|
-
"shared": +columns[4],
|
|
504
|
-
"buff_cache": +columns[5],
|
|
505
|
-
"available": +columns[6]
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
if (columns[0].indexOf('-/+') === 0) {
|
|
509
|
-
meminfo['buffers'] = {
|
|
510
|
-
"used": +columns[2],
|
|
511
|
-
"free": +columns[3]
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
if (columns[0].indexOf('Swap:') === 0) {
|
|
515
|
-
meminfo['swap'] = {
|
|
516
|
-
"total": +columns[1],
|
|
517
|
-
"used": +columns[2],
|
|
518
|
-
"free": +columns[3]
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
if (!systemGroup.initialExecution) {
|
|
524
|
-
sysinfo = {
|
|
525
|
-
"date": date,
|
|
526
|
-
"cpuinfo": cpuinfo,
|
|
527
|
-
"meminfo": meminfo
|
|
528
|
-
};
|
|
529
|
-
_printSystemInfo(sysinfo);
|
|
530
|
-
}
|
|
531
|
-
} catch (err) {
|
|
532
|
-
// do not print error message to user
|
|
533
|
-
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
534
|
-
log.silly("device#systemResource()#_setSystemResouceInfo()", "in try-catch. err:", err.toString());
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
function _printSystemInfo(sysinfo) {
|
|
540
|
-
const cpuinfo = sysinfo.cpuinfo,
|
|
541
|
-
meminfo = sysinfo.meminfo,
|
|
542
|
-
cpuinfoTable = new Table(),
|
|
543
|
-
meminfoTable = new Table(),
|
|
544
|
-
dataForCSV = [];
|
|
545
|
-
|
|
546
|
-
// add CPU info to the table
|
|
547
|
-
for (const key in cpuinfo) {
|
|
548
|
-
cpuinfoTable.cell('(%)', key);
|
|
549
|
-
cpuinfoTable.cell('overall', cpuinfo[key].overall);
|
|
550
|
-
cpuinfoTable.cell('usermode', cpuinfo[key].usermode);
|
|
551
|
-
cpuinfoTable.cell('kernelmode', cpuinfo[key].kernelmode);
|
|
552
|
-
cpuinfoTable.cell('others', cpuinfo[key].others);
|
|
553
|
-
cpuinfoTable.newRow();
|
|
554
|
-
|
|
555
|
-
// Add csv array
|
|
556
|
-
const obj = {
|
|
557
|
-
time: sysinfo.date,
|
|
558
|
-
cpu: key,
|
|
559
|
-
overall: cpuinfo[key].overall,
|
|
560
|
-
usermode: cpuinfo[key].usermode,
|
|
561
|
-
kernelmode: cpuinfo[key].kernelmode,
|
|
562
|
-
others: cpuinfo[key].others
|
|
563
|
-
};
|
|
564
|
-
dataForCSV.push(obj);
|
|
565
|
-
}
|
|
566
|
-
// add memoryInfo to the table
|
|
567
|
-
for (const key in meminfo) {
|
|
568
|
-
meminfoTable.cell('(KB)', key);
|
|
569
|
-
meminfoTable.cell('total', meminfo[key].total);
|
|
570
|
-
meminfoTable.cell('used', meminfo[key].used);
|
|
571
|
-
meminfoTable.cell('free', meminfo[key].free);
|
|
572
|
-
meminfoTable.cell('shared', meminfo[key].shared);
|
|
573
|
-
meminfoTable.cell('buff/cache', meminfo[key].buff_cache);
|
|
574
|
-
meminfoTable.cell('available', meminfo[key].available);
|
|
575
|
-
meminfoTable.newRow();
|
|
576
|
-
|
|
577
|
-
const obj = {
|
|
578
|
-
time: sysinfo.date,
|
|
579
|
-
memory: key,
|
|
580
|
-
total: meminfo[key].total,
|
|
581
|
-
used: meminfo[key].used,
|
|
582
|
-
free: meminfo[key].free,
|
|
583
|
-
shared: meminfo[key].shared,
|
|
584
|
-
"buff/cache": meminfo[key].buff_cache,
|
|
585
|
-
available: meminfo[key].available
|
|
586
|
-
};
|
|
587
|
-
dataForCSV.push(obj);
|
|
588
|
-
}
|
|
589
|
-
// write CSV file if user gives --save option
|
|
590
|
-
if (options.save && options.csvPath) {
|
|
591
|
-
// write csv file
|
|
592
|
-
// when openMode is false, the new csv file will be created and "Header" add to the file
|
|
593
|
-
let openMode = false;
|
|
594
|
-
if (fs.existsSync(options.csvPath)) {
|
|
595
|
-
openMode = true;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const csvWriter = createCsvWriter({
|
|
599
|
-
path: options.csvPath,
|
|
600
|
-
header: [
|
|
601
|
-
{id: 'time', title: 'time'},
|
|
602
|
-
{id: 'cpu', title: '(%)'},
|
|
603
|
-
{id: 'overall', title: 'overall'},
|
|
604
|
-
{id: 'usermode', title: 'usermode'},
|
|
605
|
-
{id: 'kernelmode', title: 'kernelmode'},
|
|
606
|
-
{id: 'others', title: 'others'},
|
|
607
|
-
{id: 'memory', title: '(KB)'},
|
|
608
|
-
{id: 'total', title: 'total'},
|
|
609
|
-
{id: 'used', title: 'used'},
|
|
610
|
-
{id: 'free', title: 'free'},
|
|
611
|
-
{id: 'shared', title: 'shared'},
|
|
612
|
-
{id: 'buff/cache', title: 'buff/cache'},
|
|
613
|
-
{id: 'available', title: 'available'}
|
|
614
|
-
],
|
|
615
|
-
append: openMode
|
|
616
|
-
});
|
|
617
|
-
|
|
618
|
-
csvWriter
|
|
619
|
-
.writeRecords(dataForCSV)
|
|
620
|
-
.then(function() {
|
|
621
|
-
log.silly("device#systemResource()#_printSystemInfo()", "CSV file updated");
|
|
622
|
-
// csv file has been created at first
|
|
623
|
-
if (openMode === false) {
|
|
624
|
-
const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
|
|
625
|
-
console.log(resultTxt);
|
|
626
|
-
}
|
|
627
|
-
__printTable();
|
|
628
|
-
}).catch(function(err) {
|
|
629
|
-
return setImmediate(next, errHndl.getErrMsg(err));
|
|
630
|
-
});
|
|
631
|
-
} else {
|
|
632
|
-
__printTable();
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
function __printTable() {
|
|
636
|
-
console.log(sysinfo.date + "\n");
|
|
637
|
-
console.log(cpuinfoTable.toString());
|
|
638
|
-
console.log(meminfoTable.toString());
|
|
639
|
-
console.log("=================================================================");
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
},
|
|
643
|
-
/**
|
|
644
|
-
* Get running apps and services CPUs and memories usage
|
|
645
|
-
* @property options {String} device, interval
|
|
646
|
-
*/
|
|
647
|
-
processResource: function(options, next) {
|
|
648
|
-
if (typeof next !== 'function') {
|
|
649
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
const processGroup = {};
|
|
653
|
-
processGroup.initialExecution = true;
|
|
654
|
-
options = options || {};
|
|
655
|
-
options.destinationPath = "";
|
|
656
|
-
options.fileName = "";
|
|
657
|
-
options.csvPath = "";
|
|
658
|
-
|
|
659
|
-
async.series([
|
|
660
|
-
_createOutputPath,
|
|
661
|
-
_makeSession,
|
|
662
|
-
_getProcessResouceInfo
|
|
663
|
-
], function(err, results) {
|
|
664
|
-
log.silly("device#processResource()", "err:", err, ", results:", results);
|
|
665
|
-
next(err);
|
|
666
|
-
});
|
|
667
|
-
|
|
668
|
-
function _createOutputPath(next) {
|
|
669
|
-
if (options.save && options.csvPath === "") {
|
|
670
|
-
makeCSVOutputPath(options, next);
|
|
671
|
-
} else {
|
|
672
|
-
next();
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
function _makeSession(next) {
|
|
677
|
-
makeSession(options, next);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
function _getProcessResouceInfo(next) {
|
|
681
|
-
log.info("device#processResource()#_getProcessResouceInfo()");
|
|
682
|
-
|
|
683
|
-
let timerId;
|
|
684
|
-
if (!options.interval) {
|
|
685
|
-
// If interval option is not given, call timer logic 2 times
|
|
686
|
-
const defaultRepeat = 2;
|
|
687
|
-
let repeatCount = 0;
|
|
688
|
-
try {
|
|
689
|
-
timerId = setTimeout(function repeat() {
|
|
690
|
-
if (repeatCount < defaultRepeat) {
|
|
691
|
-
_callProcessInfoCmd();
|
|
692
|
-
repeatCount++;
|
|
693
|
-
timerId = setTimeout(repeat, 1000);
|
|
694
|
-
} else {
|
|
695
|
-
clearTimeout(timerId);
|
|
696
|
-
return next();
|
|
697
|
-
}
|
|
698
|
-
}, 100);
|
|
699
|
-
} catch (err) {
|
|
700
|
-
log.silly("device#systemResource()#_getProcessResouceInfo()", "one timer. err:", err.toString());
|
|
701
|
-
clearTimeout(timerId);
|
|
702
|
-
// ignore timer logic error
|
|
703
|
-
return next();
|
|
704
|
-
}
|
|
705
|
-
} else {
|
|
706
|
-
try {
|
|
707
|
-
// when interval option is given, print initial data at first
|
|
708
|
-
const defaultRepeat = 1;
|
|
709
|
-
let repeatCount = 0;
|
|
710
|
-
timerId = setTimeout(function repeat() {
|
|
711
|
-
if (repeatCount < defaultRepeat) {
|
|
712
|
-
_callProcessInfoCmd();
|
|
713
|
-
repeatCount++;
|
|
714
|
-
timerId = setTimeout(repeat, 1000);
|
|
715
|
-
} else {
|
|
716
|
-
_callProcessInfoCmd();
|
|
717
|
-
timerId = setTimeout(repeat, options.interval * 1000);
|
|
718
|
-
}
|
|
719
|
-
}, 100);
|
|
720
|
-
} catch (err) {
|
|
721
|
-
log.silly("device#systemResource()#_getProcessResouceInfo()", "repeat timer. err:", err.toString());
|
|
722
|
-
clearTimeout(timerId);
|
|
723
|
-
// ignore timer logic error
|
|
724
|
-
return next();
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
function _callProcessInfoCmd() {
|
|
730
|
-
log.info("device#processResource()#_callProcessInfoCmd()");
|
|
731
|
-
|
|
732
|
-
const wStream = new streamBuffers.WritableStreamBuffer();
|
|
733
|
-
const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep "cpu *" /proc/stat | sed "1d" | awk \'{for (i=0;i<NR;i++){if (i==NR-1){totalSum+=$2+$3+$4+$5+$6+$7+$8+$9+$10+$11;idleSum+=$5}}} END { for (i=0;i<NR;i++){if (i==NR-1){print idleSum;print totalSum}}}\'; cat /proc/[0-9]*/stat; echo \'psList\' ; ps -ax | sed "1d" | awk \'/ /{print $1 "\t"$5}\'; echo \'serviceStringStart\'; ls /media/developer/apps/usr/palm/services ; echo \'serviceStringEnd\'; luna-send-pub -n 1 -f luna://com.webos.applicationManager/dev/running \'{}\'; grep -c ^processor /proc/cpuinfo';
|
|
734
|
-
try {
|
|
735
|
-
options.session.run(cmd, null, wStream, null, function(err) {
|
|
736
|
-
if (err) {
|
|
737
|
-
// do not print error message to user
|
|
738
|
-
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
739
|
-
log.silly("device#processResource()#_callProcessInfoCmd()", "ssh call. err:", err.toString());
|
|
740
|
-
return next(null);
|
|
741
|
-
} else {
|
|
742
|
-
const result = wStream.getContentsAsString();
|
|
743
|
-
_setProcessInfo(result);
|
|
744
|
-
processGroup.initialExecution = false;
|
|
745
|
-
}
|
|
746
|
-
});
|
|
747
|
-
} catch (err) {
|
|
748
|
-
// do not print error message to user
|
|
749
|
-
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
750
|
-
log.silly("device#processResource()#_callProcessInfoCmd()", "in try-catch. err:", err.toString());
|
|
751
|
-
return next(null);
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
function _setProcessInfo(processData) {
|
|
756
|
-
log.info("device#processResource()#_setProcessInfo()");
|
|
757
|
-
const PROC_GROUP_INFO_PATTERN = /\s+/;
|
|
758
|
-
try {
|
|
759
|
-
// Intialize temporary groups with values
|
|
760
|
-
const processList = ["Service", "System"],
|
|
761
|
-
groupProcessList = [],
|
|
762
|
-
tempProcGrps = {},
|
|
763
|
-
arrActiveServices = [];
|
|
764
|
-
// loop through all the categories and create groups
|
|
765
|
-
for (let i = 0; i < processList.length; i++) {
|
|
766
|
-
tempProcGrps[processList[i]] = {};
|
|
767
|
-
tempProcGrps[processList[i]]["pid"] = 0;
|
|
768
|
-
tempProcGrps[processList[i]]["cputime"] = 0;
|
|
769
|
-
tempProcGrps[processList[i]]["RSS"] = 0;
|
|
770
|
-
tempProcGrps[processList[i]]["pmem"] = 0;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
const processinfo = [],
|
|
774
|
-
groupProcessinfo = [], // only for dev app & service info
|
|
775
|
-
allvalues = processData.split("\n"),
|
|
776
|
-
otherList = [],
|
|
777
|
-
date = allvalues[0],
|
|
778
|
-
lastIndex = allvalues.length;
|
|
779
|
-
|
|
780
|
-
allvalues.splice(lastIndex - 1, 1);
|
|
781
|
-
const pcore = +allvalues[allvalues.length-1] * 100;
|
|
782
|
-
/* memCol[1] from 'grep "MemTotal *" /proc/meminfo' is not used */
|
|
783
|
-
let totalRAM = 0;
|
|
784
|
-
const idleCPUtime = +allvalues[1],
|
|
785
|
-
totalCPUtime = +allvalues[2],
|
|
786
|
-
psListStartIndex = allvalues.indexOf("psList", 2),
|
|
787
|
-
serviceStartIndex = allvalues.indexOf("serviceStringStart", 2), // from where to start (2)
|
|
788
|
-
serviceEndIndex = allvalues.indexOf("serviceStringEnd", 2); // from where to start (2)
|
|
789
|
-
|
|
790
|
-
const arryInstalledServices = [];
|
|
791
|
-
for (let i = serviceStartIndex + 1; i < serviceEndIndex; i++) {
|
|
792
|
-
arryInstalledServices[i-serviceStartIndex-1] = allvalues[i];
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
// get processid of external service on ps list
|
|
796
|
-
let arrayCount = 0;
|
|
797
|
-
for (let k = psListStartIndex+1 ; k < serviceStartIndex ;k++) {
|
|
798
|
-
const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
|
|
799
|
-
pid = parseInt(columns[0]),
|
|
800
|
-
procname = columns[1].trim();
|
|
801
|
-
|
|
802
|
-
if (arryInstalledServices.indexOf(procname) !== -1) {
|
|
803
|
-
const ObjService = {
|
|
804
|
-
"processid": pid,
|
|
805
|
-
"id": procname
|
|
806
|
-
};
|
|
807
|
-
arrActiveServices[arrayCount++] = ObjService;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
const appStartIndex = allvalues.indexOf("{", 2); // From where to start (2)
|
|
812
|
-
// some times specific platform does not gives list of running info itself then appStartIndex becomes -1
|
|
813
|
-
if (appStartIndex < 0) {
|
|
814
|
-
// do not print error message to user
|
|
815
|
-
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
816
|
-
log.silly("device#processResource()#_setProcessInfo()", "running app list is invalid");
|
|
817
|
-
return;
|
|
818
|
-
}
|
|
819
|
-
const appEndIndex = allvalues.length-1;
|
|
820
|
-
let strActiveApps = "",
|
|
821
|
-
objActiveApps;
|
|
822
|
-
for (let i = appStartIndex; i < appEndIndex; i++) {
|
|
823
|
-
strActiveApps += allvalues[i];
|
|
824
|
-
}
|
|
825
|
-
try {
|
|
826
|
-
objActiveApps = JSON.parse(strActiveApps);
|
|
827
|
-
} catch (err) {
|
|
828
|
-
// do not print error message to user
|
|
829
|
-
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
830
|
-
log.silly("device#processResource()#_setProcessInfo()", "active app parsing. err:", err.toString());
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
if (objActiveApps.returnValue === false) {
|
|
835
|
-
const errValue = objActiveApps["errorText"] || "running app list is invalid";
|
|
836
|
-
return next(errHndl.getErrMsg("FAILED_CALL_LUNA", errValue, null, "com.webos.applicationManager"));
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
const arrActiveApps = objActiveApps["running"],
|
|
840
|
-
groupObjList = {};
|
|
841
|
-
|
|
842
|
-
// 1st row is date, 2nd row is total CPU time and last row is total RAM(Meminfo) hence ignore it
|
|
843
|
-
// check process group info until "psList" string
|
|
844
|
-
for (let k = 3; k < psListStartIndex; k++) {
|
|
845
|
-
const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
|
|
846
|
-
procname = columns[1].trim().split(/.*\(|\)/gi)[1],
|
|
847
|
-
grpname = _getProcessGrp(procname),
|
|
848
|
-
pid = parseInt(columns[0]),
|
|
849
|
-
pname = procname,
|
|
850
|
-
ppid = parseInt(columns[3]),
|
|
851
|
-
cputime = parseInt(columns[13]) + parseInt(columns[14]),
|
|
852
|
-
rss = parseInt(columns[23]) * 4,
|
|
853
|
-
pmem = (rss * 100);
|
|
854
|
-
// sum total used RSS
|
|
855
|
-
totalRAM += rss;
|
|
856
|
-
if (grpname === "Other") {
|
|
857
|
-
const objOther = {};
|
|
858
|
-
objOther["pid"] = pid;
|
|
859
|
-
objOther["pname"] = pname;
|
|
860
|
-
objOther["ppid"] = ppid;
|
|
861
|
-
objOther["cputime"] = cputime;
|
|
862
|
-
objOther["RSS"] = rss;
|
|
863
|
-
objOther["pmem"] = pmem;
|
|
864
|
-
otherList.push(objOther);
|
|
865
|
-
} else {
|
|
866
|
-
tempProcGrps[grpname]["pid"] = pid;
|
|
867
|
-
tempProcGrps[grpname]["cputime"] += cputime;
|
|
868
|
-
tempProcGrps[grpname]["RSS"] += rss;
|
|
869
|
-
tempProcGrps[grpname]["pmem"] += pmem;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
// get the Children of Service
|
|
873
|
-
for (const k in tempProcGrps) {
|
|
874
|
-
const attrName = k;
|
|
875
|
-
if (attrName === "System") {
|
|
876
|
-
continue;
|
|
877
|
-
}
|
|
878
|
-
const objOther = tempProcGrps[k];
|
|
879
|
-
for (let i = 0; i < otherList.length; i++) {
|
|
880
|
-
if (objOther["pid"] !== otherList[i]["ppid"]) {
|
|
881
|
-
continue;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
// this variable will mantain the aggregate pcpuVal of Service + dynamic apps
|
|
887
|
-
let aggcpuVal = 0;
|
|
888
|
-
// get the Web App processes data
|
|
889
|
-
if (arrActiveApps.length === 0) {
|
|
890
|
-
// get only the existing categories(3) if no running apps.
|
|
891
|
-
// dispose all the existing process variables
|
|
892
|
-
for (const name in processGroup) {
|
|
893
|
-
// if propertyName starts with "prev_" then dispose it
|
|
894
|
-
if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
|
|
895
|
-
continue;
|
|
896
|
-
}
|
|
897
|
-
if (name.indexOf("prev_app_") >= 0) {
|
|
898
|
-
processGroup[name] = undefined;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
} else {
|
|
902
|
-
// loop through each of the running apps
|
|
903
|
-
// in loop - Check if app is newly running app (or) already existing running app
|
|
904
|
-
for (let j = 0; j < arrActiveApps.length; j++) {
|
|
905
|
-
const objActApp = arrActiveApps[j],
|
|
906
|
-
webprocId = objActApp["webprocessid"],
|
|
907
|
-
procId = objActApp["processid"],
|
|
908
|
-
displayId = objActApp["displayId"] || 0;
|
|
909
|
-
let processId;
|
|
910
|
-
if (webprocId !== "" && webprocId !== undefined && webprocId !== "undefined") {
|
|
911
|
-
processId = webprocId;
|
|
912
|
-
} else if (procId !== "" && procId !== undefined && procId !== "undefined") {
|
|
913
|
-
processId = procId;
|
|
914
|
-
} else {
|
|
915
|
-
break;
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
const prevcpuTime = "prev_app_" + processId + "cputime",
|
|
919
|
-
appid = parseInt(processId);
|
|
920
|
-
let pcputime = 0;
|
|
921
|
-
// get the cputime from otherList
|
|
922
|
-
for (let l = 0; l < otherList.length; l++) {
|
|
923
|
-
if (otherList[l]["pid"] !== appid) {
|
|
924
|
-
continue;
|
|
925
|
-
}
|
|
926
|
-
pcputime = otherList[l]["cputime"];
|
|
927
|
-
if (!processGroup[prevcpuTime]) {
|
|
928
|
-
processGroup[prevcpuTime] = pcputime;
|
|
929
|
-
break;
|
|
930
|
-
}
|
|
931
|
-
let webpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
|
|
932
|
-
// restrict showing the negative % values by making lowest to be zero.
|
|
933
|
-
if (webpcpuval < 0 || webpcpuval === undefined || isNaN(webpcpuval)) webpcpuval = 0;
|
|
934
|
-
aggcpuVal += webpcpuval;
|
|
935
|
-
const groupListAppKey = objActApp["id"]+ "-" + appid;
|
|
936
|
-
groupObjList[groupListAppKey] = {
|
|
937
|
-
"id": objActApp["id"],
|
|
938
|
-
"pid": appid,
|
|
939
|
-
"cpu": webpcpuval,
|
|
940
|
-
"memory": {
|
|
941
|
-
"size": otherList[l]["RSS"],
|
|
942
|
-
"percent": otherList[l]["pmem"].toFixed(2)
|
|
943
|
-
},
|
|
944
|
-
"displayId": displayId
|
|
945
|
-
};
|
|
946
|
-
processGroup[prevcpuTime] = pcputime;
|
|
947
|
-
otherList.splice(l, 1);
|
|
948
|
-
break;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
// get the service processes data
|
|
953
|
-
if (arrActiveServices.length === 0) {
|
|
954
|
-
// get only the existing categories(3) if no running apps.
|
|
955
|
-
// dispose all the existing process variables
|
|
956
|
-
for (const name in processGroup) {
|
|
957
|
-
// if propertyName starts with "prev_" then dispose it
|
|
958
|
-
if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
|
|
959
|
-
continue;
|
|
960
|
-
}
|
|
961
|
-
if (name.indexOf("prev_svc_") >= 0) {
|
|
962
|
-
processGroup[name] = undefined;
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
} else {
|
|
966
|
-
// loop through each of the running apps
|
|
967
|
-
// in loop - Check if app is newly running app (or) already existing running app
|
|
968
|
-
for (let j = 0; j < arrActiveServices.length; j++) {
|
|
969
|
-
const objActService = arrActiveServices[j],
|
|
970
|
-
processId = objActService["processid"],
|
|
971
|
-
prevcpuTime = "prev_svc_" + processId + "cputime",
|
|
972
|
-
appid = parseInt(processId);
|
|
973
|
-
let pcputime = 0;
|
|
974
|
-
// get the cputime from otherList
|
|
975
|
-
for (let l = 0; l < otherList.length; l++) {
|
|
976
|
-
if (otherList[l]["pid"] !== appid) {
|
|
977
|
-
continue;
|
|
978
|
-
}
|
|
979
|
-
pcputime = otherList[l]["cputime"];
|
|
980
|
-
if (!processGroup[prevcpuTime]) {
|
|
981
|
-
processGroup[prevcpuTime] = pcputime;
|
|
982
|
-
break;
|
|
983
|
-
}
|
|
984
|
-
let svcpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
|
|
985
|
-
// restrict showing the negative % values by making lowest to be zero.
|
|
986
|
-
if (svcpcpuval < 0 || svcpcpuval === undefined || isNaN(svcpcpuval)) svcpcpuval = 0;
|
|
987
|
-
aggcpuVal+= svcpcpuval;
|
|
988
|
-
groupObjList[objActService["id"]] = {
|
|
989
|
-
"pid": appid,
|
|
990
|
-
"cpu": svcpcpuval,
|
|
991
|
-
"memory": {
|
|
992
|
-
"size": otherList[l]["RSS"],
|
|
993
|
-
"percent": otherList[l]["pmem"].toFixed(2)
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
processGroup[prevcpuTime] = pcputime;
|
|
997
|
-
otherList.splice(l, 1);
|
|
998
|
-
break;
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
// get the remaining System Category processes
|
|
1003
|
-
for (let i = 0; i < otherList.length; i++) {
|
|
1004
|
-
tempProcGrps["System"]["pid"] = otherList[i]["pid"];
|
|
1005
|
-
tempProcGrps["System"]["cputime"]+= otherList[i]["cputime"];
|
|
1006
|
-
tempProcGrps["System"]["RSS"]+= otherList[i]["RSS"];
|
|
1007
|
-
tempProcGrps["System"]["pmem"]+= otherList[i]["pmem"];
|
|
1008
|
-
}
|
|
1009
|
-
if (!processGroup.initialExecution) {
|
|
1010
|
-
const diffIdle = idleCPUtime - processGroup.prevIdlecputime,
|
|
1011
|
-
diffTotal = totalCPUtime - processGroup.prevTotalcputime,
|
|
1012
|
-
overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
|
|
1013
|
-
// assign all the values to return Object
|
|
1014
|
-
for (const key in tempProcGrps) {
|
|
1015
|
-
const processName = key;
|
|
1016
|
-
let tempPcpuval = 0;
|
|
1017
|
-
if (processName === "Service") {
|
|
1018
|
-
tempPcpuval = ((tempProcGrps[processName]["cputime"] - processGroup.prevServicecputime) * 100/diffTotal);
|
|
1019
|
-
}
|
|
1020
|
-
// restrict showing the negative % values by making lowest to be zero.
|
|
1021
|
-
if (tempPcpuval < 0 || tempPcpuval === undefined || isNaN(tempPcpuval)) tempPcpuval = 0;
|
|
1022
|
-
aggcpuVal += tempPcpuval;
|
|
1023
|
-
// system = overallCpuOccupation - (Service used + dynamic apps used);
|
|
1024
|
-
if (processName === "System") {
|
|
1025
|
-
tempPcpuval = overallCpuOccupation - aggcpuVal;
|
|
1026
|
-
}
|
|
1027
|
-
// restrict Negative/peak values due to cores fluctuation
|
|
1028
|
-
tempPcpuval < 0 ? (tempPcpuval = 0) : tempPcpuval;
|
|
1029
|
-
tempPcpuval > pcore ? (tempPcpuval = pcore) : tempPcpuval;
|
|
1030
|
-
tempProcGrps[processName]["pmem"] /= totalRAM;
|
|
1031
|
-
const procinfo = {
|
|
1032
|
-
"pid": tempProcGrps[processName]["pid"],
|
|
1033
|
-
"appid": processName,
|
|
1034
|
-
"cpu": parseFloat(tempPcpuval.toFixed(2)),
|
|
1035
|
-
"memory": {
|
|
1036
|
-
"size": tempProcGrps[processName]["RSS"],
|
|
1037
|
-
"percent": tempProcGrps[processName]["pmem"].toFixed(2)
|
|
1038
|
-
}
|
|
1039
|
-
};
|
|
1040
|
-
processinfo.push(procinfo);
|
|
1041
|
-
}
|
|
1042
|
-
// push the calculated groups into list
|
|
1043
|
-
for (const propertyName in groupObjList) {
|
|
1044
|
-
if (!Object.prototype.hasOwnProperty.call(groupObjList, propertyName)) {
|
|
1045
|
-
continue;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
const procObj = groupObjList[propertyName];
|
|
1049
|
-
let pcpuval = parseFloat(procObj["cpu"].toFixed(2));
|
|
1050
|
-
if (pcpuval === undefined || isNaN(pcpuval)) {
|
|
1051
|
-
pcpuval = 0;
|
|
1052
|
-
}
|
|
1053
|
-
procObj["memory"]["percent"] /= totalRAM;
|
|
1054
|
-
const procinfo = {
|
|
1055
|
-
"pid": procObj["pid"],
|
|
1056
|
-
"appid": procObj["id"] || propertyName,
|
|
1057
|
-
"cpu": pcpuval,
|
|
1058
|
-
"memory": {
|
|
1059
|
-
"size": procObj["memory"]["size"],
|
|
1060
|
-
"percent": parseFloat(procObj["memory"]["percent"]).toFixed(2)
|
|
1061
|
-
},
|
|
1062
|
-
"displayId": procObj["displayId"]
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
processinfo.push(procinfo);
|
|
1066
|
-
// copy only app and service info to group for printing
|
|
1067
|
-
groupProcessinfo.push(procinfo);
|
|
1068
|
-
|
|
1069
|
-
if (processinfo.indexOf(propertyName) < 0) {
|
|
1070
|
-
processList.push(propertyName);
|
|
1071
|
-
groupProcessList.push(propertyName);
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
processGroup.prevIdlecputime = idleCPUtime;
|
|
1076
|
-
processGroup.prevTotalcputime = totalCPUtime;
|
|
1077
|
-
processGroup.prevServicecputime = tempProcGrps["Service"]["cputime"];
|
|
1078
|
-
|
|
1079
|
-
if (!processGroup.initialExecution) {
|
|
1080
|
-
const processgrpinfo = {
|
|
1081
|
-
"date": date,
|
|
1082
|
-
"processinfo": groupProcessinfo,
|
|
1083
|
-
"processList": groupProcessList
|
|
1084
|
-
};
|
|
1085
|
-
_printProcessList(processgrpinfo);
|
|
1086
|
-
}
|
|
1087
|
-
} catch (err) {
|
|
1088
|
-
// do not print error message to user
|
|
1089
|
-
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
1090
|
-
log.silly("device#processResource()#_setProcessInfo()", "in try-catch. err:", err.toString());
|
|
1091
|
-
return;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
function _getProcessGrp(pname) {
|
|
1096
|
-
let group;
|
|
1097
|
-
switch (pname) {
|
|
1098
|
-
case 'ls-hubd':
|
|
1099
|
-
group = 'Service'; break;
|
|
1100
|
-
default:
|
|
1101
|
-
group = 'Other'; // it could be children of above categories or System
|
|
1102
|
-
}
|
|
1103
|
-
return group;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
function _printProcessList(processgrpinfo) {
|
|
1107
|
-
log.info("device#processResource()#_printProcessList()", JSON.stringify(processgrpinfo));
|
|
1108
|
-
|
|
1109
|
-
const processinfo = processgrpinfo.processinfo,
|
|
1110
|
-
processinfoTable = new Table();
|
|
1111
|
-
|
|
1112
|
-
let found = false;
|
|
1113
|
-
if (options.id) {
|
|
1114
|
-
processinfo.forEach(function(process) {
|
|
1115
|
-
if (options.id === process.appid) {
|
|
1116
|
-
found = true;
|
|
1117
|
-
}
|
|
1118
|
-
});
|
|
1119
|
-
if (found === false) {
|
|
1120
|
-
// print guide message to user
|
|
1121
|
-
console.log("<" + options.id + ">" + " is not running. Please launch the app or service.");
|
|
1122
|
-
return;
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
if (processgrpinfo.processList.length === 0) {
|
|
1126
|
-
// print guide message to user
|
|
1127
|
-
console.log("There are no running apps or services. Please launch any app or service.");
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
// add process list to table
|
|
1132
|
-
const dataForCSV = [];
|
|
1133
|
-
if (Array.isArray(processinfo)) {
|
|
1134
|
-
processinfo.forEach(function(process) {
|
|
1135
|
-
// if user gives ID, print only the ID's information
|
|
1136
|
-
if (options.id && options.id !== process.appid) {
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
processinfoTable.cell('PID', process.pid);
|
|
1140
|
-
processinfoTable.cell('ID', process.appid);
|
|
1141
|
-
processinfoTable.cell('DISPLAY ID', process.displayId);
|
|
1142
|
-
processinfoTable.cell('CPU(%)', process.cpu);
|
|
1143
|
-
|
|
1144
|
-
const meminfo = process.memory;
|
|
1145
|
-
processinfoTable.cell('MEMORY(%)', meminfo.percent);
|
|
1146
|
-
processinfoTable.cell('MEMORY(KB)', meminfo.size);
|
|
1147
|
-
processinfoTable.newRow();
|
|
1148
|
-
|
|
1149
|
-
// add data object
|
|
1150
|
-
const obj = {
|
|
1151
|
-
time: processgrpinfo.date,
|
|
1152
|
-
pid: process.pid,
|
|
1153
|
-
id: process.appid,
|
|
1154
|
-
displayId: process.displayId,
|
|
1155
|
-
cpu: process.cpu,
|
|
1156
|
-
memory: meminfo.percent,
|
|
1157
|
-
memory_size: meminfo.size
|
|
1158
|
-
};
|
|
1159
|
-
dataForCSV.push(obj);
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
|
-
// write CSV file if user gives --save option
|
|
1163
|
-
if (options.save && options.csvPath) {
|
|
1164
|
-
// write csv file
|
|
1165
|
-
// when openMode is false, the new csv file will be created and "Header" add to the file
|
|
1166
|
-
let openMode = false;
|
|
1167
|
-
if (fs.existsSync(options.csvPath)) {
|
|
1168
|
-
openMode = true;
|
|
1169
|
-
}
|
|
1170
|
-
const csvWriter = createCsvWriter({
|
|
1171
|
-
path: options.csvPath,
|
|
1172
|
-
header: [
|
|
1173
|
-
{id: 'time', title: 'TIME'},
|
|
1174
|
-
{id: 'pid', title: 'PID'},
|
|
1175
|
-
{id: 'id', title: 'ID'},
|
|
1176
|
-
{id: 'displayId', title: 'DISPLAY ID'},
|
|
1177
|
-
{id: 'cpu', title: 'CPU(%)'},
|
|
1178
|
-
{id: 'memory', title: 'MEMORY(%)'},
|
|
1179
|
-
{id: 'memory_size', title: 'MEMORY(KB)'}
|
|
1180
|
-
],
|
|
1181
|
-
append: openMode
|
|
1182
|
-
});
|
|
1183
|
-
|
|
1184
|
-
csvWriter
|
|
1185
|
-
.writeRecords(dataForCSV)
|
|
1186
|
-
.then(function() {
|
|
1187
|
-
log.silly("device#processResource()#_printProcessList()", "CSV file updated");
|
|
1188
|
-
// csv file has been created at first
|
|
1189
|
-
if (openMode === false) {
|
|
1190
|
-
const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
|
|
1191
|
-
console.log(resultTxt);
|
|
1192
|
-
}
|
|
1193
|
-
__printTable();
|
|
1194
|
-
}).catch(function(err) {
|
|
1195
|
-
return setImmediate(next, errHndl.getErrMsg(err));
|
|
1196
|
-
});
|
|
1197
|
-
} else {
|
|
1198
|
-
__printTable();
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
function __printTable() {
|
|
1202
|
-
// Print resullt to terminal
|
|
1203
|
-
console.log(processgrpinfo.date + "\n");
|
|
1204
|
-
console.log(processinfoTable.toString());
|
|
1205
|
-
console.log("======================================================================");
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
},
|
|
1209
|
-
/**
|
|
1210
|
-
* get screen capture of the given device
|
|
1211
|
-
* @property options {String} device, display, outputPath
|
|
1212
|
-
*/
|
|
1213
|
-
captureScreen: function(options, next) {
|
|
1214
|
-
if (typeof next !== 'function') {
|
|
1215
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
1216
|
-
}
|
|
1217
|
-
options = options || {};
|
|
1218
|
-
async.series([
|
|
1219
|
-
_makeSession,
|
|
1220
|
-
_makeCaptureOption,
|
|
1221
|
-
_captureScreenFile,
|
|
1222
|
-
_copyFileToLocal
|
|
1223
|
-
], function(err, results) {
|
|
1224
|
-
log.silly("device#captureScreen()", "err:", err, ", results:", results);
|
|
1225
|
-
const resultTxt = "Create " + chalk.green(options.captureFileName) + " to " + options.destinationPath +"\nSuccess";
|
|
1226
|
-
|
|
1227
|
-
// clean up /tmp/aresCapture directory in target device
|
|
1228
|
-
if (options.createdTmpDir) {
|
|
1229
|
-
_removeTmpDir(function finish(removeErr) {
|
|
1230
|
-
next(err ? err : removeErr, {msg: resultTxt});
|
|
1231
|
-
});
|
|
1232
|
-
} else {
|
|
1233
|
-
next(err, {msg: resultTxt});
|
|
1234
|
-
}
|
|
1235
|
-
});
|
|
1236
|
-
|
|
1237
|
-
function _makeSession(next) {
|
|
1238
|
-
makeSession(options, next);
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
function _makeCaptureOption(next) {
|
|
1242
|
-
log.info("device#captureScreen()#_makeCaptureOption()");
|
|
1243
|
-
|
|
1244
|
-
const captureFormat = "PNG", // PNG is default format
|
|
1245
|
-
fileNameSeperator = "_";
|
|
1246
|
-
|
|
1247
|
-
let captureFileName = options.session.target.name + "_" + "display" + options.display + "_",
|
|
1248
|
-
destinationPath = "";
|
|
1249
|
-
|
|
1250
|
-
if (options.outputPath === null) {
|
|
1251
|
-
captureFileName += createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
|
|
1252
|
-
destinationPath = path.resolve('.');
|
|
1253
|
-
} else {
|
|
1254
|
-
// get directory path, file path, file Extenstion from given path
|
|
1255
|
-
const parseDirPath = path.dirname(options.outputPath),
|
|
1256
|
-
parseBase = path.parse(options.outputPath).base;
|
|
1257
|
-
|
|
1258
|
-
let parseExt = path.parse(options.outputPath).ext;
|
|
1259
|
-
|
|
1260
|
-
parseExt = parseExt.split('.').pop();
|
|
1261
|
-
log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
|
|
1262
|
-
+ " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
|
|
1263
|
-
|
|
1264
|
-
// if specific path is given
|
|
1265
|
-
if (parseBase) {
|
|
1266
|
-
captureFileName = parseBase;
|
|
1267
|
-
destinationPath = path.resolve(parseDirPath);
|
|
1268
|
-
// parseBase is [filename].[ext] format
|
|
1269
|
-
if (parseExt === "") {
|
|
1270
|
-
// paresBase does not have file extesntion, add .png format
|
|
1271
|
-
captureFileName += "." + captureFormat.toLowerCase();
|
|
1272
|
-
} else if (parseExt !== "png" && parseExt !== "bmp" && parseExt !== "jpg") {
|
|
1273
|
-
return next(errHndl.getErrMsg("INVALID_CAPTURE_FORMAT"));
|
|
1274
|
-
}
|
|
1275
|
-
} else if (parseDirPath) {
|
|
1276
|
-
// the path has only "directory" without parseBase
|
|
1277
|
-
// for example, "ares-device -c /"
|
|
1278
|
-
captureFileName = createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
|
|
1279
|
-
destinationPath = path.resolve(parseDirPath);
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
options.captureFormat = captureFormat;
|
|
1284
|
-
options.captureFileName = captureFileName;
|
|
1285
|
-
options.captureDirPath = "/tmp/aresCapture/";
|
|
1286
|
-
options.sourcePath = options.captureDirPath + captureFileName;
|
|
1287
|
-
options.destinationPath = destinationPath;
|
|
1288
|
-
options.ignore = true;
|
|
1289
|
-
options.silent = true;
|
|
1290
|
-
|
|
1291
|
-
next();
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
function _captureScreenFile(next) {
|
|
1295
|
-
log.info("device#captureScreen()#_captureScreenFile()");
|
|
1296
|
-
const cmd = "/bin/mkdir -p " + options.captureDirPath;
|
|
1297
|
-
options.session.run(cmd, null, null, null, function(err) {
|
|
1298
|
-
if (err) {
|
|
1299
|
-
return setImmediate(next, err);
|
|
1300
|
-
} else {
|
|
1301
|
-
options.createdTmpDir = true;
|
|
1302
|
-
const target = options.session.getDevice(),
|
|
1303
|
-
addr = target.lunaAddr.captureCompositorOutput,
|
|
1304
|
-
param = {
|
|
1305
|
-
// luna param
|
|
1306
|
-
subscribe: false,
|
|
1307
|
-
output: options.sourcePath,
|
|
1308
|
-
format: options.captureFormat,
|
|
1309
|
-
displayId: options.display
|
|
1310
|
-
};
|
|
1311
|
-
|
|
1312
|
-
luna.send(options, addr, param, function(lineObj, next) {
|
|
1313
|
-
if (lineObj.returnValue) {
|
|
1314
|
-
log.verbose("device#captureScreen()#_captureScreenFile()","Capture file in target:" + lineObj.output);
|
|
1315
|
-
next(null, {});
|
|
1316
|
-
} else {
|
|
1317
|
-
log.verbose("device#captureScreen()#_captureScreenFile()", "failure");
|
|
1318
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
1319
|
-
}
|
|
1320
|
-
}, next);
|
|
1321
|
-
}
|
|
1322
|
-
});
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
function _copyFileToLocal(next) {
|
|
1326
|
-
log.info("device#captureScreen()#_copyFileToLocal()");
|
|
1327
|
-
pullLib.pull(options.sourcePath, options.destinationPath, options, next);
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
function _removeTmpDir(next) {
|
|
1331
|
-
log.info("device#captureScreen()#_removeTmpDir()");
|
|
1332
|
-
const cmd = '/bin/rm -rf ' + options.captureDirPath;
|
|
1333
|
-
options.session.run(cmd, null, null, null, function(err) {
|
|
1334
|
-
if (err) {
|
|
1335
|
-
return setImmediate(next, err);
|
|
1336
|
-
} else {
|
|
1337
|
-
next();
|
|
1338
|
-
}
|
|
1339
|
-
});
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
};
|
|
1343
|
-
|
|
1344
|
-
function makeSession(options, next) {
|
|
1345
|
-
options.nReplies = 1; // -n 1
|
|
1346
|
-
if (!options.session) {
|
|
1347
|
-
log.info("device#makeSession()", "need to make new session");
|
|
1348
|
-
const printTarget = true;
|
|
1349
|
-
options.session = new novacom.Session(options.device, printTarget, next);
|
|
1350
|
-
} else {
|
|
1351
|
-
log.info("device#makeSession()", "already exist session");
|
|
1352
|
-
next();
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
function makeCSVOutputPath(options, next) {
|
|
1357
|
-
const csvFormat = "csv", // csv is default format
|
|
1358
|
-
fileNameSeperator = "_";
|
|
1359
|
-
|
|
1360
|
-
if (options.outputPath === null) {
|
|
1361
|
-
options.fileName = createDateFileName(fileNameSeperator, csvFormat);
|
|
1362
|
-
options.destinationPath = path.resolve('.');
|
|
1363
|
-
} else {
|
|
1364
|
-
// get directory path, file path, file Extenstion from given path
|
|
1365
|
-
const parseDirPath = path.dirname(options.outputPath),
|
|
1366
|
-
parseBase = path.parse(options.outputPath).base;
|
|
1367
|
-
|
|
1368
|
-
let parseExt = path.parse(options.outputPath).ext;
|
|
1369
|
-
|
|
1370
|
-
parseExt = parseExt.split('.').pop();
|
|
1371
|
-
log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
|
|
1372
|
-
+ " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
|
|
1373
|
-
|
|
1374
|
-
// if specific path is given
|
|
1375
|
-
if (parseBase) {
|
|
1376
|
-
options.fileName = parseBase;
|
|
1377
|
-
options.destinationPath = path.resolve(parseDirPath);
|
|
1378
|
-
// parseBase is [filename].[ext] format
|
|
1379
|
-
if (parseExt === "") {
|
|
1380
|
-
// paresBase does not have file extesntion, add .png format
|
|
1381
|
-
options.fileName += "." + csvFormat;
|
|
1382
|
-
} else if (parseExt !== csvFormat) {
|
|
1383
|
-
return next(errHndl.getErrMsg("INVALID_CSV_FORMAT"));
|
|
1384
|
-
}
|
|
1385
|
-
} else if (parseDirPath) {
|
|
1386
|
-
// the path has only "directory" without parseBase
|
|
1387
|
-
// for example, "ares-device -r -s /"
|
|
1388
|
-
options.fileName = createDateFileName(fileNameSeperator, csvFormat);
|
|
1389
|
-
options.destinationPath = path.resolve(parseDirPath);
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
options.csvPath = path.resolve(options.destinationPath, options.fileName);
|
|
1394
|
-
log.verbose("device#makeCSVOutputPath()", "csvPath:", options.csvPath);
|
|
1395
|
-
|
|
1396
|
-
fs.open(options.csvPath, 'w', function(err, fd) {
|
|
1397
|
-
if (err) {
|
|
1398
|
-
return next(errHndl.getErrMsg(err));
|
|
1399
|
-
}
|
|
1400
|
-
fs.close(fd, function(error) {
|
|
1401
|
-
if (error) {
|
|
1402
|
-
return next(errHndl.getErrMsg(error));
|
|
1403
|
-
}
|
|
1404
|
-
log.verbose("device#makeCSVOutputPath()", options.csvPath + " is closed");
|
|
1405
|
-
|
|
1406
|
-
// Defense code
|
|
1407
|
-
if (fs.existsSync(options.csvPath)) {
|
|
1408
|
-
fs.unlinkSync(options.csvPath);
|
|
1409
|
-
}
|
|
1410
|
-
log.verbose("device#makeCSVOutputPath()", options.csvPath + " is exist: " + fs.existsSync(options.csvPath));
|
|
1411
|
-
next();
|
|
1412
|
-
});
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
1417
|
-
module.exports = device;
|
|
1418
|
-
}
|
|
1419
|
-
}());
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2020-2024 LG Electronics Inc.
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const async = require('async'),
|
|
8
|
+
chalk = require('chalk'),
|
|
9
|
+
createCsvWriter = require('csv-writer').createObjectCsvWriter,
|
|
10
|
+
fs = require('fs'),
|
|
11
|
+
npmlog = require('npmlog'),
|
|
12
|
+
path = require('path'),
|
|
13
|
+
streamBuffers = require('stream-buffers'),
|
|
14
|
+
Table = require('easy-table'),
|
|
15
|
+
util = require('util'),
|
|
16
|
+
pullLib = require('./pull'),
|
|
17
|
+
errHndl = require('./base/error-handler'),
|
|
18
|
+
luna = require('./base/luna'),
|
|
19
|
+
novacom = require('./base/novacom'),
|
|
20
|
+
createDateFileName = require('./util/createFileName').createDateFileName,
|
|
21
|
+
convertJsonToList = require('./util/json').convertJsonToList;
|
|
22
|
+
|
|
23
|
+
(function() {
|
|
24
|
+
const log = npmlog;
|
|
25
|
+
log.heading = 'device';
|
|
26
|
+
log.level = 'warn';
|
|
27
|
+
|
|
28
|
+
const device = {
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @property {Object} log an npm log instance
|
|
32
|
+
*/
|
|
33
|
+
log: log,
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Print system information of the given device
|
|
37
|
+
* @property options {String} device the device to connect to
|
|
38
|
+
*/
|
|
39
|
+
systemInfo: function(options, next) {
|
|
40
|
+
if (typeof next !== 'function') {
|
|
41
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
42
|
+
}
|
|
43
|
+
options = options || {};
|
|
44
|
+
async.series([
|
|
45
|
+
_makeSession,
|
|
46
|
+
_getOsInfo,
|
|
47
|
+
_getDeviceInfo,
|
|
48
|
+
_getChromiumVersion,
|
|
49
|
+
_getQtbaseVersion,
|
|
50
|
+
_getSoftwareInfo
|
|
51
|
+
], function(err, results) {
|
|
52
|
+
log.silly("device#systemInfo()", "err:", err, ", results:", results);
|
|
53
|
+
let resultTxt = "";
|
|
54
|
+
for (let i = 1; i < results.length; i++) {
|
|
55
|
+
resultTxt += results[i] + "\n";
|
|
56
|
+
}
|
|
57
|
+
next(err, {msg: resultTxt.trim()});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
function _makeSession(next) {
|
|
61
|
+
makeSession(options, next);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _getOsInfo(next) {
|
|
65
|
+
log.info("device#systemInfo()#_getOsInfo()");
|
|
66
|
+
const target = options.session.getDevice(),
|
|
67
|
+
addr = target.lunaAddr.osInfo,
|
|
68
|
+
param = {
|
|
69
|
+
// luna param
|
|
70
|
+
parameters:["webos_build_id","webos_imagename","webos_name","webos_release",
|
|
71
|
+
"webos_manufacturing_version", "core_os_kernel_version"],
|
|
72
|
+
subscribe: false
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
luna.send(options, addr, param, function(lineObj, next) {
|
|
76
|
+
const resultValue = lineObj;
|
|
77
|
+
|
|
78
|
+
if (resultValue.returnValue) {
|
|
79
|
+
log.verbose("device#systemInfo()#_getOsInfo()", "success");
|
|
80
|
+
delete resultValue.returnValue; // remove unnecessary data
|
|
81
|
+
next(null, _makeReturnTxt(resultValue));
|
|
82
|
+
} else {
|
|
83
|
+
log.verbose("device#systemInfo()#_getOsInfo()", "failure");
|
|
84
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
85
|
+
}
|
|
86
|
+
}, next);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function _getDeviceInfo(next) {
|
|
90
|
+
log.info("device#systemInfo()#_getDeviceInfo()");
|
|
91
|
+
const target = options.session.getDevice(),
|
|
92
|
+
addr = target.lunaAddr.deviceInfo,
|
|
93
|
+
param = {
|
|
94
|
+
// luna param
|
|
95
|
+
subscribe: false
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
luna.send(options, addr, param, function(lineObj, next) {
|
|
99
|
+
const resultValue = lineObj,
|
|
100
|
+
returnObj ={};
|
|
101
|
+
|
|
102
|
+
if (resultValue.returnValue) {
|
|
103
|
+
log.verbose("device#systemInfo()#_getDeviceInfo()", "success");
|
|
104
|
+
returnObj.device_name = resultValue.device_name;
|
|
105
|
+
returnObj.device_id = resultValue.device_id;
|
|
106
|
+
next(null, _makeReturnTxt(returnObj));
|
|
107
|
+
} else {
|
|
108
|
+
log.verbose("device#systemInfo()#_getDeviceInfo()", "failure");
|
|
109
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
110
|
+
}
|
|
111
|
+
}, next);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function _getChromiumVersion(next) {
|
|
115
|
+
log.info("device#systemInfo()#_getChromiumInfo()");
|
|
116
|
+
|
|
117
|
+
// opkg is required permission as root.
|
|
118
|
+
if (options.session.getDevice().username !== 'root') {
|
|
119
|
+
return next(null, "chromium_version : " + "not supported");
|
|
120
|
+
} else {
|
|
121
|
+
const cmd = '/usr/bin/opkg list-installed webruntime*';
|
|
122
|
+
options.session.run(cmd, null, __data, null, function(err) {
|
|
123
|
+
if (err) {
|
|
124
|
+
return next(err);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function __data(data) {
|
|
129
|
+
const str = (Buffer.isBuffer(data)) ? data.toString() : data,
|
|
130
|
+
exp = /\d*\.\d*\.\d*\.\d*/,
|
|
131
|
+
version = str.match(exp);
|
|
132
|
+
|
|
133
|
+
next(null, "chromium_version : " + version);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function _getQtbaseVersion(next) {
|
|
138
|
+
log.info("device#systemInfo()#_getQtbaseInfo()");
|
|
139
|
+
|
|
140
|
+
// opkg is required permission as root.
|
|
141
|
+
if (options.session.getDevice().username !== 'root') {
|
|
142
|
+
return next(null, "qt_version : " + "not supported");
|
|
143
|
+
} else {
|
|
144
|
+
const cmd = '/usr/bin/opkg list-installed qtbase';
|
|
145
|
+
options.session.run(cmd, null, __data, null, function(err) {
|
|
146
|
+
if (err) {
|
|
147
|
+
return next(err);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function __data(data) {
|
|
152
|
+
const str = (Buffer.isBuffer(data)) ? data.toString() : data,
|
|
153
|
+
exp = /\d*\.\d*\.\d*/,
|
|
154
|
+
version = str.match(exp);
|
|
155
|
+
next(null, "qt_version : " + version);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function _getSoftwareInfo(next) {
|
|
160
|
+
log.info("device#systemInfo#_getSoftwareInfo()");
|
|
161
|
+
const target = options.session.getDevice(),
|
|
162
|
+
addr = target.lunaAddr.softwareInfo,
|
|
163
|
+
param = {
|
|
164
|
+
parameters: ["nodejs_versions"]
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
luna.sendWithoutErrorHandle(options, addr, param, function(lineObj, next) {
|
|
168
|
+
log.silly("device#systemInfo#_getSoftwareInfo():", "lineObj:", lineObj);
|
|
169
|
+
|
|
170
|
+
const resultValue = lineObj,
|
|
171
|
+
returnObj ={};
|
|
172
|
+
|
|
173
|
+
if (resultValue.returnValue) {
|
|
174
|
+
log.verbose("device#systemInfo#_getSoftwareInfo():", "success");
|
|
175
|
+
returnObj.nodejs_versions = resultValue.nodejs_versions;
|
|
176
|
+
next(null, _makeReturnTxt(returnObj));
|
|
177
|
+
} else {
|
|
178
|
+
// handle if the target device does not support softwareInfo/query
|
|
179
|
+
return next(null, "nodejs_versions : " + "not supported");
|
|
180
|
+
}
|
|
181
|
+
}, next);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function _makeReturnTxt(resultValue) {
|
|
185
|
+
let returnTxt = "";
|
|
186
|
+
|
|
187
|
+
for (const key in resultValue) {
|
|
188
|
+
if (resultValue[key] === undefined) {
|
|
189
|
+
resultValue[key] = "(unknown)";
|
|
190
|
+
}
|
|
191
|
+
returnTxt += key + " : " + resultValue[key] + "\n";
|
|
192
|
+
}
|
|
193
|
+
return returnTxt.trim();
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
/**
|
|
197
|
+
* Print session information of the given device
|
|
198
|
+
* @property options {String} device the device to connect to
|
|
199
|
+
*/
|
|
200
|
+
sessionInfo: function(options, next) {
|
|
201
|
+
if (typeof next !== 'function') {
|
|
202
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
203
|
+
}
|
|
204
|
+
options = options || {};
|
|
205
|
+
async.series([
|
|
206
|
+
_makeSession,
|
|
207
|
+
_getSessionList
|
|
208
|
+
], function(err, results) {
|
|
209
|
+
log.silly("device#sessionInfo()", "err:", err, ", results:", results);
|
|
210
|
+
let resultTxt = "";
|
|
211
|
+
|
|
212
|
+
if (results[1] !== undefined) {
|
|
213
|
+
if (typeof results[1] === "object") {
|
|
214
|
+
if (results[1].length === 0) {
|
|
215
|
+
return next(errHndl.getErrMsg("SELECT_PROFILE"));
|
|
216
|
+
}
|
|
217
|
+
for (let i = 0; i < results[1].length; i++) {
|
|
218
|
+
resultTxt += convertJsonToList(results[1][i], 0) + '\n';
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
resultTxt = results[1];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
next(err, {msg: resultTxt.trim()});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
function _makeSession(next) {
|
|
228
|
+
makeSession(options, next);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function _getSessionList(next) {
|
|
232
|
+
log.info("device#sessionInfo#_getSessionList()");
|
|
233
|
+
const target = options.session.getDevice(),
|
|
234
|
+
addr = target.lunaAddr.getSessionList,
|
|
235
|
+
param = {
|
|
236
|
+
// luna param
|
|
237
|
+
subscribe: false
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
luna.send(options, addr, param, function(lineObj, next) {
|
|
241
|
+
if (lineObj.returnValue) {
|
|
242
|
+
log.verbose("device#sessionInfo()#_getSessionList()", "success");
|
|
243
|
+
next(null, lineObj.sessionList);
|
|
244
|
+
} else {
|
|
245
|
+
log.verbose("device#sessionInfo()#_getSessionList()", "failure");
|
|
246
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
247
|
+
}
|
|
248
|
+
}, next);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
/**
|
|
252
|
+
* Print system information of the given device
|
|
253
|
+
* @property options {String} device the device to connect to
|
|
254
|
+
*/
|
|
255
|
+
tvSystemInfo: function(options, next) {
|
|
256
|
+
if (typeof next !== 'function') {
|
|
257
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
258
|
+
}
|
|
259
|
+
options = options || {};
|
|
260
|
+
async.series([
|
|
261
|
+
_makeSession,
|
|
262
|
+
_getSystemInfo,
|
|
263
|
+
], function(err, results) {
|
|
264
|
+
log.silly("device#tvSystemInfo()", "err:", err, ", results:", results);
|
|
265
|
+
next(err, {msg: results[1]});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
function _makeSession(next) {
|
|
269
|
+
makeSession(options, next);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function _getSystemInfo(next) {
|
|
273
|
+
log.info("device#tvSystemInfo#_getSystemInfo()");
|
|
274
|
+
const target = options.session.getDevice(),
|
|
275
|
+
addr = target.lunaAddr.deviceInfoSystem,
|
|
276
|
+
param = {
|
|
277
|
+
// luna param
|
|
278
|
+
keys: ["modelName", "sdkVersion", "firmwareVersion", "boardType", "otaId"],
|
|
279
|
+
subscribe: false
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
luna.sendWithoutErrorHandle(options, addr, param, function (lineObj, next) {
|
|
283
|
+
if (lineObj) {
|
|
284
|
+
log.verbose("deviceInfo#systemInfo#_getSystemInfo():", "success");
|
|
285
|
+
next(null, __makeReturnObj(lineObj, param.keys));
|
|
286
|
+
} else {
|
|
287
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
288
|
+
}
|
|
289
|
+
}, next);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function __makeReturnObj(resultValue, paramkey) {
|
|
293
|
+
let returnTxt = "";
|
|
294
|
+
|
|
295
|
+
for (const key in paramkey) {
|
|
296
|
+
if (Object.hasOwnProperty.call(resultValue, paramkey[key]))
|
|
297
|
+
returnTxt += paramkey[key] + " : " + resultValue[paramkey[key]] + "\n";
|
|
298
|
+
}
|
|
299
|
+
log.verbose("deviceInfo#systemInfo#__makeReturnObj():", returnTxt);
|
|
300
|
+
return returnTxt.trim();
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
/**
|
|
304
|
+
* Get all CPUs and memories usage of target device
|
|
305
|
+
* @property options {String} device, interval
|
|
306
|
+
*/
|
|
307
|
+
systemResource: function(options, next) {
|
|
308
|
+
if (typeof next !== 'function') {
|
|
309
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
310
|
+
}
|
|
311
|
+
const systemGroup = {};
|
|
312
|
+
systemGroup.initialExecution = true;
|
|
313
|
+
options = options || {};
|
|
314
|
+
options.destinationPath = "";
|
|
315
|
+
options.fileName = "";
|
|
316
|
+
options.csvPath = "";
|
|
317
|
+
async.series([
|
|
318
|
+
_createOutputPath,
|
|
319
|
+
_makeSession,
|
|
320
|
+
_getSystemResouceInfo
|
|
321
|
+
], function(err, results) {
|
|
322
|
+
log.silly("device#systemResource()", "err:", err, ", results:", results);
|
|
323
|
+
next(err);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
function _createOutputPath(next) {
|
|
327
|
+
if (options.save && options.csvPath === "") {
|
|
328
|
+
makeCSVOutputPath(options, next);
|
|
329
|
+
} else {
|
|
330
|
+
next();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function _makeSession(next) {
|
|
335
|
+
makeSession(options, next);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function _getSystemResouceInfo(next) {
|
|
339
|
+
log.info("device#systemResource()#_getSystemResouceInfo()");
|
|
340
|
+
|
|
341
|
+
let timerId;
|
|
342
|
+
if (!options.interval) {
|
|
343
|
+
// If interval option is not given, call timer logic 2 times
|
|
344
|
+
const defaultRepeat = 2;
|
|
345
|
+
let repeatCount = 0;
|
|
346
|
+
try {
|
|
347
|
+
timerId = setTimeout(function repeat() {
|
|
348
|
+
if (repeatCount < defaultRepeat) {
|
|
349
|
+
_callSystemResourceInfoCmd();
|
|
350
|
+
repeatCount++;
|
|
351
|
+
timerId = setTimeout(repeat, 1000);
|
|
352
|
+
} else {
|
|
353
|
+
clearTimeout(timerId);
|
|
354
|
+
return next();
|
|
355
|
+
}
|
|
356
|
+
}, 100);
|
|
357
|
+
} catch (err) {
|
|
358
|
+
log.silly("device#systemResource()#_getSystemResouceInfo()", "one timer. err:", err.toString());
|
|
359
|
+
clearTimeout(timerId);
|
|
360
|
+
// ignore timer logic error
|
|
361
|
+
return next();
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
try {
|
|
365
|
+
// when interval option is given, print initial data at first
|
|
366
|
+
const defaultRepeat = 1;
|
|
367
|
+
let repeatCount = 0;
|
|
368
|
+
timerId = setTimeout(function repeat() {
|
|
369
|
+
if (repeatCount < defaultRepeat) {
|
|
370
|
+
_callSystemResourceInfoCmd();
|
|
371
|
+
repeatCount++;
|
|
372
|
+
timerId = setTimeout(repeat, 1000);
|
|
373
|
+
} else {
|
|
374
|
+
_callSystemResourceInfoCmd();
|
|
375
|
+
timerId = setTimeout(repeat, options.interval * 1000);
|
|
376
|
+
}
|
|
377
|
+
}, 100);
|
|
378
|
+
} catch (err) {
|
|
379
|
+
log.silly("device#systemResource()#_getSystemResouceInfo()", "repeat timer. err:", err.toString());
|
|
380
|
+
clearTimeout(timerId);
|
|
381
|
+
// ignore timer logic error
|
|
382
|
+
return next();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function _callSystemResourceInfoCmd() {
|
|
388
|
+
log.info("device#systemResource()#_callSystemResourceInfoCmd()");
|
|
389
|
+
|
|
390
|
+
const wStream = new streamBuffers.WritableStreamBuffer();
|
|
391
|
+
const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep -c ^processor /proc/cpuinfo; grep "cpu *" /proc/stat; free -k';
|
|
392
|
+
try {
|
|
393
|
+
options.session.run(cmd, null, wStream, null, function(err) {
|
|
394
|
+
if (err) {
|
|
395
|
+
// do not print error message to user
|
|
396
|
+
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
397
|
+
log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "ssh call. err:"+ err.toString());
|
|
398
|
+
return next();
|
|
399
|
+
} else {
|
|
400
|
+
const result = wStream.getContentsAsString();
|
|
401
|
+
_setSystemResouceInfo(result);
|
|
402
|
+
systemGroup.initialExecution = false;
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
} catch (err) {
|
|
406
|
+
// do not print error message to user
|
|
407
|
+
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
408
|
+
log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "in try-catch. err:", err.toString());
|
|
409
|
+
return next();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function _setSystemResouceInfo(systemData) {
|
|
414
|
+
log.info("device#systemResource()#_callSystemResourceInfoCmd()");
|
|
415
|
+
|
|
416
|
+
const CPU_PATTERN = /\s+/,
|
|
417
|
+
cpuinfo = {},
|
|
418
|
+
meminfo = {};
|
|
419
|
+
let sysinfo = {};
|
|
420
|
+
try {
|
|
421
|
+
const allvalues = systemData.split("\n"),
|
|
422
|
+
date = allvalues[0], // Setup date
|
|
423
|
+
pcore = +allvalues[1] * 100;
|
|
424
|
+
let index,
|
|
425
|
+
columns,
|
|
426
|
+
isBuff_Cached = false; // This is to check the format version of kernel to find system memory parameter
|
|
427
|
+
for (index = 2; index < (allvalues.length - 1); index++) {
|
|
428
|
+
columns = allvalues[index].split(CPU_PATTERN);
|
|
429
|
+
// setup CPU information
|
|
430
|
+
if (columns[0].indexOf("cpu") === 0) {
|
|
431
|
+
const prevTotal = "prev" + columns[0] + "Total",
|
|
432
|
+
prevIdle = "prev" + columns[0] + "Idle",
|
|
433
|
+
prevUser = "prev" + columns[0] + "User",
|
|
434
|
+
prevkernel = "prev" + columns[0] + "Kernel",
|
|
435
|
+
prevOther = "prev" + columns[0] + "Other";
|
|
436
|
+
if (!systemGroup[prevTotal]) {
|
|
437
|
+
systemGroup[prevTotal] = 0;
|
|
438
|
+
systemGroup[prevIdle] = 0;
|
|
439
|
+
systemGroup[prevUser] = 0;
|
|
440
|
+
systemGroup[prevkernel] = 0;
|
|
441
|
+
systemGroup[prevOther] = 0;
|
|
442
|
+
}
|
|
443
|
+
const user = parseInt(columns[1]),
|
|
444
|
+
nice = parseInt(columns[2]),
|
|
445
|
+
kernel = parseInt(columns[3]),
|
|
446
|
+
idle = parseInt(columns[4]),
|
|
447
|
+
other = nice + parseInt(columns[5]) + parseInt(columns[6]) + parseInt(columns[7]) + parseInt(columns[8]) +
|
|
448
|
+
parseInt(columns[9]) + parseInt(columns[10]),
|
|
449
|
+
subTotal = user + nice + kernel + idle + other;
|
|
450
|
+
|
|
451
|
+
if (!systemGroup.initialExecution) {
|
|
452
|
+
const diffIdle = idle - systemGroup[prevIdle],
|
|
453
|
+
diffUser = user - systemGroup[prevUser],
|
|
454
|
+
diffKernel = kernel - systemGroup[prevkernel],
|
|
455
|
+
diffOther = other - systemGroup[prevOther],
|
|
456
|
+
diffTotal = subTotal - systemGroup[prevTotal];
|
|
457
|
+
|
|
458
|
+
let userModeCpuOccupation = (diffUser/diffTotal) * 100,
|
|
459
|
+
kernelModeCpuOccupation = (diffKernel/diffTotal) * 100,
|
|
460
|
+
otherModeCpuOccupation = (diffOther/diffTotal) * 100,
|
|
461
|
+
overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
|
|
462
|
+
|
|
463
|
+
userModeCpuOccupation < 0 ? (userModeCpuOccupation = 0) : userModeCpuOccupation;
|
|
464
|
+
userModeCpuOccupation > pcore ? (userModeCpuOccupation = pcore) : userModeCpuOccupation;
|
|
465
|
+
kernelModeCpuOccupation < 0 ? (kernelModeCpuOccupation = 0) : kernelModeCpuOccupation;
|
|
466
|
+
kernelModeCpuOccupation > pcore ? (kernelModeCpuOccupation = pcore) : kernelModeCpuOccupation;
|
|
467
|
+
otherModeCpuOccupation < 0 ? (otherModeCpuOccupation = 0) : otherModeCpuOccupation;
|
|
468
|
+
otherModeCpuOccupation > pcore ? (otherModeCpuOccupation = pcore) : otherModeCpuOccupation;
|
|
469
|
+
overallCpuOccupation < 0 ? (overallCpuOccupation = 0) : overallCpuOccupation;
|
|
470
|
+
overallCpuOccupation > pcore ? (overallCpuOccupation = pcore) : overallCpuOccupation;
|
|
471
|
+
|
|
472
|
+
cpuinfo[columns[0]] = {
|
|
473
|
+
"overall": +overallCpuOccupation.toFixed(2),
|
|
474
|
+
"usermode": +userModeCpuOccupation.toFixed(2),
|
|
475
|
+
"kernelmode": +kernelModeCpuOccupation.toFixed(2),
|
|
476
|
+
"others": +otherModeCpuOccupation.toFixed(2)
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
systemGroup[prevIdle] = idle;
|
|
480
|
+
systemGroup[prevUser] = user;
|
|
481
|
+
systemGroup[prevkernel] = kernel;
|
|
482
|
+
systemGroup[prevOther] = other;
|
|
483
|
+
systemGroup[prevTotal] = subTotal;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (!systemGroup.initialExecution) {
|
|
487
|
+
// setup memory infomation
|
|
488
|
+
if (columns[5] && columns[5].indexOf('buff/cache') !== -1) {
|
|
489
|
+
isBuff_Cached = true;
|
|
490
|
+
}
|
|
491
|
+
if (columns[0].indexOf('Mem:') === 0) {
|
|
492
|
+
meminfo['memory'] = !isBuff_Cached ? {
|
|
493
|
+
"total": +columns[1],
|
|
494
|
+
"used": +columns[2],
|
|
495
|
+
"free": +columns[3],
|
|
496
|
+
"shared": +columns[4],
|
|
497
|
+
"buffers": +columns[5],
|
|
498
|
+
"cached": +columns[6]
|
|
499
|
+
} : {
|
|
500
|
+
"total": +columns[1],
|
|
501
|
+
"used": +columns[2],
|
|
502
|
+
"free": +columns[3],
|
|
503
|
+
"shared": +columns[4],
|
|
504
|
+
"buff_cache": +columns[5],
|
|
505
|
+
"available": +columns[6]
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (columns[0].indexOf('-/+') === 0) {
|
|
509
|
+
meminfo['buffers'] = {
|
|
510
|
+
"used": +columns[2],
|
|
511
|
+
"free": +columns[3]
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
if (columns[0].indexOf('Swap:') === 0) {
|
|
515
|
+
meminfo['swap'] = {
|
|
516
|
+
"total": +columns[1],
|
|
517
|
+
"used": +columns[2],
|
|
518
|
+
"free": +columns[3]
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (!systemGroup.initialExecution) {
|
|
524
|
+
sysinfo = {
|
|
525
|
+
"date": date,
|
|
526
|
+
"cpuinfo": cpuinfo,
|
|
527
|
+
"meminfo": meminfo
|
|
528
|
+
};
|
|
529
|
+
_printSystemInfo(sysinfo);
|
|
530
|
+
}
|
|
531
|
+
} catch (err) {
|
|
532
|
+
// do not print error message to user
|
|
533
|
+
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
534
|
+
log.silly("device#systemResource()#_setSystemResouceInfo()", "in try-catch. err:", err.toString());
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function _printSystemInfo(sysinfo) {
|
|
540
|
+
const cpuinfo = sysinfo.cpuinfo,
|
|
541
|
+
meminfo = sysinfo.meminfo,
|
|
542
|
+
cpuinfoTable = new Table(),
|
|
543
|
+
meminfoTable = new Table(),
|
|
544
|
+
dataForCSV = [];
|
|
545
|
+
|
|
546
|
+
// add CPU info to the table
|
|
547
|
+
for (const key in cpuinfo) {
|
|
548
|
+
cpuinfoTable.cell('(%)', key);
|
|
549
|
+
cpuinfoTable.cell('overall', cpuinfo[key].overall);
|
|
550
|
+
cpuinfoTable.cell('usermode', cpuinfo[key].usermode);
|
|
551
|
+
cpuinfoTable.cell('kernelmode', cpuinfo[key].kernelmode);
|
|
552
|
+
cpuinfoTable.cell('others', cpuinfo[key].others);
|
|
553
|
+
cpuinfoTable.newRow();
|
|
554
|
+
|
|
555
|
+
// Add csv array
|
|
556
|
+
const obj = {
|
|
557
|
+
time: sysinfo.date,
|
|
558
|
+
cpu: key,
|
|
559
|
+
overall: cpuinfo[key].overall,
|
|
560
|
+
usermode: cpuinfo[key].usermode,
|
|
561
|
+
kernelmode: cpuinfo[key].kernelmode,
|
|
562
|
+
others: cpuinfo[key].others
|
|
563
|
+
};
|
|
564
|
+
dataForCSV.push(obj);
|
|
565
|
+
}
|
|
566
|
+
// add memoryInfo to the table
|
|
567
|
+
for (const key in meminfo) {
|
|
568
|
+
meminfoTable.cell('(KB)', key);
|
|
569
|
+
meminfoTable.cell('total', meminfo[key].total);
|
|
570
|
+
meminfoTable.cell('used', meminfo[key].used);
|
|
571
|
+
meminfoTable.cell('free', meminfo[key].free);
|
|
572
|
+
meminfoTable.cell('shared', meminfo[key].shared);
|
|
573
|
+
meminfoTable.cell('buff/cache', meminfo[key].buff_cache);
|
|
574
|
+
meminfoTable.cell('available', meminfo[key].available);
|
|
575
|
+
meminfoTable.newRow();
|
|
576
|
+
|
|
577
|
+
const obj = {
|
|
578
|
+
time: sysinfo.date,
|
|
579
|
+
memory: key,
|
|
580
|
+
total: meminfo[key].total,
|
|
581
|
+
used: meminfo[key].used,
|
|
582
|
+
free: meminfo[key].free,
|
|
583
|
+
shared: meminfo[key].shared,
|
|
584
|
+
"buff/cache": meminfo[key].buff_cache,
|
|
585
|
+
available: meminfo[key].available
|
|
586
|
+
};
|
|
587
|
+
dataForCSV.push(obj);
|
|
588
|
+
}
|
|
589
|
+
// write CSV file if user gives --save option
|
|
590
|
+
if (options.save && options.csvPath) {
|
|
591
|
+
// write csv file
|
|
592
|
+
// when openMode is false, the new csv file will be created and "Header" add to the file
|
|
593
|
+
let openMode = false;
|
|
594
|
+
if (fs.existsSync(options.csvPath)) {
|
|
595
|
+
openMode = true;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const csvWriter = createCsvWriter({
|
|
599
|
+
path: options.csvPath,
|
|
600
|
+
header: [
|
|
601
|
+
{id: 'time', title: 'time'},
|
|
602
|
+
{id: 'cpu', title: '(%)'},
|
|
603
|
+
{id: 'overall', title: 'overall'},
|
|
604
|
+
{id: 'usermode', title: 'usermode'},
|
|
605
|
+
{id: 'kernelmode', title: 'kernelmode'},
|
|
606
|
+
{id: 'others', title: 'others'},
|
|
607
|
+
{id: 'memory', title: '(KB)'},
|
|
608
|
+
{id: 'total', title: 'total'},
|
|
609
|
+
{id: 'used', title: 'used'},
|
|
610
|
+
{id: 'free', title: 'free'},
|
|
611
|
+
{id: 'shared', title: 'shared'},
|
|
612
|
+
{id: 'buff/cache', title: 'buff/cache'},
|
|
613
|
+
{id: 'available', title: 'available'}
|
|
614
|
+
],
|
|
615
|
+
append: openMode
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
csvWriter
|
|
619
|
+
.writeRecords(dataForCSV)
|
|
620
|
+
.then(function() {
|
|
621
|
+
log.silly("device#systemResource()#_printSystemInfo()", "CSV file updated");
|
|
622
|
+
// csv file has been created at first
|
|
623
|
+
if (openMode === false) {
|
|
624
|
+
const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
|
|
625
|
+
console.log(resultTxt);
|
|
626
|
+
}
|
|
627
|
+
__printTable();
|
|
628
|
+
}).catch(function(err) {
|
|
629
|
+
return setImmediate(next, errHndl.getErrMsg(err));
|
|
630
|
+
});
|
|
631
|
+
} else {
|
|
632
|
+
__printTable();
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function __printTable() {
|
|
636
|
+
console.log(sysinfo.date + "\n");
|
|
637
|
+
console.log(cpuinfoTable.toString());
|
|
638
|
+
console.log(meminfoTable.toString());
|
|
639
|
+
console.log("=================================================================");
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
/**
|
|
644
|
+
* Get running apps and services CPUs and memories usage
|
|
645
|
+
* @property options {String} device, interval
|
|
646
|
+
*/
|
|
647
|
+
processResource: function(options, next) {
|
|
648
|
+
if (typeof next !== 'function') {
|
|
649
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
const processGroup = {};
|
|
653
|
+
processGroup.initialExecution = true;
|
|
654
|
+
options = options || {};
|
|
655
|
+
options.destinationPath = "";
|
|
656
|
+
options.fileName = "";
|
|
657
|
+
options.csvPath = "";
|
|
658
|
+
|
|
659
|
+
async.series([
|
|
660
|
+
_createOutputPath,
|
|
661
|
+
_makeSession,
|
|
662
|
+
_getProcessResouceInfo
|
|
663
|
+
], function(err, results) {
|
|
664
|
+
log.silly("device#processResource()", "err:", err, ", results:", results);
|
|
665
|
+
next(err);
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
function _createOutputPath(next) {
|
|
669
|
+
if (options.save && options.csvPath === "") {
|
|
670
|
+
makeCSVOutputPath(options, next);
|
|
671
|
+
} else {
|
|
672
|
+
next();
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function _makeSession(next) {
|
|
677
|
+
makeSession(options, next);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function _getProcessResouceInfo(next) {
|
|
681
|
+
log.info("device#processResource()#_getProcessResouceInfo()");
|
|
682
|
+
|
|
683
|
+
let timerId;
|
|
684
|
+
if (!options.interval) {
|
|
685
|
+
// If interval option is not given, call timer logic 2 times
|
|
686
|
+
const defaultRepeat = 2;
|
|
687
|
+
let repeatCount = 0;
|
|
688
|
+
try {
|
|
689
|
+
timerId = setTimeout(function repeat() {
|
|
690
|
+
if (repeatCount < defaultRepeat) {
|
|
691
|
+
_callProcessInfoCmd();
|
|
692
|
+
repeatCount++;
|
|
693
|
+
timerId = setTimeout(repeat, 1000);
|
|
694
|
+
} else {
|
|
695
|
+
clearTimeout(timerId);
|
|
696
|
+
return next();
|
|
697
|
+
}
|
|
698
|
+
}, 100);
|
|
699
|
+
} catch (err) {
|
|
700
|
+
log.silly("device#systemResource()#_getProcessResouceInfo()", "one timer. err:", err.toString());
|
|
701
|
+
clearTimeout(timerId);
|
|
702
|
+
// ignore timer logic error
|
|
703
|
+
return next();
|
|
704
|
+
}
|
|
705
|
+
} else {
|
|
706
|
+
try {
|
|
707
|
+
// when interval option is given, print initial data at first
|
|
708
|
+
const defaultRepeat = 1;
|
|
709
|
+
let repeatCount = 0;
|
|
710
|
+
timerId = setTimeout(function repeat() {
|
|
711
|
+
if (repeatCount < defaultRepeat) {
|
|
712
|
+
_callProcessInfoCmd();
|
|
713
|
+
repeatCount++;
|
|
714
|
+
timerId = setTimeout(repeat, 1000);
|
|
715
|
+
} else {
|
|
716
|
+
_callProcessInfoCmd();
|
|
717
|
+
timerId = setTimeout(repeat, options.interval * 1000);
|
|
718
|
+
}
|
|
719
|
+
}, 100);
|
|
720
|
+
} catch (err) {
|
|
721
|
+
log.silly("device#systemResource()#_getProcessResouceInfo()", "repeat timer. err:", err.toString());
|
|
722
|
+
clearTimeout(timerId);
|
|
723
|
+
// ignore timer logic error
|
|
724
|
+
return next();
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function _callProcessInfoCmd() {
|
|
730
|
+
log.info("device#processResource()#_callProcessInfoCmd()");
|
|
731
|
+
|
|
732
|
+
const wStream = new streamBuffers.WritableStreamBuffer();
|
|
733
|
+
const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep "cpu *" /proc/stat | sed "1d" | awk \'{for (i=0;i<NR;i++){if (i==NR-1){totalSum+=$2+$3+$4+$5+$6+$7+$8+$9+$10+$11;idleSum+=$5}}} END { for (i=0;i<NR;i++){if (i==NR-1){print idleSum;print totalSum}}}\'; cat /proc/[0-9]*/stat; echo \'psList\' ; ps -ax | sed "1d" | awk \'/ /{print $1 "\t"$5}\'; echo \'serviceStringStart\'; ls /media/developer/apps/usr/palm/services ; echo \'serviceStringEnd\'; luna-send-pub -n 1 -f luna://com.webos.applicationManager/dev/running \'{}\'; grep -c ^processor /proc/cpuinfo';
|
|
734
|
+
try {
|
|
735
|
+
options.session.run(cmd, null, wStream, null, function(err) {
|
|
736
|
+
if (err) {
|
|
737
|
+
// do not print error message to user
|
|
738
|
+
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
739
|
+
log.silly("device#processResource()#_callProcessInfoCmd()", "ssh call. err:", err.toString());
|
|
740
|
+
return next(null);
|
|
741
|
+
} else {
|
|
742
|
+
const result = wStream.getContentsAsString();
|
|
743
|
+
_setProcessInfo(result);
|
|
744
|
+
processGroup.initialExecution = false;
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
} catch (err) {
|
|
748
|
+
// do not print error message to user
|
|
749
|
+
// when user press Ctrl + C , the ssh connection is not completed, it makes error
|
|
750
|
+
log.silly("device#processResource()#_callProcessInfoCmd()", "in try-catch. err:", err.toString());
|
|
751
|
+
return next(null);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function _setProcessInfo(processData) {
|
|
756
|
+
log.info("device#processResource()#_setProcessInfo()");
|
|
757
|
+
const PROC_GROUP_INFO_PATTERN = /\s+/;
|
|
758
|
+
try {
|
|
759
|
+
// Intialize temporary groups with values
|
|
760
|
+
const processList = ["Service", "System"],
|
|
761
|
+
groupProcessList = [],
|
|
762
|
+
tempProcGrps = {},
|
|
763
|
+
arrActiveServices = [];
|
|
764
|
+
// loop through all the categories and create groups
|
|
765
|
+
for (let i = 0; i < processList.length; i++) {
|
|
766
|
+
tempProcGrps[processList[i]] = {};
|
|
767
|
+
tempProcGrps[processList[i]]["pid"] = 0;
|
|
768
|
+
tempProcGrps[processList[i]]["cputime"] = 0;
|
|
769
|
+
tempProcGrps[processList[i]]["RSS"] = 0;
|
|
770
|
+
tempProcGrps[processList[i]]["pmem"] = 0;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
const processinfo = [],
|
|
774
|
+
groupProcessinfo = [], // only for dev app & service info
|
|
775
|
+
allvalues = processData.split("\n"),
|
|
776
|
+
otherList = [],
|
|
777
|
+
date = allvalues[0],
|
|
778
|
+
lastIndex = allvalues.length;
|
|
779
|
+
|
|
780
|
+
allvalues.splice(lastIndex - 1, 1);
|
|
781
|
+
const pcore = +allvalues[allvalues.length-1] * 100;
|
|
782
|
+
/* memCol[1] from 'grep "MemTotal *" /proc/meminfo' is not used */
|
|
783
|
+
let totalRAM = 0;
|
|
784
|
+
const idleCPUtime = +allvalues[1],
|
|
785
|
+
totalCPUtime = +allvalues[2],
|
|
786
|
+
psListStartIndex = allvalues.indexOf("psList", 2),
|
|
787
|
+
serviceStartIndex = allvalues.indexOf("serviceStringStart", 2), // from where to start (2)
|
|
788
|
+
serviceEndIndex = allvalues.indexOf("serviceStringEnd", 2); // from where to start (2)
|
|
789
|
+
|
|
790
|
+
const arryInstalledServices = [];
|
|
791
|
+
for (let i = serviceStartIndex + 1; i < serviceEndIndex; i++) {
|
|
792
|
+
arryInstalledServices[i-serviceStartIndex-1] = allvalues[i];
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// get processid of external service on ps list
|
|
796
|
+
let arrayCount = 0;
|
|
797
|
+
for (let k = psListStartIndex+1 ; k < serviceStartIndex ;k++) {
|
|
798
|
+
const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
|
|
799
|
+
pid = parseInt(columns[0]),
|
|
800
|
+
procname = columns[1].trim();
|
|
801
|
+
|
|
802
|
+
if (arryInstalledServices.indexOf(procname) !== -1) {
|
|
803
|
+
const ObjService = {
|
|
804
|
+
"processid": pid,
|
|
805
|
+
"id": procname
|
|
806
|
+
};
|
|
807
|
+
arrActiveServices[arrayCount++] = ObjService;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
const appStartIndex = allvalues.indexOf("{", 2); // From where to start (2)
|
|
812
|
+
// some times specific platform does not gives list of running info itself then appStartIndex becomes -1
|
|
813
|
+
if (appStartIndex < 0) {
|
|
814
|
+
// do not print error message to user
|
|
815
|
+
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
816
|
+
log.silly("device#processResource()#_setProcessInfo()", "running app list is invalid");
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const appEndIndex = allvalues.length-1;
|
|
820
|
+
let strActiveApps = "",
|
|
821
|
+
objActiveApps;
|
|
822
|
+
for (let i = appStartIndex; i < appEndIndex; i++) {
|
|
823
|
+
strActiveApps += allvalues[i];
|
|
824
|
+
}
|
|
825
|
+
try {
|
|
826
|
+
objActiveApps = JSON.parse(strActiveApps);
|
|
827
|
+
} catch (err) {
|
|
828
|
+
// do not print error message to user
|
|
829
|
+
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
830
|
+
log.silly("device#processResource()#_setProcessInfo()", "active app parsing. err:", err.toString());
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
if (objActiveApps.returnValue === false) {
|
|
835
|
+
const errValue = objActiveApps["errorText"] || "running app list is invalid";
|
|
836
|
+
return next(errHndl.getErrMsg("FAILED_CALL_LUNA", errValue, null, "com.webos.applicationManager"));
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const arrActiveApps = objActiveApps["running"],
|
|
840
|
+
groupObjList = {};
|
|
841
|
+
|
|
842
|
+
// 1st row is date, 2nd row is total CPU time and last row is total RAM(Meminfo) hence ignore it
|
|
843
|
+
// check process group info until "psList" string
|
|
844
|
+
for (let k = 3; k < psListStartIndex; k++) {
|
|
845
|
+
const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
|
|
846
|
+
procname = columns[1].trim().split(/.*\(|\)/gi)[1],
|
|
847
|
+
grpname = _getProcessGrp(procname),
|
|
848
|
+
pid = parseInt(columns[0]),
|
|
849
|
+
pname = procname,
|
|
850
|
+
ppid = parseInt(columns[3]),
|
|
851
|
+
cputime = parseInt(columns[13]) + parseInt(columns[14]),
|
|
852
|
+
rss = parseInt(columns[23]) * 4,
|
|
853
|
+
pmem = (rss * 100);
|
|
854
|
+
// sum total used RSS
|
|
855
|
+
totalRAM += rss;
|
|
856
|
+
if (grpname === "Other") {
|
|
857
|
+
const objOther = {};
|
|
858
|
+
objOther["pid"] = pid;
|
|
859
|
+
objOther["pname"] = pname;
|
|
860
|
+
objOther["ppid"] = ppid;
|
|
861
|
+
objOther["cputime"] = cputime;
|
|
862
|
+
objOther["RSS"] = rss;
|
|
863
|
+
objOther["pmem"] = pmem;
|
|
864
|
+
otherList.push(objOther);
|
|
865
|
+
} else {
|
|
866
|
+
tempProcGrps[grpname]["pid"] = pid;
|
|
867
|
+
tempProcGrps[grpname]["cputime"] += cputime;
|
|
868
|
+
tempProcGrps[grpname]["RSS"] += rss;
|
|
869
|
+
tempProcGrps[grpname]["pmem"] += pmem;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
// get the Children of Service
|
|
873
|
+
for (const k in tempProcGrps) {
|
|
874
|
+
const attrName = k;
|
|
875
|
+
if (attrName === "System") {
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
const objOther = tempProcGrps[k];
|
|
879
|
+
for (let i = 0; i < otherList.length; i++) {
|
|
880
|
+
if (objOther["pid"] !== otherList[i]["ppid"]) {
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// this variable will mantain the aggregate pcpuVal of Service + dynamic apps
|
|
887
|
+
let aggcpuVal = 0;
|
|
888
|
+
// get the Web App processes data
|
|
889
|
+
if (arrActiveApps.length === 0) {
|
|
890
|
+
// get only the existing categories(3) if no running apps.
|
|
891
|
+
// dispose all the existing process variables
|
|
892
|
+
for (const name in processGroup) {
|
|
893
|
+
// if propertyName starts with "prev_" then dispose it
|
|
894
|
+
if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
if (name.indexOf("prev_app_") >= 0) {
|
|
898
|
+
processGroup[name] = undefined;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
} else {
|
|
902
|
+
// loop through each of the running apps
|
|
903
|
+
// in loop - Check if app is newly running app (or) already existing running app
|
|
904
|
+
for (let j = 0; j < arrActiveApps.length; j++) {
|
|
905
|
+
const objActApp = arrActiveApps[j],
|
|
906
|
+
webprocId = objActApp["webprocessid"],
|
|
907
|
+
procId = objActApp["processid"],
|
|
908
|
+
displayId = objActApp["displayId"] || 0;
|
|
909
|
+
let processId;
|
|
910
|
+
if (webprocId !== "" && webprocId !== undefined && webprocId !== "undefined") {
|
|
911
|
+
processId = webprocId;
|
|
912
|
+
} else if (procId !== "" && procId !== undefined && procId !== "undefined") {
|
|
913
|
+
processId = procId;
|
|
914
|
+
} else {
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
const prevcpuTime = "prev_app_" + processId + "cputime",
|
|
919
|
+
appid = parseInt(processId);
|
|
920
|
+
let pcputime = 0;
|
|
921
|
+
// get the cputime from otherList
|
|
922
|
+
for (let l = 0; l < otherList.length; l++) {
|
|
923
|
+
if (otherList[l]["pid"] !== appid) {
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
pcputime = otherList[l]["cputime"];
|
|
927
|
+
if (!processGroup[prevcpuTime]) {
|
|
928
|
+
processGroup[prevcpuTime] = pcputime;
|
|
929
|
+
break;
|
|
930
|
+
}
|
|
931
|
+
let webpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
|
|
932
|
+
// restrict showing the negative % values by making lowest to be zero.
|
|
933
|
+
if (webpcpuval < 0 || webpcpuval === undefined || isNaN(webpcpuval)) webpcpuval = 0;
|
|
934
|
+
aggcpuVal += webpcpuval;
|
|
935
|
+
const groupListAppKey = objActApp["id"]+ "-" + appid;
|
|
936
|
+
groupObjList[groupListAppKey] = {
|
|
937
|
+
"id": objActApp["id"],
|
|
938
|
+
"pid": appid,
|
|
939
|
+
"cpu": webpcpuval,
|
|
940
|
+
"memory": {
|
|
941
|
+
"size": otherList[l]["RSS"],
|
|
942
|
+
"percent": otherList[l]["pmem"].toFixed(2)
|
|
943
|
+
},
|
|
944
|
+
"displayId": displayId
|
|
945
|
+
};
|
|
946
|
+
processGroup[prevcpuTime] = pcputime;
|
|
947
|
+
otherList.splice(l, 1);
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
// get the service processes data
|
|
953
|
+
if (arrActiveServices.length === 0) {
|
|
954
|
+
// get only the existing categories(3) if no running apps.
|
|
955
|
+
// dispose all the existing process variables
|
|
956
|
+
for (const name in processGroup) {
|
|
957
|
+
// if propertyName starts with "prev_" then dispose it
|
|
958
|
+
if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (name.indexOf("prev_svc_") >= 0) {
|
|
962
|
+
processGroup[name] = undefined;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
} else {
|
|
966
|
+
// loop through each of the running apps
|
|
967
|
+
// in loop - Check if app is newly running app (or) already existing running app
|
|
968
|
+
for (let j = 0; j < arrActiveServices.length; j++) {
|
|
969
|
+
const objActService = arrActiveServices[j],
|
|
970
|
+
processId = objActService["processid"],
|
|
971
|
+
prevcpuTime = "prev_svc_" + processId + "cputime",
|
|
972
|
+
appid = parseInt(processId);
|
|
973
|
+
let pcputime = 0;
|
|
974
|
+
// get the cputime from otherList
|
|
975
|
+
for (let l = 0; l < otherList.length; l++) {
|
|
976
|
+
if (otherList[l]["pid"] !== appid) {
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
979
|
+
pcputime = otherList[l]["cputime"];
|
|
980
|
+
if (!processGroup[prevcpuTime]) {
|
|
981
|
+
processGroup[prevcpuTime] = pcputime;
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
984
|
+
let svcpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
|
|
985
|
+
// restrict showing the negative % values by making lowest to be zero.
|
|
986
|
+
if (svcpcpuval < 0 || svcpcpuval === undefined || isNaN(svcpcpuval)) svcpcpuval = 0;
|
|
987
|
+
aggcpuVal+= svcpcpuval;
|
|
988
|
+
groupObjList[objActService["id"]] = {
|
|
989
|
+
"pid": appid,
|
|
990
|
+
"cpu": svcpcpuval,
|
|
991
|
+
"memory": {
|
|
992
|
+
"size": otherList[l]["RSS"],
|
|
993
|
+
"percent": otherList[l]["pmem"].toFixed(2)
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
processGroup[prevcpuTime] = pcputime;
|
|
997
|
+
otherList.splice(l, 1);
|
|
998
|
+
break;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
// get the remaining System Category processes
|
|
1003
|
+
for (let i = 0; i < otherList.length; i++) {
|
|
1004
|
+
tempProcGrps["System"]["pid"] = otherList[i]["pid"];
|
|
1005
|
+
tempProcGrps["System"]["cputime"]+= otherList[i]["cputime"];
|
|
1006
|
+
tempProcGrps["System"]["RSS"]+= otherList[i]["RSS"];
|
|
1007
|
+
tempProcGrps["System"]["pmem"]+= otherList[i]["pmem"];
|
|
1008
|
+
}
|
|
1009
|
+
if (!processGroup.initialExecution) {
|
|
1010
|
+
const diffIdle = idleCPUtime - processGroup.prevIdlecputime,
|
|
1011
|
+
diffTotal = totalCPUtime - processGroup.prevTotalcputime,
|
|
1012
|
+
overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
|
|
1013
|
+
// assign all the values to return Object
|
|
1014
|
+
for (const key in tempProcGrps) {
|
|
1015
|
+
const processName = key;
|
|
1016
|
+
let tempPcpuval = 0;
|
|
1017
|
+
if (processName === "Service") {
|
|
1018
|
+
tempPcpuval = ((tempProcGrps[processName]["cputime"] - processGroup.prevServicecputime) * 100/diffTotal);
|
|
1019
|
+
}
|
|
1020
|
+
// restrict showing the negative % values by making lowest to be zero.
|
|
1021
|
+
if (tempPcpuval < 0 || tempPcpuval === undefined || isNaN(tempPcpuval)) tempPcpuval = 0;
|
|
1022
|
+
aggcpuVal += tempPcpuval;
|
|
1023
|
+
// system = overallCpuOccupation - (Service used + dynamic apps used);
|
|
1024
|
+
if (processName === "System") {
|
|
1025
|
+
tempPcpuval = overallCpuOccupation - aggcpuVal;
|
|
1026
|
+
}
|
|
1027
|
+
// restrict Negative/peak values due to cores fluctuation
|
|
1028
|
+
tempPcpuval < 0 ? (tempPcpuval = 0) : tempPcpuval;
|
|
1029
|
+
tempPcpuval > pcore ? (tempPcpuval = pcore) : tempPcpuval;
|
|
1030
|
+
tempProcGrps[processName]["pmem"] /= totalRAM;
|
|
1031
|
+
const procinfo = {
|
|
1032
|
+
"pid": tempProcGrps[processName]["pid"],
|
|
1033
|
+
"appid": processName,
|
|
1034
|
+
"cpu": parseFloat(tempPcpuval.toFixed(2)),
|
|
1035
|
+
"memory": {
|
|
1036
|
+
"size": tempProcGrps[processName]["RSS"],
|
|
1037
|
+
"percent": tempProcGrps[processName]["pmem"].toFixed(2)
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
processinfo.push(procinfo);
|
|
1041
|
+
}
|
|
1042
|
+
// push the calculated groups into list
|
|
1043
|
+
for (const propertyName in groupObjList) {
|
|
1044
|
+
if (!Object.prototype.hasOwnProperty.call(groupObjList, propertyName)) {
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const procObj = groupObjList[propertyName];
|
|
1049
|
+
let pcpuval = parseFloat(procObj["cpu"].toFixed(2));
|
|
1050
|
+
if (pcpuval === undefined || isNaN(pcpuval)) {
|
|
1051
|
+
pcpuval = 0;
|
|
1052
|
+
}
|
|
1053
|
+
procObj["memory"]["percent"] /= totalRAM;
|
|
1054
|
+
const procinfo = {
|
|
1055
|
+
"pid": procObj["pid"],
|
|
1056
|
+
"appid": procObj["id"] || propertyName,
|
|
1057
|
+
"cpu": pcpuval,
|
|
1058
|
+
"memory": {
|
|
1059
|
+
"size": procObj["memory"]["size"],
|
|
1060
|
+
"percent": parseFloat(procObj["memory"]["percent"]).toFixed(2)
|
|
1061
|
+
},
|
|
1062
|
+
"displayId": procObj["displayId"]
|
|
1063
|
+
};
|
|
1064
|
+
|
|
1065
|
+
processinfo.push(procinfo);
|
|
1066
|
+
// copy only app and service info to group for printing
|
|
1067
|
+
groupProcessinfo.push(procinfo);
|
|
1068
|
+
|
|
1069
|
+
if (processinfo.indexOf(propertyName) < 0) {
|
|
1070
|
+
processList.push(propertyName);
|
|
1071
|
+
groupProcessList.push(propertyName);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
processGroup.prevIdlecputime = idleCPUtime;
|
|
1076
|
+
processGroup.prevTotalcputime = totalCPUtime;
|
|
1077
|
+
processGroup.prevServicecputime = tempProcGrps["Service"]["cputime"];
|
|
1078
|
+
|
|
1079
|
+
if (!processGroup.initialExecution) {
|
|
1080
|
+
const processgrpinfo = {
|
|
1081
|
+
"date": date,
|
|
1082
|
+
"processinfo": groupProcessinfo,
|
|
1083
|
+
"processList": groupProcessList
|
|
1084
|
+
};
|
|
1085
|
+
_printProcessList(processgrpinfo);
|
|
1086
|
+
}
|
|
1087
|
+
} catch (err) {
|
|
1088
|
+
// do not print error message to user
|
|
1089
|
+
// when user press Ctrl + C , the ssh cmd data is not completed, it makes error
|
|
1090
|
+
log.silly("device#processResource()#_setProcessInfo()", "in try-catch. err:", err.toString());
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
function _getProcessGrp(pname) {
|
|
1096
|
+
let group;
|
|
1097
|
+
switch (pname) {
|
|
1098
|
+
case 'ls-hubd':
|
|
1099
|
+
group = 'Service'; break;
|
|
1100
|
+
default:
|
|
1101
|
+
group = 'Other'; // it could be children of above categories or System
|
|
1102
|
+
}
|
|
1103
|
+
return group;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
function _printProcessList(processgrpinfo) {
|
|
1107
|
+
log.info("device#processResource()#_printProcessList()", JSON.stringify(processgrpinfo));
|
|
1108
|
+
|
|
1109
|
+
const processinfo = processgrpinfo.processinfo,
|
|
1110
|
+
processinfoTable = new Table();
|
|
1111
|
+
|
|
1112
|
+
let found = false;
|
|
1113
|
+
if (options.id) {
|
|
1114
|
+
processinfo.forEach(function(process) {
|
|
1115
|
+
if (options.id === process.appid) {
|
|
1116
|
+
found = true;
|
|
1117
|
+
}
|
|
1118
|
+
});
|
|
1119
|
+
if (found === false) {
|
|
1120
|
+
// print guide message to user
|
|
1121
|
+
console.log("<" + options.id + ">" + " is not running. Please launch the app or service.");
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
if (processgrpinfo.processList.length === 0) {
|
|
1126
|
+
// print guide message to user
|
|
1127
|
+
console.log("There are no running apps or services. Please launch any app or service.");
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// add process list to table
|
|
1132
|
+
const dataForCSV = [];
|
|
1133
|
+
if (Array.isArray(processinfo)) {
|
|
1134
|
+
processinfo.forEach(function(process) {
|
|
1135
|
+
// if user gives ID, print only the ID's information
|
|
1136
|
+
if (options.id && options.id !== process.appid) {
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
processinfoTable.cell('PID', process.pid);
|
|
1140
|
+
processinfoTable.cell('ID', process.appid);
|
|
1141
|
+
processinfoTable.cell('DISPLAY ID', process.displayId);
|
|
1142
|
+
processinfoTable.cell('CPU(%)', process.cpu);
|
|
1143
|
+
|
|
1144
|
+
const meminfo = process.memory;
|
|
1145
|
+
processinfoTable.cell('MEMORY(%)', meminfo.percent);
|
|
1146
|
+
processinfoTable.cell('MEMORY(KB)', meminfo.size);
|
|
1147
|
+
processinfoTable.newRow();
|
|
1148
|
+
|
|
1149
|
+
// add data object
|
|
1150
|
+
const obj = {
|
|
1151
|
+
time: processgrpinfo.date,
|
|
1152
|
+
pid: process.pid,
|
|
1153
|
+
id: process.appid,
|
|
1154
|
+
displayId: process.displayId,
|
|
1155
|
+
cpu: process.cpu,
|
|
1156
|
+
memory: meminfo.percent,
|
|
1157
|
+
memory_size: meminfo.size
|
|
1158
|
+
};
|
|
1159
|
+
dataForCSV.push(obj);
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
// write CSV file if user gives --save option
|
|
1163
|
+
if (options.save && options.csvPath) {
|
|
1164
|
+
// write csv file
|
|
1165
|
+
// when openMode is false, the new csv file will be created and "Header" add to the file
|
|
1166
|
+
let openMode = false;
|
|
1167
|
+
if (fs.existsSync(options.csvPath)) {
|
|
1168
|
+
openMode = true;
|
|
1169
|
+
}
|
|
1170
|
+
const csvWriter = createCsvWriter({
|
|
1171
|
+
path: options.csvPath,
|
|
1172
|
+
header: [
|
|
1173
|
+
{id: 'time', title: 'TIME'},
|
|
1174
|
+
{id: 'pid', title: 'PID'},
|
|
1175
|
+
{id: 'id', title: 'ID'},
|
|
1176
|
+
{id: 'displayId', title: 'DISPLAY ID'},
|
|
1177
|
+
{id: 'cpu', title: 'CPU(%)'},
|
|
1178
|
+
{id: 'memory', title: 'MEMORY(%)'},
|
|
1179
|
+
{id: 'memory_size', title: 'MEMORY(KB)'}
|
|
1180
|
+
],
|
|
1181
|
+
append: openMode
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
csvWriter
|
|
1185
|
+
.writeRecords(dataForCSV)
|
|
1186
|
+
.then(function() {
|
|
1187
|
+
log.silly("device#processResource()#_printProcessList()", "CSV file updated");
|
|
1188
|
+
// csv file has been created at first
|
|
1189
|
+
if (openMode === false) {
|
|
1190
|
+
const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
|
|
1191
|
+
console.log(resultTxt);
|
|
1192
|
+
}
|
|
1193
|
+
__printTable();
|
|
1194
|
+
}).catch(function(err) {
|
|
1195
|
+
return setImmediate(next, errHndl.getErrMsg(err));
|
|
1196
|
+
});
|
|
1197
|
+
} else {
|
|
1198
|
+
__printTable();
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
function __printTable() {
|
|
1202
|
+
// Print resullt to terminal
|
|
1203
|
+
console.log(processgrpinfo.date + "\n");
|
|
1204
|
+
console.log(processinfoTable.toString());
|
|
1205
|
+
console.log("======================================================================");
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
},
|
|
1209
|
+
/**
|
|
1210
|
+
* get screen capture of the given device
|
|
1211
|
+
* @property options {String} device, display, outputPath
|
|
1212
|
+
*/
|
|
1213
|
+
captureScreen: function(options, next) {
|
|
1214
|
+
if (typeof next !== 'function') {
|
|
1215
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
1216
|
+
}
|
|
1217
|
+
options = options || {};
|
|
1218
|
+
async.series([
|
|
1219
|
+
_makeSession,
|
|
1220
|
+
_makeCaptureOption,
|
|
1221
|
+
_captureScreenFile,
|
|
1222
|
+
_copyFileToLocal
|
|
1223
|
+
], function(err, results) {
|
|
1224
|
+
log.silly("device#captureScreen()", "err:", err, ", results:", results);
|
|
1225
|
+
const resultTxt = "Create " + chalk.green(options.captureFileName) + " to " + options.destinationPath +"\nSuccess";
|
|
1226
|
+
|
|
1227
|
+
// clean up /tmp/aresCapture directory in target device
|
|
1228
|
+
if (options.createdTmpDir) {
|
|
1229
|
+
_removeTmpDir(function finish(removeErr) {
|
|
1230
|
+
next(err ? err : removeErr, {msg: resultTxt});
|
|
1231
|
+
});
|
|
1232
|
+
} else {
|
|
1233
|
+
next(err, {msg: resultTxt});
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
|
|
1237
|
+
function _makeSession(next) {
|
|
1238
|
+
makeSession(options, next);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
function _makeCaptureOption(next) {
|
|
1242
|
+
log.info("device#captureScreen()#_makeCaptureOption()");
|
|
1243
|
+
|
|
1244
|
+
const captureFormat = "PNG", // PNG is default format
|
|
1245
|
+
fileNameSeperator = "_";
|
|
1246
|
+
|
|
1247
|
+
let captureFileName = options.session.target.name + "_" + "display" + options.display + "_",
|
|
1248
|
+
destinationPath = "";
|
|
1249
|
+
|
|
1250
|
+
if (options.outputPath === null) {
|
|
1251
|
+
captureFileName += createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
|
|
1252
|
+
destinationPath = path.resolve('.');
|
|
1253
|
+
} else {
|
|
1254
|
+
// get directory path, file path, file Extenstion from given path
|
|
1255
|
+
const parseDirPath = path.dirname(options.outputPath),
|
|
1256
|
+
parseBase = path.parse(options.outputPath).base;
|
|
1257
|
+
|
|
1258
|
+
let parseExt = path.parse(options.outputPath).ext;
|
|
1259
|
+
|
|
1260
|
+
parseExt = parseExt.split('.').pop();
|
|
1261
|
+
log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
|
|
1262
|
+
+ " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
|
|
1263
|
+
|
|
1264
|
+
// if specific path is given
|
|
1265
|
+
if (parseBase) {
|
|
1266
|
+
captureFileName = parseBase;
|
|
1267
|
+
destinationPath = path.resolve(parseDirPath);
|
|
1268
|
+
// parseBase is [filename].[ext] format
|
|
1269
|
+
if (parseExt === "") {
|
|
1270
|
+
// paresBase does not have file extesntion, add .png format
|
|
1271
|
+
captureFileName += "." + captureFormat.toLowerCase();
|
|
1272
|
+
} else if (parseExt !== "png" && parseExt !== "bmp" && parseExt !== "jpg") {
|
|
1273
|
+
return next(errHndl.getErrMsg("INVALID_CAPTURE_FORMAT"));
|
|
1274
|
+
}
|
|
1275
|
+
} else if (parseDirPath) {
|
|
1276
|
+
// the path has only "directory" without parseBase
|
|
1277
|
+
// for example, "ares-device -c /"
|
|
1278
|
+
captureFileName = createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
|
|
1279
|
+
destinationPath = path.resolve(parseDirPath);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
options.captureFormat = captureFormat;
|
|
1284
|
+
options.captureFileName = captureFileName;
|
|
1285
|
+
options.captureDirPath = "/tmp/aresCapture/";
|
|
1286
|
+
options.sourcePath = options.captureDirPath + captureFileName;
|
|
1287
|
+
options.destinationPath = destinationPath;
|
|
1288
|
+
options.ignore = true;
|
|
1289
|
+
options.silent = true;
|
|
1290
|
+
|
|
1291
|
+
next();
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
function _captureScreenFile(next) {
|
|
1295
|
+
log.info("device#captureScreen()#_captureScreenFile()");
|
|
1296
|
+
const cmd = "/bin/mkdir -p " + options.captureDirPath;
|
|
1297
|
+
options.session.run(cmd, null, null, null, function(err) {
|
|
1298
|
+
if (err) {
|
|
1299
|
+
return setImmediate(next, err);
|
|
1300
|
+
} else {
|
|
1301
|
+
options.createdTmpDir = true;
|
|
1302
|
+
const target = options.session.getDevice(),
|
|
1303
|
+
addr = target.lunaAddr.captureCompositorOutput,
|
|
1304
|
+
param = {
|
|
1305
|
+
// luna param
|
|
1306
|
+
subscribe: false,
|
|
1307
|
+
output: options.sourcePath,
|
|
1308
|
+
format: options.captureFormat,
|
|
1309
|
+
displayId: options.display
|
|
1310
|
+
};
|
|
1311
|
+
|
|
1312
|
+
luna.send(options, addr, param, function(lineObj, next) {
|
|
1313
|
+
if (lineObj.returnValue) {
|
|
1314
|
+
log.verbose("device#captureScreen()#_captureScreenFile()","Capture file in target:" + lineObj.output);
|
|
1315
|
+
next(null, {});
|
|
1316
|
+
} else {
|
|
1317
|
+
log.verbose("device#captureScreen()#_captureScreenFile()", "failure");
|
|
1318
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
1319
|
+
}
|
|
1320
|
+
}, next);
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
function _copyFileToLocal(next) {
|
|
1326
|
+
log.info("device#captureScreen()#_copyFileToLocal()");
|
|
1327
|
+
pullLib.pull(options.sourcePath, options.destinationPath, options, next);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
function _removeTmpDir(next) {
|
|
1331
|
+
log.info("device#captureScreen()#_removeTmpDir()");
|
|
1332
|
+
const cmd = '/bin/rm -rf ' + options.captureDirPath;
|
|
1333
|
+
options.session.run(cmd, null, null, null, function(err) {
|
|
1334
|
+
if (err) {
|
|
1335
|
+
return setImmediate(next, err);
|
|
1336
|
+
} else {
|
|
1337
|
+
next();
|
|
1338
|
+
}
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
|
|
1344
|
+
function makeSession(options, next) {
|
|
1345
|
+
options.nReplies = 1; // -n 1
|
|
1346
|
+
if (!options.session) {
|
|
1347
|
+
log.info("device#makeSession()", "need to make new session");
|
|
1348
|
+
const printTarget = true;
|
|
1349
|
+
options.session = new novacom.Session(options.device, printTarget, next);
|
|
1350
|
+
} else {
|
|
1351
|
+
log.info("device#makeSession()", "already exist session");
|
|
1352
|
+
next();
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
function makeCSVOutputPath(options, next) {
|
|
1357
|
+
const csvFormat = "csv", // csv is default format
|
|
1358
|
+
fileNameSeperator = "_";
|
|
1359
|
+
|
|
1360
|
+
if (options.outputPath === null) {
|
|
1361
|
+
options.fileName = createDateFileName(fileNameSeperator, csvFormat);
|
|
1362
|
+
options.destinationPath = path.resolve('.');
|
|
1363
|
+
} else {
|
|
1364
|
+
// get directory path, file path, file Extenstion from given path
|
|
1365
|
+
const parseDirPath = path.dirname(options.outputPath),
|
|
1366
|
+
parseBase = path.parse(options.outputPath).base;
|
|
1367
|
+
|
|
1368
|
+
let parseExt = path.parse(options.outputPath).ext;
|
|
1369
|
+
|
|
1370
|
+
parseExt = parseExt.split('.').pop();
|
|
1371
|
+
log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
|
|
1372
|
+
+ " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
|
|
1373
|
+
|
|
1374
|
+
// if specific path is given
|
|
1375
|
+
if (parseBase) {
|
|
1376
|
+
options.fileName = parseBase;
|
|
1377
|
+
options.destinationPath = path.resolve(parseDirPath);
|
|
1378
|
+
// parseBase is [filename].[ext] format
|
|
1379
|
+
if (parseExt === "") {
|
|
1380
|
+
// paresBase does not have file extesntion, add .png format
|
|
1381
|
+
options.fileName += "." + csvFormat;
|
|
1382
|
+
} else if (parseExt !== csvFormat) {
|
|
1383
|
+
return next(errHndl.getErrMsg("INVALID_CSV_FORMAT"));
|
|
1384
|
+
}
|
|
1385
|
+
} else if (parseDirPath) {
|
|
1386
|
+
// the path has only "directory" without parseBase
|
|
1387
|
+
// for example, "ares-device -r -s /"
|
|
1388
|
+
options.fileName = createDateFileName(fileNameSeperator, csvFormat);
|
|
1389
|
+
options.destinationPath = path.resolve(parseDirPath);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
options.csvPath = path.resolve(options.destinationPath, options.fileName);
|
|
1394
|
+
log.verbose("device#makeCSVOutputPath()", "csvPath:", options.csvPath);
|
|
1395
|
+
|
|
1396
|
+
fs.open(options.csvPath, 'w', function(err, fd) {
|
|
1397
|
+
if (err) {
|
|
1398
|
+
return next(errHndl.getErrMsg(err));
|
|
1399
|
+
}
|
|
1400
|
+
fs.close(fd, function(error) {
|
|
1401
|
+
if (error) {
|
|
1402
|
+
return next(errHndl.getErrMsg(error));
|
|
1403
|
+
}
|
|
1404
|
+
log.verbose("device#makeCSVOutputPath()", options.csvPath + " is closed");
|
|
1405
|
+
|
|
1406
|
+
// Defense code
|
|
1407
|
+
if (fs.existsSync(options.csvPath)) {
|
|
1408
|
+
fs.unlinkSync(options.csvPath);
|
|
1409
|
+
}
|
|
1410
|
+
log.verbose("device#makeCSVOutputPath()", options.csvPath + " is exist: " + fs.existsSync(options.csvPath));
|
|
1411
|
+
next();
|
|
1412
|
+
});
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
1417
|
+
module.exports = device;
|
|
1418
|
+
}
|
|
1419
|
+
}());
|