@platformatic/runtime 3.38.1 → 3.39.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/config.d.ts CHANGED
@@ -167,6 +167,10 @@ export type PlatformaticRuntimeConfig = {
167
167
  customLevels?: {
168
168
  [k: string]: unknown;
169
169
  };
170
+ openTelemetryExporter?: {
171
+ protocol: "grpc" | "http";
172
+ url: string;
173
+ };
170
174
  captureStdio?: boolean;
171
175
  [k: string]: unknown;
172
176
  };
package/lib/logger.js CHANGED
@@ -178,6 +178,31 @@ export async function createLogger (config) {
178
178
 
179
179
  const multiStream = pino.multistream([{ stream: cliStream, level: loggerConfig.level }])
180
180
 
181
+ if (config.telemetry && config.logger.openTelemetryExporter) {
182
+ multiStream.add(
183
+ pino.transport({
184
+ target: 'pino-opentelemetry-transport',
185
+ options: {
186
+ resourceAttributes: {
187
+ 'service.name': config.telemetry.applicationName,
188
+ 'service.version': config.telemetry.version
189
+ },
190
+ logRecordProcessorOptions: [
191
+ {
192
+ recordProcessorType: 'simple',
193
+ exporterOptions: {
194
+ protocol: config.logger.openTelemetryExporter.protocol,
195
+ httpExporterOptions: {
196
+ url: config.logger.openTelemetryExporter.url
197
+ }
198
+ }
199
+ }
200
+ ]
201
+ }
202
+ })
203
+ )
204
+ }
205
+
181
206
  const logsFileMb = 5
182
207
  const logsLimitMb = config.managementApi?.logs?.maxSize || 200
183
208
 
package/lib/runtime.js CHANGED
@@ -46,7 +46,7 @@ import { createChannelCreationHook } from './policies.js'
46
46
  import { startPrometheusServer } from './prom-server.js'
47
47
  import { startScheduler } from './scheduler.js'
48
48
  import { createSharedStore } from './shared-http-cache.js'
49
- import { topologicalSort } from './utils.js'
49
+ import { topologicalLevels, topologicalSort } from './utils.js'
50
50
  import { version } from './version.js'
51
51
  import { DynamicWorkersScaler } from './worker-scaler.js'
52
52
  import { HealthSignalsQueue } from './worker/health-signals.js'
@@ -560,12 +560,15 @@ export class Runtime extends EventEmitter {
560
560
  // If circular dependencies are detected, an error with proper error code is thrown.
561
561
  applications = topologicalSort(dependencies)
562
562
 
563
- const startInvocations = []
564
- for (const application of applications) {
565
- startInvocations.push([application, silent])
566
- }
563
+ // Group into dependency levels so that each level's dependencies are all
564
+ // in previous levels. Levels are started sequentially, but applications
565
+ // within the same level start in parallel.
566
+ const levels = topologicalLevels(applications, dependencies)
567
567
 
568
- return executeInParallel(this.startApplication.bind(this), startInvocations, this.#concurrency)
568
+ for (const level of levels) {
569
+ const startInvocations = level.map(app => [app, silent])
570
+ await executeInParallel(this.startApplication.bind(this), startInvocations, this.#concurrency)
571
+ }
569
572
  }
570
573
 
571
574
  async stopApplications (applicationsToStop, silent = false, skipDependencies = false) {
package/lib/utils.js CHANGED
@@ -19,6 +19,35 @@ export function getRuntimeTmpDir (runtimeDir) {
19
19
  return join(platformaticTmpDir, runtimeDirHash)
20
20
  }
21
21
 
22
+ // Given a topologically sorted list and the dependency graph,
23
+ // group nodes into levels where each level's dependencies are all in previous levels.
24
+ // This allows starting each level in parallel while respecting dependency order.
25
+ export function topologicalLevels (sorted, graph) {
26
+ const levels = []
27
+ const levelOf = new Map()
28
+
29
+ for (const node of sorted) {
30
+ const deps = graph.get(node) ?? []
31
+ let level = 0
32
+
33
+ for (const dep of deps) {
34
+ if (levelOf.has(dep)) {
35
+ level = Math.max(level, levelOf.get(dep) + 1)
36
+ }
37
+ }
38
+
39
+ levelOf.set(node, level)
40
+
41
+ while (levels.length <= level) {
42
+ levels.push([])
43
+ }
44
+
45
+ levels[level].push(node)
46
+ }
47
+
48
+ return levels
49
+ }
50
+
22
51
  // Graph: Map<string, string[]>
23
52
  export function topologicalSort (graph) {
24
53
  const result = []
@@ -5,6 +5,7 @@ import {
5
5
  ensureLoggableError,
6
6
  getPrivateSymbol
7
7
  } from '@platformatic/foundation'
8
+ import { addPinoInstrumentation } from '@platformatic/telemetry'
8
9
  import { subscribe } from 'node:diagnostics_channel'
9
10
  import { EventEmitter } from 'node:events'
10
11
  import { ServerResponse } from 'node:http'
@@ -93,6 +94,10 @@ function createLogger () {
93
94
  pinoOptions.timestamp = buildPinoTimestamp(pinoOptions.timestamp)
94
95
  }
95
96
 
97
+ if (workerData.config.logger?.openTelemetryExporter && workerData.applicationConfig.telemetry?.enabled !== false) {
98
+ addPinoInstrumentation(pinoOptions)
99
+ }
100
+
96
101
  return pino(pinoOptions)
97
102
  }
98
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "3.38.1",
3
+ "version": "3.39.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -35,14 +35,14 @@
35
35
  "typescript": "^5.5.4",
36
36
  "undici-oidc-interceptor": "^0.5.0",
37
37
  "why-is-node-running": "^2.2.2",
38
- "@platformatic/db": "3.38.1",
39
- "@platformatic/gateway": "3.38.1",
40
- "@platformatic/composer": "3.38.1",
41
- "@platformatic/node": "3.38.1",
42
- "@platformatic/service": "3.38.1",
43
- "@platformatic/sql-graphql": "3.38.1",
44
- "@platformatic/sql-mapper": "3.38.1",
45
- "@platformatic/wattpm-pprof-capture": "3.38.1"
38
+ "@platformatic/composer": "3.39.0",
39
+ "@platformatic/db": "3.39.0",
40
+ "@platformatic/service": "3.39.0",
41
+ "@platformatic/node": "3.39.0",
42
+ "@platformatic/sql-graphql": "3.39.0",
43
+ "@platformatic/gateway": "3.39.0",
44
+ "@platformatic/wattpm-pprof-capture": "3.39.0",
45
+ "@platformatic/sql-mapper": "3.39.0"
46
46
  },
47
47
  "dependencies": {
48
48
  "@fastify/accepts": "^5.0.0",
@@ -50,6 +50,7 @@
50
50
  "@fastify/error": "^4.0.0",
51
51
  "@fastify/websocket": "^11.0.0",
52
52
  "@opentelemetry/api": "^1.9.0",
53
+ "@platformatic/prom-client": "^1.0.0",
53
54
  "@platformatic/undici-cache-memory": "^0.8.1",
54
55
  "@watchable/unpromise": "^1.0.2",
55
56
  "change-case-all": "^2.1.0",
@@ -63,20 +64,20 @@
63
64
  "help-me": "^5.0.0",
64
65
  "minimist": "^1.2.8",
65
66
  "pino": "^9.9.0",
67
+ "pino-opentelemetry-transport": "^2.0.0",
66
68
  "pino-pretty": "^13.0.0",
67
- "@platformatic/prom-client": "^1.0.0",
68
69
  "semgrator": "^0.3.0",
69
70
  "sonic-boom": "^4.2.0",
70
71
  "systeminformation": "^5.27.11",
71
72
  "undici": "^7.0.0",
72
73
  "undici-thread-interceptor": "^1.3.1",
73
74
  "ws": "^8.16.0",
74
- "@platformatic/basic": "3.38.1",
75
- "@platformatic/foundation": "3.38.1",
76
- "@platformatic/generators": "3.38.1",
77
- "@platformatic/metrics": "3.38.1",
78
- "@platformatic/itc": "3.38.1",
79
- "@platformatic/telemetry": "3.38.1"
75
+ "@platformatic/basic": "3.39.0",
76
+ "@platformatic/generators": "3.39.0",
77
+ "@platformatic/itc": "3.39.0",
78
+ "@platformatic/telemetry": "3.39.0",
79
+ "@platformatic/foundation": "3.39.0",
80
+ "@platformatic/metrics": "3.39.0"
80
81
  },
81
82
  "engines": {
82
83
  "node": ">=22.19.0"
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.38.1.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.39.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Runtime Config",
5
5
  "type": "object",
@@ -1578,6 +1578,26 @@
1578
1578
  "type": "object",
1579
1579
  "additionalProperties": true
1580
1580
  },
1581
+ "openTelemetryExporter": {
1582
+ "type": "object",
1583
+ "properties": {
1584
+ "protocol": {
1585
+ "type": "string",
1586
+ "enum": [
1587
+ "grpc",
1588
+ "http"
1589
+ ]
1590
+ },
1591
+ "url": {
1592
+ "type": "string"
1593
+ }
1594
+ },
1595
+ "required": [
1596
+ "protocol",
1597
+ "url"
1598
+ ],
1599
+ "additionalProperties": false
1600
+ },
1581
1601
  "captureStdio": {
1582
1602
  "type": "boolean",
1583
1603
  "default": true