dcp-worker 3.2.30-2 → 3.2.30-4

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.
@@ -1,114 +1,30 @@
1
1
  /**
2
- * @file worker-loggers/console.js
3
- * @author Ryan Rossiter, ryan@kingsds.network
4
- * @date April 2020
5
- *
6
- * This worker logger uses console.log to produce
7
- * simple log output.
2
+ * @file worker-loggers/console.js
3
+ * Logger interface which just logs to the node console on stdout/stderr.
4
+ * @author Wes Garland, wes@distributive.network
5
+ * @date June 2023
8
6
  */
7
+ 'use strict';
9
8
 
10
- require('./common-types');
9
+ const process = require('process');
11
10
 
12
- /**
13
- * When this.enhancedDisplay is true
14
- * Sandbox 1: Slice Started: slice 1, 0x5b5214D48F0428669c4E: Simple Job
15
- * Sandbox 1: Slice Completed: slice 1, 0x5b5214D48F0428669c4E: Simple Job: dt 114ms
16
- * When this.enhancedDisplay is false
17
- * Sandbox 1: Slice Started: 0x5b5214D48F0428669c4E68779896D29D77c42903 Simple Job
18
- * Sandbox 1: Slice Completed: 0x5b5214D48F0428669c4E68779896D29D77c42903 Simple Job
19
- * @type {WorkerLogger}
20
- */
21
- const consoleLogger = {
22
- init(worker, options) {
23
- this.worker = worker;
24
- this.options = Object.assign({}, options);
25
- this.sliceMap = {}; // jobAddress --> ( sliceNumber, t0 )
26
- this.enhancedDisplay = true; // When false, no timing, no sliceNumber, full jobAddress
27
- this.truncationLength = 22; // Extra 2 for '0x'
28
- },
29
-
30
- id (sandbox, sliceNumber) {
31
- if (!this.enhancedDisplay)
32
- return sandbox.public ? `${sandbox.jobAddress} ${sandbox.public.name}` : `${sandbox.jobAddress}`;
33
-
34
- const address = sandbox.jobAddress ? sandbox.jobAddress.slice(0, this.truncationLength) : 'null';
35
- const baseInfo = sandbox.public ? `${address}: ${sandbox.public.name}` : `${address}:`;
36
-
37
- if (!sliceNumber)
38
- sliceNumber = sandbox.slice ? sandbox.slice.sliceNumber : 0;
39
- return sliceNumber ? `slice ${sliceNumber}, ${baseInfo}` : baseInfo;
40
- },
41
-
42
- onSandboxReady(sandbox) {
43
- const shortId = sandbox.id.toString(10).padStart(3);
11
+ exports.init = function console$$init(options)
12
+ {
13
+ const myConsole = new (require('console').Console)(process);
44
14
 
45
- const sandboxData = {
46
- shortId,
15
+ delete exports.init; // singleton
16
+ if (process.env.RAW_CONSOLE)
17
+ {
18
+ /* raw mode is used to debug node-inspect problems by dumping raw types directly to console.log */
19
+ exports.raw = function console$$raw(level, ...args) {
20
+ myConsole[level](...args);
47
21
  };
48
-
49
- console.log(` * Sandbox ${sandboxData.shortId}: Initialized`);
50
-
51
- return sandboxData;
52
- },
53
-
54
- sandbox$onSliceStart(sandbox, sandboxData, ev) {
55
- const sliceNumber = sandbox.slice ? sandbox.slice.sliceNumber : 0;
56
- this.sliceMap[sandbox.id] = { slice: sliceNumber, t0: Date.now() };
57
- console.log(` * Sandbox ${sandboxData.shortId}: Slice Started: ${this.id(sandbox)}`);
58
- },
59
-
60
- sandbox$onSliceProgress(sandbox, sandboxData, ev) {
61
- // something
62
- },
63
-
64
- sandbox$onSliceFinish(sandbox, sandboxData, ev) {
65
- const sliceInfo = this.sliceMap[sandbox.id];
66
- if (sliceInfo && this.enhancedDisplay)
67
- console.log(` * Sandbox ${sandboxData.shortId}: Slice Completed: ${this.id(sandbox, sliceInfo.slice)}: dt ${Date.now() - sliceInfo.t0}ms`);
68
- else
69
- console.log(` * Sandbox ${sandboxData.shortId}: Slice Completed: ${this.id(sandbox)}`);
70
- },
71
-
72
- sandbox$onWorkerStop(sandbox, sandboxData, ev) {
73
- const sliceInfo = this.sliceMap[sandbox.id];
74
- delete this.sliceMap[sandbox.id];
75
- console.log(` * Sandbox ${sandboxData.shortId}: Terminated: ${this.id(sandbox, sliceInfo?.slice)}`);
76
- },
77
-
78
- onPayment({ payment }) {
79
- try {
80
- payment = parseFloat(payment);
81
- } catch (e) {
82
- console.error(" ! Failed to parse payment:", payment);
83
- return;
84
- }
85
-
86
- if (payment > 0) console.log(` * DCC Credit: ${payment.toFixed(3)}`);
87
- },
88
-
89
- onFetchingSlices() {
90
- this.options.verbose && console.log(" * Fetching slices...");
91
- },
92
-
93
- onFetchedSlices(ev) {
94
- this.options.verbose && console.log(" * Fetched", ev);
95
- },
96
-
97
- onFetchSlicesFailed(ev) {
98
- console.log(" ! Failed to fetch slices:", ev);
99
- },
100
-
101
- onSubmitStart() {
102
- this.options.verbose >= 2 && console.log(" * Submitting results...");
103
- },
104
-
105
- onSubmit() {
106
- this.options.verbose >= 2 && console.log(" * Submitted");
107
- },
108
-
109
- onSubmitError(ev) {
110
- console.log(" ! Failed to submit results:", ev);
111
- },
112
- };
113
-
114
- Object.assign(exports, consoleLogger);
22
+ }
23
+ else
24
+ {
25
+ /* Log a single string to the console; conceptually very similar to other loggers */
26
+ exports.at = function console$$at(level, ...args) {
27
+ myConsole[level](args.join(' '));
28
+ };
29
+ }
30
+ }
@@ -6,183 +6,42 @@
6
6
  * This worker logger uses the blessed library to create
7
7
  * a monitoring dashboard for the worker.
8
8
  */
9
+ 'use strict';
9
10
 
10
- const dcpConfig = require('dcp/dcp-config');
11
- const blessed = require('blessed');
12
- const contrib = require('blessed-contrib');
13
11
  const chalk = require('chalk');
14
- const util = require('util');
15
-
16
- const components = require('../blessed-components');
17
- require('./common-types');
18
-
19
- const SLICE_FETCH_STATUS = {
20
- IDLE: chalk.yellow('Idle'),
21
- FETCHING: chalk.blue('Fetching Work...'),
22
- WORKING: chalk.green('Working'),
23
- NO_WORK: chalk.red('No Work Available'),
24
- }
25
-
26
- /** @type {WorkerLogger} */
27
- const dashboardLogger = {
28
- init(worker, options) {
29
- this.worker = worker;
30
- this.options = options;
31
- this.totalDCCs = 0;
32
- this.sliceFetchStatus = SLICE_FETCH_STATUS.IDLE;
33
- exports.screen = this.screen = blessed.screen();
34
- const grid = new contrib.grid({rows: 3, cols: 5, screen: this.screen});
35
-
36
- const log = grid.set(0, 2, 2, 3, components.log, {
37
- label: 'Worker Log',
38
- scrollable: true,
39
- alwaysScroll: true,
40
- mouse: true,
41
- scrollbar: {
42
- bg: 'blue',
43
- },
44
- });
12
+ const _console = new (require('console').Console)(process);
13
+
14
+ exports.init = function dashboardLogger$$init(options)
15
+ {
16
+ function logWrapperFactory(logLevel)
17
+ {
18
+ const inspect = Symbol.for('nodejs.util.inspect.custom');
19
+ const dashboardTui = require('../dashboard-tui');
20
+
21
+ return function wrappedLogFun() {
22
+ if (!dashboardTui.logPane) /* no logPane => TUI not ready - fallback to console */
23
+ {
24
+ const consoleLogger = require('./console');
25
+ if (consoleLogger.init)
26
+ consoleLogger.init();
45
27
 
46
- console.log = console.error = console.warn = console.info = console.debug = function logWrapper() {
47
- arguments = Array.from(arguments);
48
- for (let i in arguments)
28
+ const logAt = consoleLogger.at || consoleLogger.raw;
29
+ logAt(logLevel, ...arguments);
30
+ return;
31
+ }
32
+
33
+ const argv = Array.from(arguments);
34
+ for (let i in argv)
49
35
  {
50
- if (arguments[i] instanceof Error)
51
- arguments[i] = util.inspect(arguments[i]);
36
+ if (argv[i] instanceof Error || (typeof argv[i] === 'object' && argv[i][inspect]))
37
+ argv[i] = util.inspect(argv[i]);
38
+ else if (logLevel === 'error' && typeof argv[i] === 'string')
39
+ argv[i] = chalk.red(argv[i]);
52
40
  }
53
- log.log.apply(log, arguments);
54
- }
55
- require('../remote-console').reintercept();
56
-
57
- this.sandboxes = grid.set(0, 0, 2, 2, components.sandboxes, {
58
- label: 'Sandboxes',
59
- defaultProgressBars: this.worker.cpuCores,
60
- scrollable: true,
61
- alwaysScroll: true,
62
- mouse: true,
63
- scrollbar: {
64
- bg: 'blue',
65
- },
66
- });
67
-
68
- this.workerInfo = grid.set(2, 0, 1, 5, blessed.text);
69
- this.updateWorkerInfo();
70
-
71
- setInterval(() => this.screen.render(), 50).unref(); /* 50ms = 20 fps */
72
-
73
- function raise(sig)
74
- {
75
- process.kill(process.pid, sig);
76
- }
77
-
78
- /* Apply key bindings which mimic canonical input mode */
79
- this.screen.key(['C-c'], () => raise('SIGINT'));
80
- this.screen.key(['C-z'], () => raise('SIGTSTP'));
81
- this.screen.key(['\u001c'], () => raise('SIGQUIT')); /* C-\ */
82
-
83
- this.screen.key(['escape'], () => {
84
- console.log('Stopping worker...');
85
- worker.stop();
86
- });
87
- },
88
-
89
- updateWorkerInfo() {
90
- const workerOptions = dcpConfig.worker;
91
-
92
- this.workerInfo.setLabel(`Worker Status [${this.sliceFetchStatus}]`);
93
- this.workerInfo.setContent([
94
- chalk.green(` DCCs Earned: ${chalk.bold(this.totalDCCs.toFixed(7))}`),
95
- '',
96
- ` Scheduler: ${chalk.yellow(dcpConfig.scheduler.location.href)}`,
97
- ` Bank: ${chalk.yellow(dcpConfig.bank.location.href)}`,
98
- `Bank Account: ${chalk.yellow(this.worker.paymentAddress || 'Starting...')}`,
99
- ` Identity: ${chalk.yellow(this.worker.identityKeystore? this.worker.identityKeystore.address : 'Starting...')}`,
100
- ` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
101
- ` Priv Groups: ${Object.keys(workerOptions.computeGroups).length}`,
102
- ` Pub Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
103
- ].join('\n'));
104
- },
105
-
106
- onSandboxReady(sandbox) {
107
-
108
- },
109
-
110
- sandbox$onSliceStart(sandbox, sandboxData, slice) {
111
- sandboxData.progressData = {
112
- indeterminate: true,
113
- progress: 0,
114
- label: sandbox.public.name,
115
- };
116
-
117
- this.sandboxes.data.push(sandboxData.progressData);
118
-
119
- this.sandboxes.update();
120
- },
121
-
122
- sandbox$onSliceProgress(sandbox, sandboxData, ev) {
123
- if (ev.indeterminate) {
124
- sandboxData.progressData.progress = 100;
125
-
126
- setTimeout(() => {
127
- if (sandboxData.progressData.indeterminate) {
128
- sandboxData.progressData.progress = 0;
129
- this.sandboxes.update();
130
- }
131
- }, 500).unref();
132
- } else {
133
- sandboxData.progressData.progress = ev.progress;
134
- sandboxData.progressData.indeterminate = false;
41
+ dashboardTui.logPane.log(...argv);
135
42
  }
43
+ }
136
44
 
137
- this.sandboxes.update();
138
- },
139
-
140
- sandbox$onSliceFinish(sandbox, sandboxData, ev) {
141
- this.sandboxes.data =
142
- this.sandboxes.data.filter(d => d != sandboxData.progressData);
143
-
144
- this.sandboxes.update();
145
- },
146
-
147
- sandbox$onWorkerStop(sandbox, sandboxData, ev) {
148
- this.sandbox$onSliceFinish(sandbox, sandboxData, ev);
149
- },
150
-
151
- onPayment({ payment }) {
152
- try {
153
- payment = parseFloat(payment);
154
- } catch (e) {
155
- console.error("Failed to parse payment float:", payment);
156
- return;
157
- }
158
-
159
- try {
160
- this.totalDCCs += payment;
161
- this.updateWorkerInfo();
162
- } catch(e) {
163
- console.error(e.message);
164
- }
165
- },
166
-
167
- onFetchingSlices() {
168
- this.sliceFetchStatus = SLICE_FETCH_STATUS.FETCHING;
169
- this.updateWorkerInfo();
170
- },
171
-
172
- onFetchedSlices(fetchedSliceCount) {
173
- if (fetchedSliceCount === 0 && this.sandboxes.data.length === 0) {
174
- this.sliceFetchStatus = SLICE_FETCH_STATUS.NO_WORK;
175
- } else {
176
- this.sliceFetchStatus = SLICE_FETCH_STATUS.WORKING;
177
- }
178
-
179
- this.updateWorkerInfo();
180
- },
181
-
182
- onFetchSlicesFailed(ev) {
183
- this.sliceFetchStatus = SLICE_FETCH_STATUS.NO_WORK;
184
- this.updateWorkerInfo();
185
- },
186
- };
187
-
188
- Object.assign(exports, dashboardLogger);
45
+ for (let level of ['log', 'warn', 'debug', 'info', 'error'])
46
+ exports[level] = logWrapperFactory(level);
47
+ }
@@ -3,65 +3,42 @@
3
3
  * @author Eddie Roosenmaallen <eddie@kingsds.network>
4
4
  * @date August 2022
5
5
  *
6
- * This logger module emits events to the Windows event-log, writing all
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
6
+ * This logger module redirects logs to the Windows event-log, writing all
7
+ * console logs to it.
13
8
  */
9
+ 'use strict';
14
10
 
15
- require('./common-types');
16
- const consoleLogger = require('./console');
11
+ const os = require('os');
12
+ if (os.platform() !== 'win32')
13
+ throw new Error(`Windows Event Log module is not supported on ${os.platform()}`);
17
14
 
18
15
  const { EventLog } = require('node-eventlog');
19
16
 
20
17
  // Copy the original global console object's properties onto a backup
21
18
  const _console = Object.assign({}, console);
22
19
 
20
+ /**
21
+ * Initialize the eventlog worker logger
22
+ *
23
+ * @param {object} options Options for logger behaviour (passed
24
+ * through to consoleLogger)
25
+ */
26
+ exports.init = function eventLog$$init(options)
27
+ {
28
+ exports._processName = require('path').basename(process.mainModule.filename || process.argv0);
29
+ const source = options.source || exports._processName || 'dcp-worker';
30
+ exports._eventLog = new EventLog(source);
31
+ require('../startWorkerLogger').inspectOptions.colors = false;
32
+ exports.at = log;
33
+ }
23
34
 
24
- const eventlogLogger = {
25
- /**
26
- * Initialize the eventlog 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._processName = require('path').basename(process.mainModule.filename || process.argv0);
36
- const source = options.source || this._processName || 'dcp-worker';
37
- // _console.log(`036: creating new EventLog(${source}) client...`);
38
- this._eventLog = new EventLog(source);
39
-
40
- ['debug','error','info','log','warn'].forEach(level => {
41
- console[level] = (...args) => this._log(level, ...args);
42
- });
43
- },
44
-
45
- _log(level, ...items) {
46
- const strBuilder = [`${this._processName}[${process.pid}]:`];
47
-
48
- items.forEach(i => {
49
- try {
50
- switch (typeof i) {
51
- case 'object':
52
- strBuilder.push(JSON.stringify(i));
53
- break;
54
- default:
55
- strBuilder.push(String(i));
56
- }
57
- }
58
- catch (e) {
59
- if (e instanceof TypeError) {
60
- strBuilder.push('[encoding error: ' + e.message + ']');
61
- }
62
- }
63
- });
64
-
35
+ /**
36
+ * @param {string} level The node log level to log at
37
+ * @param {[string]} items An array of strings to log as a single message
38
+ */
39
+ function log(level, ...items)
40
+ {
41
+ {
65
42
  // Use the string log-level to look up the severity number:
66
43
  let severity = {
67
44
  error: 'error',
@@ -71,18 +48,9 @@ const eventlogLogger = {
71
48
  debug: 'info',
72
49
  }[level];
73
50
 
74
- // _console.debug(`074: about to actually log a line:`, strBuilder, severity);
75
- return this._eventLog.log(strBuilder.join(' '), severity).catch(error => {
51
+ return exports._eventLog.log(items.join(' '), severity).catch(error => {
76
52
  if (error)
77
53
  _console.error('255: Unexpected error writing to event log:', error);
78
54
  });
79
55
  }
80
- };
81
-
82
- // necessary to keep `this` pointing at the correct thing when we call
83
- for (const [prop, value] of Object.entries(consoleLogger))
84
- {
85
- if (typeof value === 'function')
86
- exports[prop] = value.bind(consoleLogger);
87
56
  }
88
- Object.assign(exports, eventlogLogger);
@@ -4,122 +4,96 @@
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.
8
7
  */
9
-
10
- require('./common-types');
11
- const consoleLogger = require('./console');
8
+ 'use strict';
12
9
 
13
10
  // Copy the original global console object's properties onto a backup
14
11
  const _console = Object.assign({}, console);
15
12
 
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
- });
39
-
40
- ['debug','error','info','log','warn'].forEach(level => {
41
- console[level] = (...args) => this._log(level, ...args);
42
- });
43
- },
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
+ }
44
34
 
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) {
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
+ {
54
44
  const fs = require('fs');
55
45
 
56
- if (this._file)
46
+ if (getLogFile._file)
57
47
  {
58
- if (!forceNew)
59
- return this._file;
60
-
61
48
  try
62
49
  {
63
- this._file.end();
50
+ getLogFile._file.end();
64
51
  }
65
52
  catch (err)
66
53
  {
67
54
  console.error('061: failed to close old log file:', err);
68
55
  }
69
- this._file = false;
56
+ getLogFile._file = false;
70
57
  }
71
58
 
72
- const options = {
73
- flags: this.options.truncate ? 'w' : 'a', // NYI: cli --truncate
59
+ const fileOptions = {
60
+ flags: options.truncate ? 'w' : 'a', // NYI: cli --truncate
74
61
  }
75
62
 
76
- const file = this._file = fs.createWriteStream(this._filepath, options);
63
+ const file = getLogFile._file = fs.createWriteStream(options.logfile, fileOptions);
77
64
 
78
65
  // On error, close & recreate the log file
79
66
  file.on('error', err => {
80
67
  _console.error('082: console-patch::LogFileConsole write error:', err);
81
68
 
82
- this._getLogFile(true);
69
+ getLogFile(options);
83
70
  });
84
71
 
85
72
  return file;
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 = [
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 = [
96
86
  (new Date()).toISOString(),
97
87
  level,
98
88
  ];
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
-
89
+
90
+ const logElements = logPrefix.concat(items);
91
+
116
92
  try {
117
- this._file.write(strBuilder.join(' ') + '\n');
93
+ getLogFile._file.write(logElements.join(' ') + '\n');
118
94
  }
119
95
  catch (error) {
120
96
  _console.error('131: Unexpected error writing to log file:', error);
121
97
  }
122
- },
123
- };
124
-
125
- Object.assign(exports, consoleLogger, logfileLogger);
98
+ }
99
+ }