dcp-worker 3.2.30-7 → 3.2.30-9

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.
@@ -4,96 +4,122 @@
4
4
  * @date August 2022
5
5
  *
6
6
  * This logger module maintains a log file, writing all console logs to it.
7
+ * Most worker events are passed through to the console logger.
7
8
  */
8
- 'use strict';
9
+
10
+ require('./common-types');
11
+ const consoleLogger = require('./console');
9
12
 
10
13
  // Copy the original global console object's properties onto a backup
11
14
  const _console = Object.assign({}, console);
12
15
 
13
- /**
14
- * Initialize the logfile worker logger
15
- *
16
- * @param {object} options Options for logger behaviour
17
- * @param {string} options.filepath Path to worker file; default: ./dcp-worker.log
18
- * @param {boolean} options.truncate If true, logfile will be cleared at worker startup
19
- */
20
- exports.init = function init(options)
21
- {
22
- delete exports.init; // singleton
23
- options.verbose >= 3 && _console.debug('050: constructing LogfileConsole', options.logfile, options);
24
- getLogFile(options);
25
- require('../startWorkerLogger').inspectOptions.colors = Boolean(process.env.FORCE_COLOR);
26
-
27
- // on SIGHUP, close the output stream and open a new one
28
- process.on('SIGHUP', () => {
29
- getLogFile(options);
30
- });
31
-
32
- exports.at = log;
33
- }
16
+ const logfileLogger = {
17
+ /**
18
+ * Initialize the logfile worker logger
19
+ *
20
+ * @param {Worker} worker DCP Worker object to log
21
+ * @param {object} options Options for logger behaviour
22
+ * @param {string} options.filepath Path to worker file; default: ./dcp-worker.log
23
+ * @param {boolean} options.truncate If true, logfile will be cleared at worker startup
24
+ */
25
+ init(worker, options) {
26
+ consoleLogger.init(worker, options);
27
+
28
+ this._filepath = options.filepath || './dcp-worker.log';
29
+ this.options = options;
30
+
31
+ options.verbose >= 3 && console.debug('050: constructing LogfileConsole', this._filepath, options);
32
+
33
+ this._getLogFile();
34
+
35
+ // on SIGHUP, close the output stream and open a new one
36
+ process.on('SIGHUP', () => {
37
+ this._getLogFile(true);
38
+ });
34
39
 
35
- /**
36
- * Return a handle to the WritableStream for this logger, creating one if
37
- * necessary.
38
- *
39
- * @return {fs.WriteStream}
40
- */
41
- function getLogFile(options)
42
- {
43
- {
40
+ ['debug','error','info','log','warn'].forEach(level => {
41
+ console[level] = (...args) => this._log(level, ...args);
42
+ });
43
+ },
44
+
45
+ /**
46
+ * Return a handle to the WritableStream for this logger, creating one if
47
+ * necessary.
48
+ *
49
+ * @param {boolean} forceNew If truthy, close any existing stream and open
50
+ * a new one
51
+ * @return {fs.WriteStream}
52
+ */
53
+ _getLogFile(forceNew = false) {
44
54
  const fs = require('fs');
45
55
 
46
- if (getLogFile._file)
56
+ if (this._file)
47
57
  {
58
+ if (!forceNew)
59
+ return this._file;
60
+
48
61
  try
49
62
  {
50
- getLogFile._file.end();
63
+ this._file.end();
51
64
  }
52
65
  catch (err)
53
66
  {
54
67
  console.error('061: failed to close old log file:', err);
55
68
  }
56
- getLogFile._file = false;
69
+ this._file = false;
57
70
  }
58
71
 
59
- const fileOptions = {
60
- flags: options.truncate ? 'w' : 'a', // NYI: cli --truncate
72
+ const options = {
73
+ flags: this.options.truncate ? 'w' : 'a', // NYI: cli --truncate
61
74
  }
62
75
 
63
- const file = getLogFile._file = fs.createWriteStream(options.logfile, fileOptions);
76
+ const file = this._file = fs.createWriteStream(this._filepath, options);
64
77
 
65
78
  // On error, close & recreate the log file
66
79
  file.on('error', err => {
67
80
  _console.error('082: console-patch::LogFileConsole write error:', err);
68
81
 
69
- getLogFile(options);
82
+ this._getLogFile(true);
70
83
  });
71
84
 
72
85
  return file;
73
- }
74
- }
75
-
76
- /** Write a log line to the output file.
77
- *
78
- * current outputStream.
79
- * @param {string} level Log level.
80
- * @param {any} ...items Items to log.
81
- */
82
- function log(level, ...items)
83
- {
84
- {
85
- const logPrefix = [
86
+ },
87
+
88
+ /** Write a log line to the output file. Items will be converted to strings as
89
+ * possible and concatenated after the log-level and timestamp, then written to the
90
+ * current outputStream.
91
+ * @param {string} level Log level.
92
+ * @param {any} ...items Items to log.
93
+ */
94
+ _log(level = 'none', ...items) {
95
+ const strBuilder = [
86
96
  (new Date()).toISOString(),
87
97
  level,
88
98
  ];
89
-
90
- const logElements = logPrefix.concat(items);
91
-
99
+
100
+ items.forEach(i => {
101
+ try {
102
+ switch (typeof i) {
103
+ case 'object':
104
+ strBuilder.push(JSON.stringify(i));
105
+ default:
106
+ strBuilder.push(String(i));
107
+ }
108
+ }
109
+ catch (e) {
110
+ if (e instanceof TypeError) {
111
+ strBuilder.push('[encoding error: ' + e.message + ']');
112
+ }
113
+ }
114
+ });
115
+
92
116
  try {
93
- getLogFile._file.write(logElements.join(' ') + '\n');
117
+ this._file.write(strBuilder.join(' ') + '\n');
94
118
  }
95
119
  catch (error) {
96
120
  _console.error('131: Unexpected error writing to log file:', error);
97
121
  }
98
- }
99
- }
122
+ },
123
+ };
124
+
125
+ Object.assign(exports, consoleLogger, logfileLogger);
@@ -4,45 +4,66 @@
4
4
  * @date August 2022
5
5
  *
6
6
  * This logger module emits log lines to a remote syslogd, writing all
7
- * console logs to it.
7
+ * console logs to it. Most worker events are passed through to be handled
8
+ * by the console logger.
9
+ *
10
+ * @TODO: This could likely be improved by handling worker events directly
11
+ * and emitting events to the event log more deliberately than just
12
+ * redirecting the base console output. ~ER20220831
8
13
  */
9
- 'use strict';
10
14
 
11
- const os = require('os');
12
- const syslog = require('syslog-client');
13
- const process = require('process');
15
+ require('./common-types');
16
+ const consoleLogger = require('./console');
17
+
18
+ const syslog = require('syslog-client');
14
19
 
15
20
  // Copy the original global console object's properties onto a backup
16
21
  const _console = Object.assign({}, console);
17
- var syslogClient;
18
- var processName;
19
22
 
20
- /**
21
- * Initialize the syslog worker logger
22
- *
23
- * @param {object} cliArgs Options for logger behaviour (passed
24
- * through to consoleLogger)
25
- */
26
- exports.init = function syslog$$init(cliArgs)
27
- {
28
- {
23
+
24
+ const eventlogLogger = {
25
+ /**
26
+ * Initialize the syslog worker logger
27
+ *
28
+ * @param {Worker} worker DCP Worker object to log
29
+ * @param {object} options Options for logger behaviour (passed
30
+ * through to consoleLogger)
31
+ */
32
+ init(worker, options) {
33
+ consoleLogger.init(worker, options);
34
+
35
+ this.options = Object.assign({}, options);
29
36
  const syslogOptions = {
30
- syslogHostname: os.hostname(),
31
- transport: cliArgs.syslogTransport || 'udp', // tcp, udp, unix, tls
32
- port: cliArgs.syslogPort,
33
- facility: syslog.Facility[cliArgs.syslogFacility[0].toUpperCase() + cliArgs.syslogFacility.slice(1)],
37
+ transport: options.syslogTransport || 'udp', // tcp, udp, unix, tls
38
+ port: options.syslogPort || 514,
34
39
  }
35
40
 
36
- syslogClient = syslog.createClient(cliArgs.syslogAddress || '127.0.0.1', syslogOptions);
37
- processName = require('path').basename(process.mainModule.filename || process.argv0);
38
- exports.close = () => syslogClient.close();
39
- }
40
- }
41
+ this._syslog = syslog.createClient(options.syslogAddress || '127.0.0.1', options);
42
+ this._processName = require('path').basename(process.mainModule.filename || process.argv0);
41
43
 
42
- function log(level, ...argv)
43
- {
44
- {
45
- const logPrefix = `${processName}[${process.pid}]: `;
44
+ ['debug','error','info','log','warn'].forEach(level => {
45
+ console[level] = (...args) => this._log(level, ...args);
46
+ });
47
+ },
48
+
49
+ _log(level, ...items) {
50
+ const strBuilder = [`${this._processName}[${process.pid}]:`];
51
+
52
+ items.forEach(i => {
53
+ try {
54
+ switch (typeof i) {
55
+ case 'object':
56
+ strBuilder.push(JSON.stringify(i));
57
+ default:
58
+ strBuilder.push(String(i));
59
+ }
60
+ }
61
+ catch (e) {
62
+ if (e instanceof TypeError) {
63
+ strBuilder.push('[encoding error: ' + e.message + ']');
64
+ }
65
+ }
66
+ });
46
67
 
47
68
  // Use the string log-level to look up the severity number:
48
69
  let severity = {
@@ -53,17 +74,18 @@ function log(level, ...argv)
53
74
  debug: syslog.Severity.Debug,
54
75
  }[level];
55
76
 
56
- const logMessages = argv.join(' ').split('\n');
57
-
58
- for (let logMessage of logMessages)
59
- {
60
- logMessage = logPrefix + logMessage;
61
- syslogClient.log(logMessage, { severity }, error => {
62
- if (error)
63
- _console.error('168: Unexpected error writing to syslog:');
64
- });
65
- }
77
+ this._syslog.log(strBuilder.join(' '), {
78
+ severity,
79
+ }, error => {
80
+ if (error)
81
+ _console.error('168: Unexpected error writing to syslog:', error);
82
+ });
66
83
  }
67
- }
84
+ };
68
85
 
69
- exports.at = log;
86
+ for (const [prop, value] of Object.entries(consoleLogger))
87
+ {
88
+ if (typeof value === 'function')
89
+ exports[prop] = value.bind(consoleLogger);
90
+ }
91
+ Object.assign(exports, eventlogLogger);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dcp-worker",
3
- "version": "3.2.30-7",
3
+ "version": "3.2.30-9",
4
4
  "description": "JavaScript portion of DCP Workers for Node.js",
5
5
  "main": "bin/dcp-worker",
6
6
  "keywords": [
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-worker.git"
15
+ "url": "git@github.com:Distributed-Compute-Labs/dcp-worker.git"
16
16
  },
17
17
  "license": "MIT",
18
18
  "author": "Kings Distributed Systems",
@@ -37,9 +37,8 @@
37
37
  "blessed": "^0.1.81",
38
38
  "blessed-contrib": "^4.11.0",
39
39
  "chalk": "^4.1.0",
40
- "dcp-client": "4.2.32",
41
- "semver": "^7.3.8",
42
- "syslog-client": "1.1.1"
40
+ "dcp-client": "4.3.0-4",
41
+ "semver": "^7.3.8"
43
42
  },
44
43
  "optionalDependencies": {
45
44
  "telnet-console": "^1.0.4"
@@ -50,6 +49,6 @@
50
49
  },
51
50
  "engines": {
52
51
  "node": ">=16",
53
- "npm": ">=7"
52
+ "npm": ">=6"
54
53
  }
55
54
  }
@@ -1,184 +0,0 @@
1
- /**
2
- * @file worker-loggers/dashboard.js
3
- * @author Ryan Rossiter, ryan@kingsds.network
4
- * @date April 2020
5
- * @author Wes Garland, wes@distributive.network
6
- * @date June 2023
7
- *
8
- * This module uses the blessed library to create a monitoring dashboard for the worker.
9
- * A corresponding worker-logger, dashboard.js, knows how to log to this dashboard.
10
- */
11
- 'use strict';
12
-
13
- const dcpConfig = require('dcp/dcp-config');
14
- const chalk = require('chalk');
15
- const blessed = require('blessed');
16
- const contrib = require('blessed-contrib');
17
- const components = require('./blessed-components');
18
-
19
- const { replaceWorkerEvent, replaceSandboxEvent } = require('./default-ui-events');
20
-
21
- const SLICE_FETCH_STATUS = {
22
- IDLE: chalk.yellow('Idle'),
23
- FETCHING: chalk.blue('Fetching Work...'),
24
- WORKING: chalk.green('Working'),
25
- NO_WORK: chalk.red('No Work Available'),
26
- }
27
-
28
- const usingDebugger = require('module')._cache.niim instanceof require('module').Module;
29
- const screenConf = {
30
- input: usingDebugger ? new (require('events').EventEmitter) : undefined,
31
- output: usingDebugger ? new (require('events').EventEmitter) : undefined,
32
- };
33
- /**
34
- */
35
- exports.init = function dashboard$$init(worker, options)
36
- {
37
- var sliceFetchStatus = SLICE_FETCH_STATUS.IDLE;
38
- var totalDCCs = 0;
39
- const screen = blessed.screen(screenConf);
40
- const grid = new contrib.grid({rows: 3, cols: 5, screen});
41
- const workerInfoPane = grid.set(2, 0, 1, 5, blessed.text);
42
-
43
- const logPane = grid.set(0, 2, 2, 3, components.log, {
44
- label: 'Worker Log',
45
- scrollable: true,
46
- alwaysScroll: true,
47
- mouse: true,
48
- scrollbar: {
49
- bg: 'blue',
50
- },
51
- });
52
-
53
- const sandboxPane = grid.set(0, 0, 2, 2, components.sandboxes, {
54
- label: 'Sandboxes',
55
- defaultProgressBars: Math.floor(worker.workerOptions.cores.cpu) || 1,
56
- scrollable: true,
57
- alwaysScroll: true,
58
- mouse: true,
59
- scrollbar: {
60
- bg: 'blue',
61
- },
62
- });
63
-
64
- delete exports.init; /* singleton */
65
-
66
- if (!usingDebugger)
67
- exports.logPane = logPane; /* now dashboard log can find the pane */
68
- setInterval(() => screen.render(), 50).unref(); /* 50ms = 20 fps */
69
- updateWorkerInfo();
70
- screen.render();
71
-
72
- /* Apply key bindings which mimic canonical input mode */
73
- screen.key(['C-c'], () => raise('SIGINT'));
74
- screen.key(['C-z'], () => raise('SIGTSTP'));
75
- screen.key(['\u001c'], () => raise('SIGQUIT')); /* C-\ */
76
-
77
- screen.key(['escape'], () => {
78
- console.log('Stopping worker...');
79
- worker.stop();
80
- });
81
-
82
- function updateWorkerInfo()
83
- {
84
- const workerOptions = worker.workerOptions;
85
-
86
- workerInfoPane.setLabel(`Worker Status [${sliceFetchStatus}]`);
87
- workerInfoPane.setContent([
88
- chalk.green(` DCCs Earned: ${chalk.bold(totalDCCs.toFixed(3))}`),
89
- '',
90
- ` Scheduler: ${chalk.yellow(dcpConfig.scheduler.location.href)}`,
91
- ` Bank: ${chalk.yellow(dcpConfig.bank.location.href)}`,
92
- `Bank Account: ${chalk.yellow(worker.paymentAddress || 'Starting...')}`,
93
- ` Identity: ${chalk.yellow(worker.identityKeystore? worker.identityKeystore.address : 'Starting...')}`,
94
- ` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
95
- ` Priv Groups: ${Object.keys(workerOptions.computeGroups).length}`,
96
- ` Pub Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
97
- ].join('\n'));
98
- }
99
-
100
- /* Override default event behaviour to work better with the Dashboard. */
101
-
102
- replaceSandboxEvent('start', function dashboard$$sliceStart(sandbox, sandboxData, ev) {
103
- sandboxData.progressData = {
104
- indeterminate: true,
105
- progress: 0,
106
- label: sandbox.public.name,
107
- };
108
-
109
- sandboxPane.data.push(sandboxData.progressData);
110
- sandboxPane.update();
111
- });
112
-
113
- replaceSandboxEvent('sliceProgress', function dashboard$$sliceProgress(sandbox, sandboxData, ev) {
114
- if (ev.indeterminate)
115
- {
116
- sandboxData.progressData.progress = 100;
117
- setTimeout(() => {
118
- if (sandboxData.progressData.indeterminate) {
119
- sandboxData.progressData.progress = 0;
120
- sandboxPane.update();
121
- }
122
- }, 500).unref();
123
- }
124
- else
125
- {
126
- sandboxData.progressData.progress = ev.progress;
127
- sandboxData.progressData.indeterminate = false;
128
- }
129
-
130
- sandboxPane.update();
131
- });
132
-
133
- replaceSandboxEvent('sliceFinish', function dashboard$$sliceFinish(sandbox, sandboxData, ev) {
134
- sandboxPane.data = sandboxPane.data.filter(d => d != sandboxData.progressData);
135
- sandboxPane.update();
136
- });
137
-
138
- worker.on('payment', updateWorkerInfo);
139
-
140
- replaceWorkerEvent('fetchStart', function dashboard$$fetchStart(ev) {
141
- sliceFetchStatus = SLICE_FETCH_STATUS.FETCHING;
142
- updateWorkerInfo();
143
- });
144
-
145
- replaceWorkerEvent('fetch', function dashboard$$fetch(ev) {
146
- var slicesFetched;
147
-
148
- if (ev instanceof Error)
149
- {
150
- console.error('Error fetching slices:', ev);
151
- return;
152
- }
153
-
154
- if (typeof ev === 'number' || typeof ev === 'string') /* <= June 2023 Worker events: remove ~ Sep 2023 /wg */
155
- slicesFetched = ev;
156
- else
157
- {
158
- const task = ev;
159
- slicesFetched = task.slices.length;
160
- }
161
-
162
- if (slicesFetched === 0 && sandboxPane.data.length === 0) {
163
- sliceFetchStatus = SLICE_FETCH_STATUS.NO_WORK;
164
- } else {
165
- sliceFetchStatus = SLICE_FETCH_STATUS.WORKING;
166
- }
167
-
168
- updateWorkerInfo();
169
- });
170
-
171
- replaceWorkerEvent('fetchError', function dashabord$$fetchError() {
172
- sliceFetchStatus = SLICE_FETCH_STATUS.NO_WORK;
173
- updateWorkerInfo();
174
- });
175
- };
176
-
177
- /**
178
- * Send a signal to the caller
179
- * @param {number|string} sig the signal to raise
180
- */
181
- function raise(sig)
182
- {
183
- process.kill(process.pid, sig);
184
- }