@platformatic/runtime 1.24.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.
@@ -23,5 +23,10 @@
23
23
  "config": "platformatic.db.json"
24
24
  }
25
25
  }
26
+ },
27
+ "server": {
28
+ "logger": {
29
+ "level": "trace"
30
+ }
26
31
  }
27
32
  }
@@ -6,5 +6,9 @@
6
6
  "autoload": {
7
7
  "path": "./services"
8
8
  },
9
+ "server": {
10
+ "hostname": "127.0.0.1",
11
+ "port": 0
12
+ },
9
13
  "managementApi": true
10
14
  }
@@ -1,13 +1,5 @@
1
1
  {
2
2
  "$schema": "https://platformatic.dev/schemas/v1.22.0/service",
3
- "server": {
4
- "hostname": "127.0.0.1",
5
- "port": 0,
6
- "logger": {
7
- "name": "service-with-logger",
8
- "level": "trace"
9
- }
10
- },
11
3
  "service": {
12
4
  "openapi": true
13
5
  },
@@ -1,9 +1,5 @@
1
1
  {
2
2
  "$schema": "https://platformatic.dev/schemas/v1.22.0/service",
3
- "server": {
4
- "hostname": "127.0.0.1",
5
- "port": 0
6
- },
7
3
  "service": {
8
4
  "openapi": true
9
5
  },
package/lib/api.js CHANGED
@@ -61,8 +61,6 @@ class RuntimeApi {
61
61
  if (this.#dispatcher) {
62
62
  await this.#dispatcher.close()
63
63
  }
64
- await this.stopServices()
65
-
66
64
  setImmediate(process.exit) // Exit the worker thread.
67
65
  return
68
66
  }
package/lib/app.js CHANGED
@@ -248,10 +248,12 @@ class PlatformaticApp {
248
248
  }
249
249
 
250
250
  #setuplogger (configManager) {
251
- // Set the logger if not present
252
251
  configManager.current.server = configManager.current.server || {}
253
- const childLogger = this.#logger.child({}, { level: configManager.current.server.logger?.level || 'info' })
254
- configManager.current.server.logger = childLogger
252
+ const level = configManager.current.server.logger?.level
253
+
254
+ configManager.current.server.logger = level
255
+ ? this.#logger.child({ level })
256
+ : this.#logger
255
257
  }
256
258
 
257
259
  #startFileWatching () {
@@ -2,30 +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
- const { prettyFactory } = require('pino-pretty')
8
8
  const errors = require('./errors')
9
9
  const platformaticVersion = require('../package.json').version
10
10
 
11
- const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'pids')
12
-
13
- const pinoLogLevels = {
14
- fatal: 60,
15
- error: 50,
16
- warn: 40,
17
- info: 30,
18
- debug: 20,
19
- trace: 10
20
- }
11
+ const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
12
+ const runtimeTmpDir = join(PLATFORMATIC_TMP_DIR, process.pid.toString())
21
13
 
22
14
  async function createManagementApi (configManager, runtimeApiClient, loggingPort) {
23
- let apiConfig = configManager.current.managementApi
24
- if (!apiConfig || apiConfig === true) {
25
- apiConfig = {}
26
- }
27
-
28
- const app = fastify(apiConfig)
15
+ const app = fastify()
29
16
  app.log.warn(
30
17
  'Runtime Management API is in the experimental stage. ' +
31
18
  'The feature is not subject to semantic versioning rules. ' +
@@ -128,27 +115,10 @@ async function createManagementApi (configManager, runtimeApiClient, loggingPort
128
115
  .send(res.body)
129
116
  })
130
117
 
131
- app.get('/logs', { websocket: true }, async (connection, req) => {
132
- const logLevel = req.query.level || 'info'
133
- const pretty = req.query.pretty !== 'false'
134
- const serviceId = req.query.serviceId || null
135
-
136
- const logLevelNumber = pinoLogLevels[logLevel]
137
- const prettify = prettyFactory()
138
-
118
+ app.get('/logs/live', { websocket: true }, async (connection, req) => {
139
119
  const handler = (message) => {
140
- for (let log of message.logs) {
141
- try {
142
- const parsedLog = JSON.parse(log)
143
- if (parsedLog.level < logLevelNumber) continue
144
- if (serviceId && parsedLog.name !== serviceId) continue
145
- if (pretty) {
146
- log = prettify(parsedLog)
147
- }
148
- connection.socket.send(log)
149
- } catch (err) {
150
- console.error('Failed to parse log message: ', log, err)
151
- }
120
+ for (const log of message.logs) {
121
+ connection.socket.send(log)
152
122
  }
153
123
  }
154
124
 
@@ -163,7 +133,41 @@ async function createManagementApi (configManager, runtimeApiClient, loggingPort
163
133
  loggingPort.off('message', handler)
164
134
  })
165
135
  })
166
- }, { prefix: '/api' })
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
+ })
170
+ }, { prefix: '/api/v1' })
167
171
 
168
172
  return app
169
173
  }
@@ -175,12 +179,11 @@ async function startManagementApi (configManager, runtimeApiClient, loggingPort)
175
179
  if (platform() === 'win32') {
176
180
  socketPath = '\\\\.\\pipe\\platformatic-' + runtimePID
177
181
  } else {
178
- await mkdir(PLATFORMATIC_TMP_DIR, { recursive: true })
179
- socketPath = join(PLATFORMATIC_TMP_DIR, `${runtimePID}.sock`)
182
+ socketPath = join(runtimeTmpDir, 'socket')
180
183
  }
181
184
 
182
185
  try {
183
- await mkdir(PLATFORMATIC_TMP_DIR, { recursive: true })
186
+ await mkdir(runtimeTmpDir, { recursive: true })
184
187
  await unlink(socketPath).catch((err) => {
185
188
  if (err.code !== 'ENOENT') {
186
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,31 +37,41 @@ globalThis.fetch = undici.fetch
34
37
 
35
38
  const config = workerData.config
36
39
 
37
- let loggerConfig = config.server?.logger
38
-
39
- if (loggerConfig) {
40
- loggerConfig = { ...loggerConfig }
41
- } else {
42
- loggerConfig = {}
43
- }
40
+ function createLogger (config) {
41
+ const loggerConfig = { ...config.server?.logger }
42
+ const cliStream = isatty(1) ? pretty() : pino.destination(1)
44
43
 
45
- const cliStream = isatty(1) ? pretty() : pino.destination(1)
44
+ if (!config.loggingPort && !config.managementApi) {
45
+ return pino(loggerConfig, cliStream)
46
+ }
46
47
 
47
- let logger = null
48
- if (config.loggingPort) {
49
- const portStream = new MessagePortWritable({
50
- metadata: config.loggingMetadata,
51
- port: config.loggingPort
52
- })
53
48
  const multiStream = pino.multistream([
54
- { stream: portStream, level: 'trace' },
55
49
  { stream: cliStream, level: loggerConfig.level || 'info' }
56
50
  ])
57
- logger = pino({ level: 'trace' }, multiStream)
58
- } else {
59
- logger = pino(loggerConfig, cliStream)
51
+
52
+ if (loggerConfig.transport) {
53
+ const transport = pino.transport(loggerConfig.transport)
54
+ multiStream.add({ level: loggerConfig.level || 'info', stream: transport })
55
+ }
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)
60
72
  }
61
73
 
74
+ const logger = createLogger(config)
62
75
  if (config.server) {
63
76
  config.server.logger = logger
64
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "1.24.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-graphql": "1.24.0",
36
- "@platformatic/sql-mapper": "1.24.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.24.0",
59
- "@platformatic/config": "1.24.0",
60
- "@platformatic/db": "1.24.0",
61
- "@platformatic/generators": "1.24.0",
62
- "@platformatic/service": "1.24.0",
63
- "@platformatic/telemetry": "1.24.0",
64
- "@platformatic/utils": "1.24.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": [