@platformatic/control 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.
- package/lib/logs.js +35 -14
- package/lib/runtime-api-client.js +51 -24
- package/package.json +3 -3
package/lib/logs.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { parseArgs } = require('node:util')
|
|
4
|
+
const { prettyFactory } = require('pino-pretty')
|
|
4
5
|
const RuntimeApiClient = require('./runtime-api-client')
|
|
5
6
|
|
|
7
|
+
const pinoLogLevels = {
|
|
8
|
+
fatal: 60,
|
|
9
|
+
error: 50,
|
|
10
|
+
warn: 40,
|
|
11
|
+
info: 30,
|
|
12
|
+
debug: 20,
|
|
13
|
+
trace: 10
|
|
14
|
+
}
|
|
15
|
+
|
|
6
16
|
async function streamRuntimeLogsCommand (argv) {
|
|
7
17
|
const args = parseArgs({
|
|
8
18
|
args: argv,
|
|
@@ -10,7 +20,7 @@ async function streamRuntimeLogsCommand (argv) {
|
|
|
10
20
|
pid: { type: 'string', short: 'p' },
|
|
11
21
|
name: { type: 'string', short: 'n' },
|
|
12
22
|
level: { type: 'string', short: 'l', default: 'info' },
|
|
13
|
-
pretty: { type: '
|
|
23
|
+
pretty: { type: 'string', default: 'true' },
|
|
14
24
|
service: { type: 'string', short: 's' }
|
|
15
25
|
},
|
|
16
26
|
strict: false
|
|
@@ -19,19 +29,30 @@ async function streamRuntimeLogsCommand (argv) {
|
|
|
19
29
|
const client = new RuntimeApiClient()
|
|
20
30
|
const runtime = await client.getMatchingRuntime(args)
|
|
21
31
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const logLevelNumber = pinoLogLevels[args.level]
|
|
33
|
+
const prettify = prettyFactory()
|
|
34
|
+
|
|
35
|
+
const logsStream = client.getRuntimeLiveLogsStream(runtime.pid)
|
|
36
|
+
|
|
37
|
+
logsStream.on('data', (data) => {
|
|
38
|
+
const logs = data.toString().split('\n').filter(Boolean)
|
|
39
|
+
|
|
40
|
+
for (let log of logs) {
|
|
41
|
+
try {
|
|
42
|
+
const parsedLog = JSON.parse(log)
|
|
43
|
+
if (parsedLog.level < logLevelNumber) continue
|
|
44
|
+
if (args.service && parsedLog.name !== args.service) continue
|
|
45
|
+
if (args.pretty !== 'false') {
|
|
46
|
+
log = prettify(parsedLog)
|
|
47
|
+
} else {
|
|
48
|
+
log += '\n'
|
|
49
|
+
}
|
|
50
|
+
process.stdout.write(log)
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error('Failed to parse log message: ', log, err)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
})
|
|
35
56
|
|
|
36
57
|
process.on('SIGINT', () => {
|
|
37
58
|
logsStream.destroy()
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
const { tmpdir, platform, EOL } = require('node:os')
|
|
4
4
|
const { join } = require('node:path')
|
|
5
5
|
const { exec, spawn } = require('node:child_process')
|
|
6
|
-
const { readdir } = require('node:fs/promises')
|
|
6
|
+
const { readdir, unlink, access } = require('node:fs/promises')
|
|
7
7
|
const { Readable } = require('node:stream')
|
|
8
8
|
const { Client } = require('undici')
|
|
9
9
|
const WebSocket = require('ws')
|
|
10
10
|
const errors = require('./errors.js')
|
|
11
11
|
|
|
12
|
-
const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', '
|
|
12
|
+
const PLATFORMATIC_TMP_DIR = join(tmpdir(), 'platformatic', 'runtimes')
|
|
13
13
|
const PLATFORMATIC_PIPE_PREFIX = '\\\\.\\pipe\\platformatic-'
|
|
14
14
|
|
|
15
15
|
class RuntimeApiClient {
|
|
@@ -44,16 +44,25 @@ class RuntimeApiClient {
|
|
|
44
44
|
})
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
const runtimes = []
|
|
48
|
+
for (let i = 0; i < runtimePIDs.length; i++) {
|
|
49
|
+
const runtimePID = runtimePIDs[i]
|
|
50
|
+
const metadataRequest = getMetadataRequests[i]
|
|
51
|
+
|
|
52
|
+
if (metadataRequest.status === 'rejected') {
|
|
53
|
+
await this.#removeRuntimeSocket(runtimePID).catch(() => {})
|
|
54
|
+
} else {
|
|
55
|
+
runtimes.push(metadataRequest.value)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return runtimes
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
async getRuntimeMetadata (pid) {
|
|
53
62
|
const client = this.#getUndiciClient(pid)
|
|
54
63
|
|
|
55
64
|
const { statusCode, body } = await client.request({
|
|
56
|
-
path: '/api/metadata',
|
|
65
|
+
path: '/api/v1/metadata',
|
|
57
66
|
method: 'GET'
|
|
58
67
|
})
|
|
59
68
|
|
|
@@ -70,7 +79,7 @@ class RuntimeApiClient {
|
|
|
70
79
|
const client = this.#getUndiciClient(pid)
|
|
71
80
|
|
|
72
81
|
const { statusCode, body } = await client.request({
|
|
73
|
-
path: '/api/services',
|
|
82
|
+
path: '/api/v1/services',
|
|
74
83
|
method: 'GET'
|
|
75
84
|
})
|
|
76
85
|
|
|
@@ -87,7 +96,7 @@ class RuntimeApiClient {
|
|
|
87
96
|
const client = this.#getUndiciClient(pid)
|
|
88
97
|
|
|
89
98
|
const { statusCode, body } = await client.request({
|
|
90
|
-
path: `/api/services/${serviceId}/config`,
|
|
99
|
+
path: `/api/v1/services/${serviceId}/config`,
|
|
91
100
|
method: 'GET'
|
|
92
101
|
})
|
|
93
102
|
|
|
@@ -104,7 +113,7 @@ class RuntimeApiClient {
|
|
|
104
113
|
const client = this.#getUndiciClient(pid)
|
|
105
114
|
|
|
106
115
|
const { statusCode, body } = await client.request({
|
|
107
|
-
path: '/api/config',
|
|
116
|
+
path: '/api/v1/config',
|
|
108
117
|
method: 'GET'
|
|
109
118
|
})
|
|
110
119
|
|
|
@@ -121,7 +130,7 @@ class RuntimeApiClient {
|
|
|
121
130
|
const client = this.#getUndiciClient(pid)
|
|
122
131
|
|
|
123
132
|
const { statusCode, body } = await client.request({
|
|
124
|
-
path: '/api/env',
|
|
133
|
+
path: '/api/v1/env',
|
|
125
134
|
method: 'GET'
|
|
126
135
|
})
|
|
127
136
|
|
|
@@ -148,7 +157,7 @@ class RuntimeApiClient {
|
|
|
148
157
|
const client = this.#getUndiciClient(pid)
|
|
149
158
|
|
|
150
159
|
const { statusCode, body } = await client.request({
|
|
151
|
-
path: '/api/reload',
|
|
160
|
+
path: '/api/v1/reload',
|
|
152
161
|
method: 'POST'
|
|
153
162
|
})
|
|
154
163
|
|
|
@@ -162,7 +171,7 @@ class RuntimeApiClient {
|
|
|
162
171
|
const client = this.#getUndiciClient(pid)
|
|
163
172
|
|
|
164
173
|
const { statusCode, body } = await client.request({
|
|
165
|
-
path: '/api/stop',
|
|
174
|
+
path: '/api/v1/stop',
|
|
166
175
|
method: 'POST'
|
|
167
176
|
})
|
|
168
177
|
|
|
@@ -172,15 +181,22 @@ class RuntimeApiClient {
|
|
|
172
181
|
}
|
|
173
182
|
}
|
|
174
183
|
|
|
175
|
-
|
|
184
|
+
getRuntimeLiveLogsStream (pid) {
|
|
176
185
|
const socketPath = this.#getSocketPathFromPid(pid)
|
|
177
|
-
let query = ''
|
|
178
|
-
if (options.level || options.pretty || options.serviceId) {
|
|
179
|
-
query = '?' + new URLSearchParams(options).toString()
|
|
180
|
-
}
|
|
181
186
|
|
|
182
187
|
const protocol = platform() === 'win32' ? 'ws+unix:' : 'ws+unix://'
|
|
183
|
-
const webSocketUrl = protocol + socketPath + ':/api/logs'
|
|
188
|
+
const webSocketUrl = protocol + socketPath + ':/api/v1/logs/live'
|
|
189
|
+
const webSocketStream = new WebSocketStream(webSocketUrl)
|
|
190
|
+
this.#webSockets.add(webSocketStream.ws)
|
|
191
|
+
|
|
192
|
+
return webSocketStream
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
getRuntimeHistoryLogsStream (pid) {
|
|
196
|
+
const socketPath = this.#getSocketPathFromPid(pid)
|
|
197
|
+
|
|
198
|
+
const protocol = platform() === 'win32' ? 'ws+unix:' : 'ws+unix://'
|
|
199
|
+
const webSocketUrl = protocol + socketPath + ':/api/v1/logs/history'
|
|
184
200
|
const webSocketStream = new WebSocketStream(webSocketUrl)
|
|
185
201
|
this.#webSockets.add(webSocketStream.ws)
|
|
186
202
|
|
|
@@ -191,7 +207,7 @@ class RuntimeApiClient {
|
|
|
191
207
|
const client = this.#getUndiciClient(pid)
|
|
192
208
|
|
|
193
209
|
const response = await client.request({
|
|
194
|
-
path: `/api/services/${serviceId}/proxy` + options.url,
|
|
210
|
+
path: `/api/v1/services/${serviceId}/proxy` + options.url,
|
|
195
211
|
method: options.method,
|
|
196
212
|
headers: options.headers,
|
|
197
213
|
query: options.query,
|
|
@@ -227,15 +243,19 @@ class RuntimeApiClient {
|
|
|
227
243
|
if (platform() === 'win32') {
|
|
228
244
|
return PLATFORMATIC_PIPE_PREFIX + pid
|
|
229
245
|
}
|
|
230
|
-
return join(PLATFORMATIC_TMP_DIR,
|
|
246
|
+
return join(PLATFORMATIC_TMP_DIR, pid.toString(), 'socket')
|
|
231
247
|
}
|
|
232
248
|
|
|
233
249
|
async #getUnixRuntimePIDs () {
|
|
234
|
-
|
|
250
|
+
try {
|
|
251
|
+
await access(PLATFORMATIC_TMP_DIR)
|
|
252
|
+
} catch {
|
|
253
|
+
return []
|
|
254
|
+
}
|
|
255
|
+
const runtimeDirs = await readdir(PLATFORMATIC_TMP_DIR)
|
|
235
256
|
const runtimePIDs = []
|
|
236
|
-
for (const
|
|
237
|
-
|
|
238
|
-
runtimePIDs.push(parseInt(runtimePID))
|
|
257
|
+
for (const runtimeDirName of runtimeDirs) {
|
|
258
|
+
runtimePIDs.push(parseInt(runtimeDirName))
|
|
239
259
|
}
|
|
240
260
|
return runtimePIDs
|
|
241
261
|
}
|
|
@@ -268,6 +288,13 @@ class RuntimeApiClient {
|
|
|
268
288
|
)
|
|
269
289
|
})
|
|
270
290
|
}
|
|
291
|
+
|
|
292
|
+
async #removeRuntimeSocket (pid) {
|
|
293
|
+
if (platform() !== 'win32') {
|
|
294
|
+
const socketPath = this.#getSocketPathFromPid(pid)
|
|
295
|
+
await unlink(socketPath)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
271
298
|
}
|
|
272
299
|
|
|
273
300
|
class WebSocketStream extends Readable {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/control",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "Platformatic Control",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
"split2": "^4.2.0",
|
|
25
25
|
"standard": "^17.1.0",
|
|
26
26
|
"tsd": "^0.30.4",
|
|
27
|
-
"@platformatic/runtime": "1.
|
|
27
|
+
"@platformatic/runtime": "1.26.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@fastify/error": "^3.4.1",
|
|
31
31
|
"commist": "^3.2.0",
|
|
32
|
+
"help-me": "^5.0.0",
|
|
32
33
|
"pino": "^8.17.2",
|
|
33
34
|
"pino-pretty": "^10.3.1",
|
|
34
|
-
"help-me": "^5.0.0",
|
|
35
35
|
"table": "^6.8.1",
|
|
36
36
|
"undici": "^6.6.0",
|
|
37
37
|
"ws": "^8.16.0"
|