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.
@@ -1,127 +1,94 @@
1
1
  /**
2
2
  * @file startWorkerLogger.js
3
- * Start the DCP Worker logging subsystem. Sets console.log (etc) redirection, determine
4
- * the correct log target (screen, TUI, syslog, windows event log, file) and redirect the
5
- * output there.
6
3
  * @author Ryan Rossiter, ryan@kingsds.network
7
4
  * @date April 2020
8
- * @author Wes Garland, wes@distributive.network
9
5
  */
10
- 'use strict';
11
6
 
12
7
  const process = require('process');
13
8
  const os = require('os');
14
- const util = require('util');
9
+ require('./worker-loggers/common-types');
15
10
 
16
11
  /**
17
12
  * Detects and returns the appropriate logger for the environment
18
- * @param {object} options - cliArgs from worker
19
13
  * @returns {WorkerLogger}
20
14
  */
21
- function getLogger(options)
22
- {
23
- if (options.outputMode === 'detect')
24
- {
25
- options.outputMode = 'console';
26
- /* have TTY - use dashboard when charset supports line drawing */
27
- if ((process.env.LANG && process.env.LANG.match(/utf-|latin-|iso-8859-/i)) || os.platform() === 'win32')
28
- options.outputMode = 'dashboard';
15
+ function getLogger({ outputMode='detect' }) {
16
+ if (outputMode === 'detect') {
17
+ if (process.stdout.isTTY && os.platform() !== 'win32' &&
18
+ process.env.LANG && process.env.LANG.match(/utf-?8/i)) {
19
+ outputMode = 'dashboard';
20
+ } else {
21
+ outputMode = 'console';
22
+ }
29
23
  }
30
24
 
31
25
  try
32
26
  {
33
- const om = require('path').basename(options.outputMode);
27
+ const om = require('path').basename(outputMode);
34
28
  return require('./worker-loggers/' + om);
35
29
  }
36
30
  catch (error)
37
31
  {
38
- if (error.code === 'MODULE_NOT_FOUND')
39
- throw new Error(`Unknown outputMode "${options.outputMode}"`);
40
- throw error;
32
+ console.error(`032: Failed to load worker logger "${outputMode}":`, error);
33
+ throw new Error(`Unknown outputMode "${outputMode}"`);
41
34
  }
42
35
  }
43
36
 
44
- /**
45
- * Start intercepting console.* methods so that log output from the worker goes to the appropriate log
46
- * target; eg syslog, file, windows event log, etc. Unlike the telnet console log interceptor which is
47
- * merely a passthrough shim, this is a "dead end" interceptor - we do not pass the log message through
48
- * to the original console method. This implies, for example, that sending console messages to syslogd
49
- * quiesces the tty output.
50
- *
51
- * @param {object} options - cliArgs from worker
52
- */
53
- exports.init = function startWorkerLogger$$init(options)
54
- {
55
- const logger = getLogger(options);
56
-
57
- logger.init(options);
37
+ const workerEvents = {
38
+ fetchStart: 'onFetchingSlices',
39
+ fetchEnd: 'onFetchedSlices',
40
+ fetchError: 'onFetchSlicesFailed',
41
+ submit: 'onSubmit',
42
+ submitError: 'onSubmitError',
43
+ payment: 'onPayment',
44
+ }
45
+ const supervisorEvents = {
46
+ submittingResult: 'onSubmitStart',
47
+ }
48
+ const sandboxEvents = {
49
+ start: 'sandbox$onSliceStart',
50
+ sliceProgress: 'sandbox$onSliceProgress',
51
+ sliceFinish: 'sandbox$onSliceFinish',
52
+ terminated: 'sandbox$onWorkerStop',
53
+ }
58
54
 
59
- /* The logger module's exports are its API. The following functions are supported, in this order
60
- * of severity:
61
- * . debug: debug-level message
62
- * . info: informational message
63
- * . log: normal, but significant, condition
64
- * . warn: warning conditions
65
- * . error: error conditions
66
- *
67
- * Additionally, generic functions may be used when one of the above is not defined:
68
- * . at: write a log message at a specific log level; the level is the first argument
69
- * . raw: same as at, but arguments are not formatted
70
- * . any: write a log message without regard to log level
71
- *
72
- * All of these functions, with the exception of raw, receive only string arguments.
55
+ Object.assign(exports, {
56
+ /**
57
+ * This method will attach event listeners from the provided
58
+ * worker to a worker logger. The logger to use is
59
+ * determined by getLogger based on the environment.
60
+ *
61
+ * @param {Worker} worker
62
+ * @param {object} options
63
+ * @param {number} options.verbose
64
+ * @param {boolean} options.outputMode - which logger to use (default='detect')
73
65
  */
66
+ startWorkerLogger(worker, options={}) {
67
+ const logger = getLogger(options);
68
+ logger.init(worker, options);
74
69
 
75
- for (let level of ['debug', 'error', 'info', 'log', 'warn'])
76
- {
77
- if (logger[level])
78
- console[level] = (...args) => logger[level]( ...format(...args));
79
- else if (logger.at)
80
- console[level] = (...args) => logger.at(level, ...format(...args));
81
- else if (logger.raw)
82
- console[level] = (...args) => logger.raw(level, ...args);
83
- else if (logger.any)
84
- console[level] = (...args) => logger.any(`${level}:`, format(...args));
85
- else
70
+ for (const [ev, handler] of Object.entries(workerEvents))
86
71
  {
87
- require('./remote-console').reintercept();
88
- throw new Error('logger module missing export for ' + level);
72
+ if (typeof logger[handler] === 'function')
73
+ worker.on(ev, logger[handler].bind(logger));
89
74
  }
90
- }
91
-
92
- require('./remote-console').reintercept();
93
- }
94
-
95
- /**
96
- * Format console.log arguments for use by a non-native logger, eg syslog. All non-string arguments are
97
- * converted into the best human-readable strings we can muster.
98
- */
99
- function format(...argv)
100
- {
101
- for (let i in argv)
102
- {
103
- try
75
+ for (const [ev, handler] of Object.entries(supervisorEvents))
104
76
  {
105
- if (typeof argv[i] === 'object' && argv[i] instanceof String)
106
- argv[i] = String(argv[i]);
107
- if (typeof argv[i] === 'object')
108
- argv[i] = util.inspect(argv[i], exports.inspectOptions);
109
- if (typeof argv[i] !== 'string')
110
- argv[i] = String(argv[i]);
77
+ if (typeof logger[handler] === 'function')
78
+ worker.addSupervisorEventListener(ev, logger[handler].bind(logger));
111
79
  }
112
- catch(e)
113
- {
114
- if (e instanceof TypeError)
115
- argv[i] = '[encoding error: ' + e.message + ']';
116
- }
117
- }
118
80
 
119
- return argv;
120
- }
121
-
122
- /**
123
- * Options for util.inspect. Loggers which cannot deal with colours should force this false.
124
- */
125
- exports.inspectOptions = {
126
- colors: process.stdout.hasColors() || process.env.FORCE_COLOR,
127
- };
81
+ worker.on('sandbox', (sandbox) => {
82
+ /**
83
+ * logger.onSandboxStart can return a data object that will be provided to
84
+ * the other sandbox event handlers
85
+ */
86
+ const data = logger.onSandboxReady(sandbox) || {};
87
+ for (const [ev, handler] of Object.entries(sandboxEvents))
88
+ {
89
+ if (typeof logger[handler] === 'function')
90
+ sandbox.on(ev, logger[handler].bind(logger, sandbox, data));
91
+ }
92
+ });
93
+ }
94
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @typedef WorkerLogger
3
+ * @property {onSandboxReady} onSandboxReady
4
+ * @property {function} onPayment
5
+ * @property {function} onFetchingSlices
6
+ * @property {function} onFetchedSlices
7
+ * @property {function} onFetchSlicesFailed
8
+ * @property {SandboxCallback} sandbox$onSliceStart
9
+ * @property {SandboxCallback} sandbox$onSliceProgress
10
+ * @property {SandboxCallback} sandbox$onSliceFinish
11
+ * @property {SandboxCallback} sandbox$onWorkerStop
12
+ */
13
+
14
+ /**
15
+ * @typedef {function} onSandboxReady
16
+ * @param {Sandbox} sandbox
17
+ * @returns {object} workerData
18
+ */
19
+
20
+ /**
21
+ * @typedef {function} SandboxCallback
22
+ * @param {Sandbox} sandbox
23
+ * @param {object} workerData
24
+ */
@@ -1,30 +1,114 @@
1
1
  /**
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
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.
6
8
  */
7
- 'use strict';
8
9
 
9
- const process = require('process');
10
+ require('./common-types');
10
11
 
11
- exports.init = function console$$init(options)
12
- {
13
- const myConsole = new (require('console').Console)(process);
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
+ },
14
29
 
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);
21
- };
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(' '));
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);
44
+
45
+ const sandboxData = {
46
+ shortId,
28
47
  };
29
- }
30
- }
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);
@@ -6,42 +6,183 @@
6
6
  * This worker logger uses the blessed library to create
7
7
  * a monitoring dashboard for the worker.
8
8
  */
9
- 'use strict';
10
9
 
10
+ const dcpConfig = require('dcp/dcp-config');
11
+ const blessed = require('blessed');
12
+ const contrib = require('blessed-contrib');
11
13
  const chalk = require('chalk');
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();
14
+ const util = require('util');
27
15
 
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)
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
+ });
45
+
46
+ console.log = console.error = console.warn = console.info = console.debug = function logWrapper() {
47
+ arguments = Array.from(arguments);
48
+ for (let i in arguments)
35
49
  {
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]);
50
+ if (arguments[i] instanceof Error)
51
+ arguments[i] = util.inspect(arguments[i]);
40
52
  }
41
- dashboardTui.logPane.log(...argv);
53
+ log.log.apply(log, arguments);
42
54
  }
43
- }
55
+ require('../remote-console').reintercept();
44
56
 
45
- for (let level of ['log', 'warn', 'debug', 'info', 'error'])
46
- exports[level] = logWrapperFactory(level);
47
- }
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;
135
+ }
136
+
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);
@@ -3,42 +3,65 @@
3
3
  * @author Eddie Roosenmaallen <eddie@kingsds.network>
4
4
  * @date August 2022
5
5
  *
6
- * This logger module redirects logs to the Windows event-log, writing all
7
- * console logs to it.
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
8
13
  */
9
- 'use strict';
10
14
 
11
- const os = require('os');
12
- if (os.platform() !== 'win32')
13
- throw new Error(`Windows Event Log module is not supported on ${os.platform()}`);
15
+ require('./common-types');
16
+ const consoleLogger = require('./console');
14
17
 
15
18
  const { EventLog } = require('node-eventlog');
16
19
 
17
20
  // Copy the original global console object's properties onto a backup
18
21
  const _console = Object.assign({}, console);
19
22
 
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
- }
34
23
 
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
- {
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
+
42
65
  // Use the string log-level to look up the severity number:
43
66
  let severity = {
44
67
  error: 'error',
@@ -48,9 +71,18 @@ function log(level, ...items)
48
71
  debug: 'info',
49
72
  }[level];
50
73
 
51
- return exports._eventLog.log(items.join(' '), severity).catch(error => {
74
+ // _console.debug(`074: about to actually log a line:`, strBuilder, severity);
75
+ return this._eventLog.log(strBuilder.join(' '), severity).catch(error => {
52
76
  if (error)
53
77
  _console.error('255: Unexpected error writing to event log:', error);
54
78
  });
55
79
  }
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);
56
87
  }
88
+ Object.assign(exports, eventlogLogger);