@platformatic/basic 2.37.1 → 2.38.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/lib/base.js CHANGED
@@ -8,7 +8,6 @@ import { hostname, platform } from 'node:os'
8
8
  import { pathToFileURL } from 'node:url'
9
9
  import { workerData } from 'node:worker_threads'
10
10
  import pino from 'pino'
11
- import split2 from 'split2'
12
11
  import { NonZeroExitCode } from './errors.js'
13
12
  import { cleanBasePath } from './utils.js'
14
13
  import { ChildManager } from './worker/child-manager.js'
@@ -21,7 +20,7 @@ export class BaseStackable {
21
20
  #subprocessStarted
22
21
  #metricsCollected
23
22
 
24
- constructor (type, version, options, root, configManager) {
23
+ constructor (type, version, options, root, configManager, standardStreams = {}) {
25
24
  options.context.worker ??= { count: 1, index: 0 }
26
25
 
27
26
  this.type = type
@@ -45,6 +44,8 @@ export class BaseStackable {
45
44
  this.endHttpTimer = null
46
45
  this.clientWs = null
47
46
  this.runtimeConfig = deepmerge(options.context?.runtimeConfig ?? {}, workerData?.config ?? {})
47
+ this.stdout = standardStreams?.stdout ?? process.stdout
48
+ this.stderr = standardStreams?.stderr ?? process.stderr
48
49
 
49
50
  // Setup the logger
50
51
  const pinoOptions = {
@@ -59,7 +60,7 @@ export class BaseStackable {
59
60
  pinoOptions.base = { pid: process.pid, hostname: hostname(), worker: this.workerId }
60
61
  }
61
62
 
62
- this.logger = pino(pinoOptions)
63
+ this.logger = pino(pinoOptions, standardStreams?.stdout)
63
64
 
64
65
  // Setup globals
65
66
  this.registerGlobals({
@@ -182,27 +183,7 @@ export class BaseStackable {
182
183
  try {
183
184
  await this.childManager?.inject()
184
185
 
185
- const subprocess = this.spawn(command)
186
- subprocess.stdout.setEncoding('utf8')
187
- subprocess.stderr.setEncoding('utf8')
188
-
189
- // Wait for the process to be started
190
- await new Promise((resolve, reject) => {
191
- subprocess.on('spawn', resolve)
192
- subprocess.on('error', reject)
193
- })
194
-
195
- // Route anything not catched by child process logger to the logger manually
196
- /* c8 ignore next 3 */
197
- subprocess.stdout.pipe(split2()).on('data', line => {
198
- this.logger.info(line)
199
- })
200
-
201
- /* c8 ignore next 3 */
202
- subprocess.stderr.pipe(split2()).on('data', line => {
203
- this.logger.error(line)
204
- })
205
-
186
+ const subprocess = await this.spawn(command)
206
187
  const [exitCode] = await once(subprocess, 'exit')
207
188
 
208
189
  if (exitCode !== 0) {
@@ -250,28 +231,7 @@ export class BaseStackable {
250
231
 
251
232
  try {
252
233
  await this.childManager.inject()
253
-
254
- this.subprocess = this.spawn(command)
255
- this.subprocess.stdout.setEncoding('utf8')
256
- this.subprocess.stderr.setEncoding('utf8')
257
-
258
- // Route anything not catched by child process logger to the logger manually
259
- /* c8 ignore next 3 */
260
- this.subprocess.stdout.pipe(split2()).on('data', line => {
261
- this.logger.info(line)
262
- })
263
-
264
- /* c8 ignore next 3 */
265
- this.subprocess.stderr.pipe(split2()).on('data', line => {
266
- this.logger.error(line)
267
- })
268
-
269
- // Wait for the process to be started
270
- await new Promise((resolve, reject) => {
271
- this.subprocess.on('spawn', resolve)
272
- this.subprocess.on('error', reject)
273
- })
274
-
234
+ this.subprocess = await this.spawn(command)
275
235
  this.#subprocessStarted = true
276
236
  } catch (e) {
277
237
  this.childManager.close()
@@ -327,13 +287,28 @@ export class BaseStackable {
327
287
  return this.childManager
328
288
  }
329
289
 
330
- spawn (command) {
290
+ async spawn (command) {
331
291
  const [executable, ...args] = parseCommandString(command)
332
292
 
333
293
  /* c8 ignore next 3 */
334
- return platform() === 'win32'
335
- ? spawn(command, { cwd: this.root, shell: true, windowsVerbatimArguments: true })
336
- : spawn(executable, args, { cwd: this.root })
294
+ const subprocess =
295
+ platform() === 'win32'
296
+ ? spawn(command, { cwd: this.root, shell: true, windowsVerbatimArguments: true })
297
+ : spawn(executable, args, { cwd: this.root })
298
+
299
+ subprocess.stdout.setEncoding('utf8')
300
+ subprocess.stderr.setEncoding('utf8')
301
+
302
+ subprocess.stdout.pipe(this.stdout, { end: false })
303
+ subprocess.stderr.pipe(this.stderr, { end: false })
304
+
305
+ // Wait for the process to be started
306
+ await new Promise((resolve, reject) => {
307
+ subprocess.on('spawn', resolve)
308
+ subprocess.on('error', reject)
309
+ })
310
+
311
+ return subprocess
337
312
  }
338
313
 
339
314
  async _collectMetrics () {
@@ -437,8 +412,7 @@ export class BaseStackable {
437
412
  /* c8 ignore next 2 */
438
413
  port: (this.isEntrypoint ? this.serverConfig?.port || 0 : undefined) ?? true,
439
414
  host: (this.isEntrypoint ? this.serverConfig?.hostname : undefined) ?? true,
440
- telemetryConfig: this.telemetryConfig,
441
- interceptLogging: typeof workerData?.loggingPort !== 'undefined'
415
+ telemetryConfig: this.telemetryConfig
442
416
  }
443
417
  }
444
418
  }
@@ -7,7 +7,6 @@ import { register } from 'node:module'
7
7
  import { platform, tmpdir } from 'node:os'
8
8
  import { dirname, join, resolve } from 'node:path'
9
9
  import { pathToFileURL } from 'node:url'
10
- import { workerData } from 'node:worker_threads'
11
10
  import { request } from 'undici'
12
11
  import { WebSocketServer } from 'ws'
13
12
  import { exitCodes } from '../errors.js'
@@ -60,16 +59,8 @@ export class ChildManager extends ITC {
60
59
  scripts ??= []
61
60
 
62
61
  super({
63
- name: 'child-manager',
64
62
  ...itcOpts,
65
- handlers: {
66
- log: message => {
67
- /* c8 ignore next */
68
- const logs = Array.isArray(message.logs) ? message.logs : [message.logs]
69
- this._forwardLogs(logs)
70
- },
71
- ...itcOpts.handlers
72
- }
63
+ name: 'child-manager'
73
64
  })
74
65
 
75
66
  this.#id = generateChildrenId(context)
@@ -238,11 +229,6 @@ export class ChildManager extends ITC {
238
229
  this.#server.close()
239
230
  }
240
231
 
241
- /* c8 ignore next 3 */
242
- _forwardLogs (logs) {
243
- workerData.loggingPort.postMessage({ logs: logs.map(m => JSON.stringify(m)) })
244
- }
245
-
246
232
  async #childProcessFetchHandler (req, res) {
247
233
  const { url, headers } = req
248
234
 
@@ -1,6 +1,6 @@
1
1
  import { ITC } from '@platformatic/itc'
2
2
  import { client, collectMetrics } from '@platformatic/metrics'
3
- import { createPinoWritable, ensureLoggableError, features } from '@platformatic/utils'
3
+ import { disablePinoDirectWrite, ensureFlushedWorkerStdio, ensureLoggableError, features } from '@platformatic/utils'
4
4
  import diagnosticChannel, { tracingChannel } from 'node:diagnostics_channel'
5
5
  import { EventEmitter, once } from 'node:events'
6
6
  import { readFile } from 'node:fs/promises'
@@ -194,6 +194,9 @@ export class ChildProcess extends ITC {
194
194
  }
195
195
 
196
196
  #setupLogger () {
197
+ disablePinoDirectWrite()
198
+ ensureFlushedWorkerStdio()
199
+
197
200
  // Since this is executed by user code, make sure we only override this in the main thread
198
201
  // The rest will be intercepted by the BaseStackable.
199
202
  const pinoOptions = {
@@ -209,18 +212,7 @@ export class ChildProcess extends ITC {
209
212
  }
210
213
  }
211
214
 
212
- if (isMainThread && globalThis.platformatic.interceptLogging) {
213
- pinoOptions.transport = {
214
- target: new URL('./child-transport.js', import.meta.url).toString()
215
- }
216
-
217
- this.#logger = pino(pinoOptions)
218
-
219
- Reflect.defineProperty(process, 'stdout', { value: createPinoWritable(this.#logger, 'info', false, 'STDOUT') })
220
- Reflect.defineProperty(process, 'stderr', { value: createPinoWritable(this.#logger, 'error', true, 'STDERR') })
221
- } else {
222
- this.#logger = pino(pinoOptions)
223
- }
215
+ this.#logger = pino(pinoOptions)
224
216
  }
225
217
 
226
218
  #setupServer () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/basic",
3
- "version": "2.37.1",
3
+ "version": "2.38.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -24,11 +24,11 @@
24
24
  "split2": "^4.2.0",
25
25
  "undici": "^7.0.0",
26
26
  "ws": "^8.18.0",
27
- "@platformatic/config": "2.37.1",
28
- "@platformatic/itc": "2.37.1",
29
- "@platformatic/metrics": "2.37.1",
30
- "@platformatic/telemetry": "2.37.1",
31
- "@platformatic/utils": "2.37.1"
27
+ "@platformatic/itc": "2.38.0",
28
+ "@platformatic/config": "2.38.0",
29
+ "@platformatic/telemetry": "2.38.0",
30
+ "@platformatic/metrics": "2.38.0",
31
+ "@platformatic/utils": "2.38.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "borp": "^0.19.0",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/basic/2.37.1.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/basic/2.38.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Stackable",
5
5
  "type": "object",