@platformatic/runtime 1.25.0 → 1.26.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.
@@ -2,20 +2,17 @@
2
2
 
3
3
  const { tmpdir, platform } = require('node:os')
4
4
  const { join } = require('node:path')
5
- const { readFile, mkdir, unlink } = require('node:fs/promises')
5
+ const { createReadStream } = require('node:fs')
6
+ const { readFile, readdir, mkdir, unlink } = require('node:fs/promises')
6
7
  const fastify = require('fastify')
7
8
  const errors = require('./errors')
8
9
  const platformaticVersion = require('../package.json').version
9
10
 
10
- const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'pids')
11
+ const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
12
+ const runtimeTmpDir = join(PLATFORMATIC_TMP_DIR, process.pid.toString())
11
13
 
12
14
  async function createManagementApi (configManager, runtimeApiClient, loggingPort) {
13
- let apiConfig = configManager.current.managementApi
14
- if (!apiConfig || apiConfig === true) {
15
- apiConfig = {}
16
- }
17
-
18
- const app = fastify(apiConfig)
15
+ const app = fastify()
19
16
  app.log.warn(
20
17
  'Runtime Management API is in the experimental stage. ' +
21
18
  'The feature is not subject to semantic versioning rules. ' +
@@ -118,7 +115,7 @@ async function createManagementApi (configManager, runtimeApiClient, loggingPort
118
115
  .send(res.body)
119
116
  })
120
117
 
121
- app.get('/logs', { websocket: true }, async (connection, req) => {
118
+ app.get('/logs/live', { websocket: true }, async (connection, req) => {
122
119
  const handler = (message) => {
123
120
  for (const log of message.logs) {
124
121
  connection.socket.send(log)
@@ -136,6 +133,40 @@ async function createManagementApi (configManager, runtimeApiClient, loggingPort
136
133
  loggingPort.off('message', handler)
137
134
  })
138
135
  })
136
+
137
+ app.get('/logs/history', { websocket: true }, async (connection, req) => {
138
+ const runtimeTmpFiles = await readdir(runtimeTmpDir)
139
+ const runtimeLogFiles = runtimeTmpFiles
140
+ .filter((file) => file.startsWith('logs'))
141
+ .map((file) => join(runtimeTmpDir, file))
142
+ .sort()
143
+
144
+ if (runtimeLogFiles.length === 0) {
145
+ connection.end()
146
+ return
147
+ }
148
+
149
+ const streamLogFile = (fileIndex) => {
150
+ const file = runtimeLogFiles[fileIndex]
151
+ const isLastFile = fileIndex === runtimeLogFiles.length - 1
152
+
153
+ const stream = createReadStream(file)
154
+ stream.pipe(connection, { end: isLastFile })
155
+
156
+ stream.on('error', (err) => {
157
+ app.log.error(err, 'Error streaming log file')
158
+ connection.end()
159
+ })
160
+ stream.on('end', () => {
161
+ if (isLastFile) {
162
+ connection.end()
163
+ return
164
+ }
165
+ streamLogFile(fileIndex + 1)
166
+ })
167
+ }
168
+ streamLogFile(0)
169
+ })
139
170
  }, { prefix: '/api/v1' })
140
171
 
141
172
  return app
@@ -148,12 +179,11 @@ async function startManagementApi (configManager, runtimeApiClient, loggingPort)
148
179
  if (platform() === 'win32') {
149
180
  socketPath = '\\\\.\\pipe\\platformatic-' + runtimePID
150
181
  } else {
151
- await mkdir(PLATFORMATIC_TMP_DIR, { recursive: true })
152
- socketPath = join(PLATFORMATIC_TMP_DIR, `${runtimePID}.sock`)
182
+ socketPath = join(runtimeTmpDir, 'socket')
153
183
  }
154
184
 
155
185
  try {
156
- await mkdir(PLATFORMATIC_TMP_DIR, { recursive: true })
186
+ await mkdir(runtimeTmpDir, { recursive: true })
157
187
  await unlink(socketPath).catch((err) => {
158
188
  if (err.code !== 'ENOENT') {
159
189
  throw new errors.FailedToUnlinkManagementApiSocket(err.message)
package/lib/worker.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const inspector = require('node:inspector')
4
+ const { tmpdir } = require('node:os')
4
5
  const { register, createRequire } = require('node:module')
5
6
  const { isatty } = require('node:tty')
6
7
  const { pathToFileURL } = require('node:url')
@@ -18,6 +19,8 @@ const RuntimeApi = require('./api')
18
19
  const { MessagePortWritable } = require('./message-port-writable')
19
20
  let loaderPort
20
21
 
22
+ const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
23
+
21
24
  if (typeof register === 'function' && workerData.config.loaderFile) {
22
25
  const { port1, port2 } = new MessageChannel()
23
26
  register(workerData.config.loaderFile, {
@@ -34,28 +37,41 @@ globalThis.fetch = undici.fetch
34
37
 
35
38
  const config = workerData.config
36
39
 
37
- const loggerConfig = { ...config.server?.logger }
38
- const cliStream = isatty(1) ? pretty() : pino.destination(1)
40
+ function createLogger (config) {
41
+ const loggerConfig = { ...config.server?.logger }
42
+ const cliStream = isatty(1) ? pretty() : pino.destination(1)
43
+
44
+ if (!config.loggingPort && !config.managementApi) {
45
+ return pino(loggerConfig, cliStream)
46
+ }
39
47
 
40
- let logger = null
41
- if (config.loggingPort) {
42
- const portStream = new MessagePortWritable({
43
- metadata: config.loggingMetadata,
44
- port: config.loggingPort
45
- })
46
48
  const multiStream = pino.multistream([
47
- { stream: portStream, level: 'trace' },
48
49
  { stream: cliStream, level: loggerConfig.level || 'info' }
49
50
  ])
51
+
50
52
  if (loggerConfig.transport) {
51
53
  const transport = pino.transport(loggerConfig.transport)
52
54
  multiStream.add({ level: loggerConfig.level || 'info', stream: transport })
53
55
  }
54
- logger = pino({ level: 'trace' }, multiStream)
55
- } else {
56
- logger = pino(loggerConfig, cliStream)
56
+ if (config.loggingPort) {
57
+ const portStream = new MessagePortWritable({
58
+ metadata: config.loggingMetadata,
59
+ port: config.loggingPort
60
+ })
61
+ multiStream.add({ level: 'trace', stream: portStream })
62
+ }
63
+ if (config.managementApi) {
64
+ const logsPath = join(PLATFORMATIC_TMP_DIR, process.pid.toString(), 'logs')
65
+ const pinoRoll = pino.transport({
66
+ target: 'pino-roll',
67
+ options: { file: logsPath, size: '5m', mkdir: true }
68
+ })
69
+ multiStream.add({ level: 'trace', stream: pinoRoll })
70
+ }
71
+ return pino({ level: 'trace' }, multiStream)
57
72
  }
58
73
 
74
+ const logger = createLogger(config)
59
75
  if (config.server) {
60
76
  config.server.logger = logger
61
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -32,8 +32,8 @@
32
32
  "typescript": "^5.3.3",
33
33
  "undici-oauth-interceptor": "^0.4.2",
34
34
  "ws": "^8.16.0",
35
- "@platformatic/sql-mapper": "1.25.0",
36
- "@platformatic/sql-graphql": "1.25.0"
35
+ "@platformatic/sql-graphql": "1.26.0",
36
+ "@platformatic/sql-mapper": "1.26.0"
37
37
  },
38
38
  "dependencies": {
39
39
  "@fastify/error": "^3.4.1",
@@ -53,15 +53,16 @@
53
53
  "minimist": "^1.2.8",
54
54
  "pino": "^8.17.2",
55
55
  "pino-pretty": "^10.3.1",
56
+ "pino-roll": "1.0.0-rc.1",
56
57
  "undici": "^6.6.0",
57
58
  "why-is-node-running": "^2.2.2",
58
- "@platformatic/composer": "1.25.0",
59
- "@platformatic/config": "1.25.0",
60
- "@platformatic/generators": "1.25.0",
61
- "@platformatic/service": "1.25.0",
62
- "@platformatic/telemetry": "1.25.0",
63
- "@platformatic/db": "1.25.0",
64
- "@platformatic/utils": "1.25.0"
59
+ "@platformatic/composer": "1.26.0",
60
+ "@platformatic/config": "1.26.0",
61
+ "@platformatic/generators": "1.26.0",
62
+ "@platformatic/db": "1.26.0",
63
+ "@platformatic/service": "1.26.0",
64
+ "@platformatic/utils": "1.26.0",
65
+ "@platformatic/telemetry": "1.26.0"
65
66
  },
66
67
  "standard": {
67
68
  "ignore": [