deepline 0.1.222 → 0.1.224

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.
@@ -15,6 +15,13 @@ import {
15
15
  WorkflowEntrypoint,
16
16
  exports as workersExports,
17
17
  } from 'cloudflare:workers';
18
+ import {
19
+ createWorkerTelemetry,
20
+ type TelemetryEvent,
21
+ type TelemetryFields,
22
+ type TelemetryScalar,
23
+ } from '../../../shared_libs/observability/worker-telemetry';
24
+ import { createSecretRedactionContext } from '../../../shared_libs/play-runtime/secret-redaction';
18
25
  import {
19
26
  _dispatcherBindingImpl as createDispatcherWorkflowBinding,
20
27
  dispatchWorkflow,
@@ -83,6 +90,59 @@ import {
83
90
 
84
91
  export { DynamicWorkflowBinding };
85
92
 
93
+ const coordinatorTelemetry = createWorkerTelemetry({
94
+ service: 'play-runtime',
95
+ component: 'coordinator',
96
+ });
97
+ const coordinatorStorageRedactor = createSecretRedactionContext();
98
+ const coordinatorPerfTelemetry = createWorkerTelemetry({
99
+ service: 'play-runtime',
100
+ component: 'coordinator',
101
+ adapter: {
102
+ emit(event: TelemetryEvent) {
103
+ console.log(`[perf-trace] ${JSON.stringify(event)}`);
104
+ },
105
+ },
106
+ });
107
+
108
+ function coordinatorTelemetryFields(input: object): TelemetryFields {
109
+ const fields: Record<string, TelemetryScalar> = {};
110
+ for (const [key, value] of Object.entries(input)) {
111
+ if (
112
+ value === undefined ||
113
+ value === null ||
114
+ typeof value === 'string' ||
115
+ typeof value === 'number' ||
116
+ typeof value === 'boolean'
117
+ ) {
118
+ fields[key] = value;
119
+ }
120
+ }
121
+ return fields;
122
+ }
123
+
124
+ function recordCoordinatorEvent(
125
+ level: 'info' | 'warn' | 'error',
126
+ event: string,
127
+ tag: string,
128
+ input: Record<string, unknown> = {},
129
+ ): void {
130
+ const telemetry = coordinatorTelemetry.child({
131
+ context: {
132
+ runId: typeof input.runId === 'string' ? input.runId : null,
133
+ orgId: typeof input.orgId === 'string' ? input.orgId : null,
134
+ playName: typeof input.playName === 'string' ? input.playName : null,
135
+ requestId: typeof input.requestId === 'string' ? input.requestId : null,
136
+ },
137
+ });
138
+ const fields = coordinatorTelemetryFields(input);
139
+ if (level === 'error') {
140
+ void telemetry.error(event, input.error ?? input.message, fields, { tag });
141
+ } else {
142
+ void telemetry[level](event, fields, { tag });
143
+ }
144
+ }
145
+
86
146
  export type PlayWorkflowParams = {
87
147
  runId: string;
88
148
  playId: string;
@@ -389,7 +449,11 @@ function buildCoordinatorPerfTracePayload(
389
449
  }
390
450
 
391
451
  function logCoordinatorPerfTrace(payload: CoordinatorPerfTracePayload): void {
392
- console.log(`[perf-trace] ${JSON.stringify(payload)}`);
452
+ void coordinatorPerfTelemetry
453
+ .child({ context: { runId: payload.runId } })
454
+ .info(payload.phase, coordinatorTelemetryFields(payload), {
455
+ tag: '[perf-trace]',
456
+ });
393
457
  }
394
458
 
395
459
  function recordCoordinatorPerfTrace(event: CoordinatorPerfTraceInput): void {
@@ -417,7 +481,7 @@ async function appendCoordinatorPerfTrace(
417
481
  {
418
482
  method: 'POST',
419
483
  headers: { 'content-type': 'application/json' },
420
- body: JSON.stringify(payload),
484
+ body: JSON.stringify(coordinatorStorageRedactor.redact(payload)),
421
485
  },
422
486
  );
423
487
  if (!response.ok) {
@@ -438,11 +502,16 @@ function recordCoordinatorPerfTraceBuffered(
438
502
  if (!payload) return;
439
503
  logCoordinatorPerfTrace(payload);
440
504
  const append = appendCoordinatorPerfTrace(env, payload).catch((error) => {
441
- console.warn('[coordinator] failed to buffer perf trace', {
442
- runId: payload.runId,
443
- phase: payload.phase,
444
- error: error instanceof Error ? error.message : String(error),
445
- });
505
+ return coordinatorTelemetry
506
+ .child({ context: { runId: payload.runId } })
507
+ .warn(
508
+ 'coordinator.perf_trace.buffer_failed',
509
+ {
510
+ phase: payload.phase,
511
+ error: error instanceof Error ? error.message : String(error),
512
+ },
513
+ { tag: '[coordinator] failed to buffer perf trace' },
514
+ );
446
515
  });
447
516
  if (typeof ctx?.waitUntil === 'function') {
448
517
  ctx.waitUntil(append);
@@ -595,7 +664,7 @@ async function writeCoordinatorChildTerminalState(input: {
595
664
  headers: { 'content-type': 'application/json' },
596
665
  body: JSON.stringify({
597
666
  eventKey: input.eventKey,
598
- data: input.data,
667
+ data: coordinatorStorageRedactor.redact(input.data),
599
668
  storedAt: Date.now(),
600
669
  }),
601
670
  },
@@ -858,12 +927,17 @@ async function callRunScopedControl<T>(
858
927
  } catch (error) {
859
928
  const handoffMessage = durableObjectDeployHandoffMessage(error);
860
929
  if (handoffMessage && attempt < maxAttempts) {
861
- console.warn('[coordinator] run state DO deploy handoff retry', {
862
- runId,
863
- path,
864
- attempt,
865
- error: handoffMessage,
866
- });
930
+ recordCoordinatorEvent(
931
+ 'warn',
932
+ 'coordinator.run_state.handoff_retry',
933
+ '[coordinator] run state DO deploy handoff retry',
934
+ {
935
+ runId,
936
+ path,
937
+ attempt,
938
+ error: handoffMessage,
939
+ },
940
+ );
867
941
  await sleepForDurableObjectDeployHandoffRetry(attempt - 1);
868
942
  continue;
869
943
  }
@@ -877,13 +951,18 @@ async function callRunScopedControl<T>(
877
951
  const responseText = (await response.text().catch(() => '')).slice(0, 400);
878
952
  const handoffMessage = durableObjectDeployHandoffMessage(responseText);
879
953
  if (handoffMessage && attempt < maxAttempts) {
880
- console.warn('[coordinator] run state DO deploy handoff retry', {
881
- runId,
882
- path,
883
- attempt,
884
- status: response.status,
885
- error: handoffMessage,
886
- });
954
+ recordCoordinatorEvent(
955
+ 'warn',
956
+ 'coordinator.run_state.handoff_retry',
957
+ '[coordinator] run state DO deploy handoff retry',
958
+ {
959
+ runId,
960
+ path,
961
+ attempt,
962
+ status: response.status,
963
+ error: handoffMessage,
964
+ },
965
+ );
887
966
  await sleepForDurableObjectDeployHandoffRetry(attempt - 1);
888
967
  continue;
889
968
  }
@@ -1341,14 +1420,19 @@ async function markWorkflowRuntimeFailure(input: {
1341
1420
  const response = await fetch(url, { method: 'POST', headers, body });
1342
1421
  if (response.ok) {
1343
1422
  if (attempt > 0) {
1344
- console.info('[coordinator.runtime_api.retry]', {
1345
- action: 'append_run_events',
1346
- status: 'ok',
1347
- attempt,
1348
- runId,
1349
- requestId,
1350
- baseOrigin: safeOrigin(baseUrl),
1351
- });
1423
+ recordCoordinatorEvent(
1424
+ 'info',
1425
+ 'coordinator.runtime_api.retry',
1426
+ '[coordinator.runtime_api.retry]',
1427
+ {
1428
+ action: 'append_run_events',
1429
+ status: 'ok',
1430
+ attempt,
1431
+ runId,
1432
+ requestId,
1433
+ baseOrigin: safeOrigin(baseUrl),
1434
+ },
1435
+ );
1352
1436
  }
1353
1437
  return;
1354
1438
  }
@@ -1367,26 +1451,37 @@ async function markWorkflowRuntimeFailure(input: {
1367
1451
  lastError = error;
1368
1452
  }
1369
1453
  if (attempt < backoffMs.length) {
1370
- console.warn('[coordinator.runtime_api.retry]', {
1371
- action: 'append_run_events',
1372
- status: 'retry',
1373
- attempt: attempt + 1,
1374
- retryDelayMs: backoffMs[attempt],
1375
- runId,
1376
- requestId,
1377
- baseOrigin: safeOrigin(baseUrl),
1378
- error:
1379
- lastError instanceof Error
1380
- ? lastError.message.slice(0, 300)
1381
- : String(lastError).slice(0, 300),
1382
- });
1454
+ recordCoordinatorEvent(
1455
+ 'warn',
1456
+ 'coordinator.runtime_api.retry',
1457
+ '[coordinator.runtime_api.retry]',
1458
+ {
1459
+ action: 'append_run_events',
1460
+ status: 'retry',
1461
+ attempt: attempt + 1,
1462
+ retryDelayMs: backoffMs[attempt],
1463
+ runId,
1464
+ requestId,
1465
+ baseOrigin: safeOrigin(baseUrl),
1466
+ error:
1467
+ lastError instanceof Error
1468
+ ? lastError.message.slice(0, 300)
1469
+ : String(lastError).slice(0, 300),
1470
+ },
1471
+ );
1383
1472
  await new Promise((resolve) => setTimeout(resolve, backoffMs[attempt]));
1384
1473
  }
1385
1474
  }
1386
- console.error('[coordinator] failed to mark workflow runtime failure', {
1387
- runId,
1388
- message: lastError instanceof Error ? lastError.message : String(lastError),
1389
- });
1475
+ recordCoordinatorEvent(
1476
+ 'error',
1477
+ 'coordinator.workflow_runtime_failure.mark_failed',
1478
+ '[coordinator] failed to mark workflow runtime failure',
1479
+ {
1480
+ runId,
1481
+ message:
1482
+ lastError instanceof Error ? lastError.message : String(lastError),
1483
+ },
1484
+ );
1390
1485
  }
1391
1486
 
1392
1487
  async function appendWorkflowChildCompletedRunEvent(input: {
@@ -1767,10 +1862,15 @@ async function restartWorkflowAfterPlatformReset(input: {
1767
1862
  env: input.env,
1768
1863
  runId: input.runId,
1769
1864
  }).catch((error) => {
1770
- console.warn('[coordinator] workflow platform retry claim failed', {
1771
- runId: input.runId,
1772
- error: error instanceof Error ? error.message : String(error),
1773
- });
1865
+ recordCoordinatorEvent(
1866
+ 'warn',
1867
+ 'coordinator.workflow_platform_retry.claim_failed',
1868
+ '[coordinator] workflow platform retry claim failed',
1869
+ {
1870
+ runId: input.runId,
1871
+ error: error instanceof Error ? error.message : String(error),
1872
+ },
1873
+ );
1774
1874
  return null;
1775
1875
  });
1776
1876
  if (!claim?.claimed || !claim.params) {
@@ -1968,13 +2068,18 @@ async function callRuntimeApiFromCoordinator(input: {
1968
2068
  '',
1969
2069
  ) || null
1970
2070
  : null;
1971
- console.info('[coordinator.runtime_api.breadcrumb]', {
1972
- phase: 'request',
1973
- action,
1974
- runId,
1975
- requestId,
1976
- baseOrigin: safeOrigin(input.baseUrl),
1977
- });
2071
+ recordCoordinatorEvent(
2072
+ 'info',
2073
+ 'coordinator.runtime_api.breadcrumb',
2074
+ '[coordinator.runtime_api.breadcrumb]',
2075
+ {
2076
+ phase: 'request',
2077
+ action,
2078
+ runId,
2079
+ requestId,
2080
+ baseOrigin: safeOrigin(input.baseUrl),
2081
+ },
2082
+ );
1978
2083
  const response = await input.env.HARNESS.runtimeApiCall({
1979
2084
  contract: PLAY_RUNTIME_CONTRACT,
1980
2085
  executorToken: input.executorToken,
@@ -1987,15 +2092,20 @@ async function callRuntimeApiFromCoordinator(input: {
1987
2092
  },
1988
2093
  });
1989
2094
  recordTiming('coordinator.runtime_api.fetch', fetchStartedAt);
1990
- console.info('[coordinator.runtime_api.breadcrumb]', {
1991
- phase: 'response',
1992
- action,
1993
- runId,
1994
- requestId,
1995
- status: response.status,
1996
- ms: Date.now() - fetchStartedAt,
1997
- baseOrigin: safeOrigin(input.baseUrl),
1998
- });
2095
+ recordCoordinatorEvent(
2096
+ 'info',
2097
+ 'coordinator.runtime_api.breadcrumb',
2098
+ '[coordinator.runtime_api.breadcrumb]',
2099
+ {
2100
+ phase: 'response',
2101
+ action,
2102
+ runId,
2103
+ requestId,
2104
+ status: response.status,
2105
+ ms: Date.now() - fetchStartedAt,
2106
+ baseOrigin: safeOrigin(input.baseUrl),
2107
+ },
2108
+ );
1999
2109
 
2000
2110
  const bodyStartedAt = Date.now();
2001
2111
  const responseBody = response.body;
@@ -3031,7 +3141,9 @@ async function submitChildWorkflowThroughCoordinator(input: {
3031
3141
  childRunId,
3032
3142
  error,
3033
3143
  }).catch((markError) => {
3034
- console.error(
3144
+ recordCoordinatorEvent(
3145
+ 'error',
3146
+ 'coordinator.child_workflow_submit.failure_mark_failed',
3035
3147
  '[coordinator] child workflow submit failure mark failed',
3036
3148
  {
3037
3149
  childRunId,
@@ -3088,11 +3200,16 @@ async function submitChildWorkflowThroughCoordinator(input: {
3088
3200
  childRunId,
3089
3201
  error: `workflow submit returned ${response.status}: ${responseText.slice(0, 800)}`,
3090
3202
  }).catch((markError) => {
3091
- console.error('[coordinator] child workflow submit failure mark failed', {
3092
- childRunId,
3093
- error:
3094
- markError instanceof Error ? markError.message : String(markError),
3095
- });
3203
+ recordCoordinatorEvent(
3204
+ 'error',
3205
+ 'coordinator.child_workflow_submit.failure_mark_failed',
3206
+ '[coordinator] child workflow submit failure mark failed',
3207
+ {
3208
+ childRunId,
3209
+ error:
3210
+ markError instanceof Error ? markError.message : String(markError),
3211
+ },
3212
+ );
3096
3213
  });
3097
3214
  }
3098
3215
  return {
@@ -3159,9 +3276,16 @@ export class RuntimeApi extends WorkerEntrypoint<CoordinatorEnv, undefined> {
3159
3276
  .clone()
3160
3277
  .text()
3161
3278
  .catch(() => '');
3162
- console.error(
3163
- `[RUNTIME_API] ${incoming.pathname} failed: status=${res.status} ` +
3164
- `target=${target.toString()} body=${body.slice(0, 500)}`,
3279
+ recordCoordinatorEvent(
3280
+ 'error',
3281
+ 'coordinator.runtime_api.proxy_failed',
3282
+ '[RUNTIME_API] request failed',
3283
+ {
3284
+ path: incoming.pathname,
3285
+ status: res.status,
3286
+ targetOrigin: target.origin,
3287
+ body: body.slice(0, 500),
3288
+ },
3165
3289
  );
3166
3290
  }
3167
3291
  return res;
@@ -3394,10 +3518,15 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
3394
3518
  status: 'running',
3395
3519
  ts: Date.now(),
3396
3520
  }).catch((error) => {
3397
- console.warn('[coordinator] workflow entry status event failed', {
3398
- runId: entryTrace.runId,
3399
- error: error instanceof Error ? error.message : String(error),
3400
- });
3521
+ recordCoordinatorEvent(
3522
+ 'warn',
3523
+ 'coordinator.workflow_entry.status_event_failed',
3524
+ '[coordinator] workflow entry status event failed',
3525
+ {
3526
+ runId: entryTrace.runId,
3527
+ error: error instanceof Error ? error.message : String(error),
3528
+ },
3529
+ );
3401
3530
  }),
3402
3531
  );
3403
3532
  }
@@ -3449,7 +3578,9 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
3449
3578
  event: dispatchedEvent,
3450
3579
  error: hydrateError,
3451
3580
  }).catch((markError) => {
3452
- console.error(
3581
+ recordCoordinatorEvent(
3582
+ 'error',
3583
+ 'coordinator.db_session_expired.failure_forward_failed',
3453
3584
  '[coordinator] failed to forward expired-db-session run failure',
3454
3585
  {
3455
3586
  runId: entryTrace.runId,
@@ -3586,7 +3717,9 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
3586
3717
  });
3587
3718
  }
3588
3719
  } catch (childTerminalError) {
3589
- console.warn(
3720
+ recordCoordinatorEvent(
3721
+ 'warn',
3722
+ 'coordinator.child_terminal.ledger_append_failed',
3590
3723
  '[coordinator] child terminal ledger append failed; preserving coordinator terminal cache',
3591
3724
  {
3592
3725
  runId: runIdForTrace,
@@ -3624,7 +3757,7 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
3624
3757
  {
3625
3758
  graphHash,
3626
3759
  runId: runIdForTrace,
3627
- message:
3760
+ error:
3628
3761
  terminalError instanceof Error
3629
3762
  ? terminalError.message
3630
3763
  : String(terminalError),
@@ -3641,7 +3774,9 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
3641
3774
  } catch (innerError) {
3642
3775
  const failure =
3643
3776
  normalizeCoordinatorWorkflowRuntimeFailure(innerError);
3644
- console.error(
3777
+ recordCoordinatorEvent(
3778
+ 'error',
3779
+ 'coordinator.dynamic_workflow.runner_failed',
3645
3780
  '[coordinator] DynamicWorkflow runner.run threw',
3646
3781
  {
3647
3782
  graphHash,
@@ -3668,7 +3803,9 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
3668
3803
  event: innerEvent,
3669
3804
  error: innerError,
3670
3805
  }).catch((markError) => {
3671
- console.error(
3806
+ recordCoordinatorEvent(
3807
+ 'error',
3808
+ 'coordinator.dynamic_workflow.failure_forward_failed',
3672
3809
  '[coordinator] failed to forward DynamicWorkflow runner error',
3673
3810
  {
3674
3811
  graphHash,
@@ -3685,7 +3822,9 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
3685
3822
  error: failure.message,
3686
3823
  }).catch(() => undefined);
3687
3824
  } else {
3688
- console.warn(
3825
+ recordCoordinatorEvent(
3826
+ 'warn',
3827
+ 'coordinator.dynamic_workflow.platform_reset_retrying',
3689
3828
  '[coordinator] DynamicWorkflow platform reset will be retried; not publishing durable run.failed',
3690
3829
  {
3691
3830
  graphHash,
@@ -4133,11 +4272,16 @@ function coordinatorWorkflowRouteErrorResponse(input: {
4133
4272
  const message =
4134
4273
  input.error instanceof Error ? input.error.message : String(input.error);
4135
4274
  const phase = `coordinator.${input.action || 'unknown'}`;
4136
- console.error('[coordinator.workflow_route.error]', {
4137
- runId: input.runId,
4138
- action: input.action,
4139
- error: message,
4140
- });
4275
+ recordCoordinatorEvent(
4276
+ 'error',
4277
+ 'coordinator.workflow_route.error',
4278
+ '[coordinator.workflow_route.error]',
4279
+ {
4280
+ runId: input.runId,
4281
+ action: input.action,
4282
+ error: message,
4283
+ },
4284
+ );
4141
4285
  if (
4142
4286
  input.action === 'submit' &&
4143
4287
  isTenantStorageDegradationError(input.error)
@@ -4151,12 +4295,17 @@ function coordinatorWorkflowRouteErrorResponse(input: {
4151
4295
  // actions (status/result/tail/cancel/signal) run against an already-active,
4152
4296
  // possibly-billing run, so surfacing "storage not ready, nothing billed,
4153
4297
  // run db repair" there would be false and alarming on a healthy run.
4154
- console.error('[coordinator.workflow_route.storage_not_ready]', {
4155
- runId: input.runId,
4156
- action: input.action,
4157
- phase,
4158
- error: message,
4159
- });
4298
+ recordCoordinatorEvent(
4299
+ 'error',
4300
+ 'coordinator.workflow_route.storage_not_ready',
4301
+ '[coordinator.workflow_route.storage_not_ready]',
4302
+ {
4303
+ runId: input.runId,
4304
+ action: input.action,
4305
+ phase,
4306
+ error: message,
4307
+ },
4308
+ );
4160
4309
  return Response.json(
4161
4310
  {
4162
4311
  error: {
@@ -4198,7 +4347,7 @@ function coordinatorRouteErrorResponse(input: {
4198
4347
  }): Response {
4199
4348
  const message =
4200
4349
  input.error instanceof Error ? input.error.message : String(input.error);
4201
- console.error(input.logTag, {
4350
+ recordCoordinatorEvent('error', 'coordinator.route.error', input.logTag, {
4202
4351
  runId: input.runId,
4203
4352
  phase: input.phase,
4204
4353
  error: message,
@@ -4358,7 +4507,9 @@ async function handleWorkflowRoute(input: {
4358
4507
  // logs. Log the tenant-storage classification loudly so the real
4359
4508
  // cause (and the WORKSPACE_STORAGE_NOT_READY repair path) is visible.
4360
4509
  if (storageNotReady) {
4361
- console.error(
4510
+ recordCoordinatorEvent(
4511
+ 'error',
4512
+ 'coordinator.harness_prewarm_postgres.storage_not_ready',
4362
4513
  '[coordinator.harness_prewarm_postgres.storage_not_ready]',
4363
4514
  {
4364
4515
  runId: submittedRunId,
@@ -4414,11 +4565,16 @@ async function handleWorkflowRoute(input: {
4414
4565
  } catch (error) {
4415
4566
  const errorMessage =
4416
4567
  error instanceof Error ? error.message : String(error);
4417
- console.error('[coordinator] workflow retry state persistence failed', {
4418
- code: 'WORKFLOW_RETRY_STATE_PERSISTENCE_FAILED',
4419
- runId: submittedRunId,
4420
- error: errorMessage,
4421
- });
4568
+ recordCoordinatorEvent(
4569
+ 'error',
4570
+ 'coordinator.workflow_retry_state.persistence_failed',
4571
+ '[coordinator] workflow retry state persistence failed',
4572
+ {
4573
+ code: 'WORKFLOW_RETRY_STATE_PERSISTENCE_FAILED',
4574
+ runId: submittedRunId,
4575
+ error: errorMessage,
4576
+ },
4577
+ );
4422
4578
  recordSubmitTiming({
4423
4579
  phase: 'coordinator.retry_state_persistence',
4424
4580
  ms: 0,
@@ -4561,16 +4717,23 @@ async function handleWorkflowRoute(input: {
4561
4717
  instanceId: instance.id,
4562
4718
  });
4563
4719
  } catch (error) {
4564
- console.warn('[coordinator] workflow instance id record failed', {
4565
- runId: submittedRunId,
4566
- instanceId: instance?.id ?? null,
4567
- error: error instanceof Error ? error.message : String(error),
4568
- });
4720
+ recordCoordinatorEvent(
4721
+ 'warn',
4722
+ 'coordinator.workflow_instance_id.record_failed',
4723
+ '[coordinator] workflow instance id record failed',
4724
+ {
4725
+ runId: submittedRunId,
4726
+ instanceId: instance?.id ?? null,
4727
+ error: error instanceof Error ? error.message : String(error),
4728
+ },
4729
+ );
4569
4730
  await releaseWorkflowSubmitClaim({
4570
4731
  env,
4571
4732
  runId: submittedRunId,
4572
4733
  }).catch((releaseError) => {
4573
- console.warn(
4734
+ recordCoordinatorEvent(
4735
+ 'warn',
4736
+ 'coordinator.workflow_submit_claim.release_failed',
4574
4737
  '[coordinator] workflow submit claim release after instance record failure failed',
4575
4738
  {
4576
4739
  runId: submittedRunId,
@@ -4678,19 +4841,24 @@ async function handleWorkflowRoute(input: {
4678
4841
  ms: Date.now() - startedAt,
4679
4842
  extra: { status: submitResponse.status, childRunId },
4680
4843
  });
4681
- console.info('[play.runtime.span]', {
4682
- event: 'play.runtime.span',
4683
- phase: 'coordinator_child_submit',
4684
- runId,
4685
- parentRunId: runId,
4686
- childRunId,
4687
- playName: childPlayName,
4688
- ms: Date.now() - startedAt,
4689
- status: submitResponse.ok ? 'ok' : 'failed',
4690
- ...(submitResponse.ok
4691
- ? {}
4692
- : { errorCode: 'COORDINATOR_CHILD_SUBMIT_FAILED' }),
4693
- });
4844
+ recordCoordinatorEvent(
4845
+ 'info',
4846
+ 'play.runtime.span',
4847
+ '[play.runtime.span]',
4848
+ {
4849
+ event: 'play.runtime.span',
4850
+ phase: 'coordinator_child_submit',
4851
+ runId,
4852
+ parentRunId: runId,
4853
+ childRunId,
4854
+ playName: childPlayName,
4855
+ ms: Date.now() - startedAt,
4856
+ status: submitResponse.ok ? 'ok' : 'failed',
4857
+ ...(submitResponse.ok
4858
+ ? {}
4859
+ : { errorCode: 'COORDINATOR_CHILD_SUBMIT_FAILED' }),
4860
+ },
4861
+ );
4694
4862
  if (!submitResponse.ok) {
4695
4863
  return new Response(responseText, {
4696
4864
  status: submitResponse.status,
@@ -4716,11 +4884,16 @@ async function handleWorkflowRoute(input: {
4716
4884
  );
4717
4885
  } catch (error) {
4718
4886
  const message = error instanceof Error ? error.message : String(error);
4719
- console.error('[coordinator.child_submit.error]', {
4720
- runId,
4721
- ms: Date.now() - startedAt,
4722
- error: message,
4723
- });
4887
+ recordCoordinatorEvent(
4888
+ 'error',
4889
+ 'coordinator.child_submit.error',
4890
+ '[coordinator.child_submit.error]',
4891
+ {
4892
+ runId,
4893
+ ms: Date.now() - startedAt,
4894
+ error: message,
4895
+ },
4896
+ );
4724
4897
  return Response.json(
4725
4898
  {
4726
4899
  error: {
@@ -4883,10 +5056,15 @@ async function handleWorkflowRoute(input: {
4883
5056
  ).catch((error: unknown) => {
4884
5057
  // Tolerated: better to risk a harmless terminal-over-terminal
4885
5058
  // overwrite than to skip the cancelled write and hang watchers.
4886
- console.warn('[coordinator] terminal state read before cancel failed', {
4887
- runId,
4888
- error: error instanceof Error ? error.message : String(error),
4889
- });
5059
+ recordCoordinatorEvent(
5060
+ 'warn',
5061
+ 'coordinator.cancel.terminal_state_read_failed',
5062
+ '[coordinator] terminal state read before cancel failed',
5063
+ {
5064
+ runId,
5065
+ error: error instanceof Error ? error.message : String(error),
5066
+ },
5067
+ );
4890
5068
  return null;
4891
5069
  });
4892
5070
  if (!existingTerminal) {
@@ -4901,10 +5079,15 @@ async function handleWorkflowRoute(input: {
4901
5079
  // hang on 'running' forever without the terminal event.
4902
5080
  const message =
4903
5081
  error instanceof Error ? error.message : String(error);
4904
- console.error('[coordinator] cancel terminal state write failed', {
4905
- runId,
4906
- error: message,
4907
- });
5082
+ recordCoordinatorEvent(
5083
+ 'error',
5084
+ 'coordinator.cancel.terminal_state_write_failed',
5085
+ '[coordinator] cancel terminal state write failed',
5086
+ {
5087
+ runId,
5088
+ error: message,
5089
+ },
5090
+ );
4908
5091
  return Response.json(
4909
5092
  {
4910
5093
  runId,
@@ -4944,11 +5127,16 @@ async function handleWorkflowRoute(input: {
4944
5127
  eventKey,
4945
5128
  data: body.data ?? body,
4946
5129
  }).catch((error: unknown) => {
4947
- console.warn('[coordinator] child terminal cache write failed', {
4948
- runId,
4949
- eventKey,
4950
- error: error instanceof Error ? error.message : String(error),
4951
- });
5130
+ recordCoordinatorEvent(
5131
+ 'warn',
5132
+ 'coordinator.child_terminal.cache_write_failed',
5133
+ '[coordinator] child terminal cache write failed',
5134
+ {
5135
+ runId,
5136
+ eventKey,
5137
+ error: error instanceof Error ? error.message : String(error),
5138
+ },
5139
+ );
4952
5140
  });
4953
5141
  }
4954
5142
  await instance.sendEvent({
@@ -5048,7 +5236,9 @@ async function handleWorkflowRoute(input: {
5048
5236
  message,
5049
5237
  )
5050
5238
  ) {
5051
- console.warn(
5239
+ recordCoordinatorEvent(
5240
+ 'warn',
5241
+ 'coordinator.permanent_error.terminate_failed',
5052
5242
  '[coordinator] terminate-after-permanent-error failed',
5053
5243
  {
5054
5244
  runId,
@@ -5462,12 +5652,20 @@ export class TenantWorkflow extends WorkflowEntrypoint {
5462
5652
  })).catch(() => null);
5463
5653
  }
5464
5654
  console.log("[perf-trace] " + JSON.stringify({
5655
+ telemetrySchemaVersion: 1,
5656
+ timestamp: new Date().toISOString(),
5657
+ service: "play-runtime",
5658
+ component: "coordinator-warmup",
5659
+ event: "dynamic_worker.warmup_run",
5660
+ tag: "[perf-trace]",
5465
5661
  ts: Date.now(),
5466
5662
  source: "dynamic_worker",
5467
5663
  runId,
5468
5664
  phase: "dynamic_worker.warmup_run",
5469
5665
  ms: Date.now() - startedAt,
5470
- graphHash: "coordinator-warmup-v1"
5666
+ graphHash: "coordinator-warmup-v1",
5667
+ telemetryKind: "log",
5668
+ telemetryLevel: "info"
5471
5669
  }));
5472
5670
  return { ok: true, warmup: true };
5473
5671
  }
@@ -5540,15 +5738,20 @@ async function handleStagedFilePut(
5540
5738
  }
5541
5739
  const existing = await headExistingStagedFile(env, key, expectedBytes);
5542
5740
  if (existing.exists) {
5543
- console.info('[perf][coordinator.staged_file_put]', {
5544
- key,
5545
- bytes: expectedBytes,
5546
- headMs: existing.ms,
5547
- putMs: 0,
5548
- ms: existing.ms,
5549
- transport: 'raw',
5550
- skipped: true,
5551
- });
5741
+ recordCoordinatorEvent(
5742
+ 'info',
5743
+ 'coordinator.staged_file_put',
5744
+ '[perf][coordinator.staged_file_put]',
5745
+ {
5746
+ key,
5747
+ bytes: expectedBytes,
5748
+ headMs: existing.ms,
5749
+ putMs: 0,
5750
+ ms: existing.ms,
5751
+ transport: 'raw',
5752
+ skipped: true,
5753
+ },
5754
+ );
5552
5755
  return Response.json({
5553
5756
  ok: true,
5554
5757
  key,
@@ -5571,14 +5774,19 @@ async function handleStagedFilePut(
5571
5774
  httpMetadata: { contentType },
5572
5775
  });
5573
5776
  const putMs = Date.now() - putStartedAt;
5574
- console.info('[perf][coordinator.staged_file_put]', {
5575
- key,
5576
- bytes: bytes.byteLength,
5577
- readMs,
5578
- putMs,
5579
- ms: readMs + putMs,
5580
- transport: 'raw',
5581
- });
5777
+ recordCoordinatorEvent(
5778
+ 'info',
5779
+ 'coordinator.staged_file_put',
5780
+ '[perf][coordinator.staged_file_put]',
5781
+ {
5782
+ key,
5783
+ bytes: bytes.byteLength,
5784
+ readMs,
5785
+ putMs,
5786
+ ms: readMs + putMs,
5787
+ transport: 'raw',
5788
+ },
5789
+ );
5582
5790
  return Response.json({
5583
5791
  ok: true,
5584
5792
  key,
@@ -5615,15 +5823,20 @@ async function handleStagedFilePut(
5615
5823
  }
5616
5824
  const existing = await headExistingStagedFile(env, key, expectedBytes);
5617
5825
  if (existing.exists) {
5618
- console.info('[perf][coordinator.staged_file_put]', {
5619
- key,
5620
- bytes: expectedBytes,
5621
- headMs: existing.ms,
5622
- putMs: 0,
5623
- ms: existing.ms,
5624
- transport: 'base64',
5625
- skipped: true,
5626
- });
5826
+ recordCoordinatorEvent(
5827
+ 'info',
5828
+ 'coordinator.staged_file_put',
5829
+ '[perf][coordinator.staged_file_put]',
5830
+ {
5831
+ key,
5832
+ bytes: expectedBytes,
5833
+ headMs: existing.ms,
5834
+ putMs: 0,
5835
+ ms: existing.ms,
5836
+ transport: 'base64',
5837
+ skipped: true,
5838
+ },
5839
+ );
5627
5840
  return Response.json({
5628
5841
  ok: true,
5629
5842
  key,
@@ -5646,13 +5859,18 @@ async function handleStagedFilePut(
5646
5859
  httpMetadata: { contentType },
5647
5860
  });
5648
5861
  const putMs = Date.now() - putStartedAt;
5649
- console.info('[perf][coordinator.staged_file_put]', {
5650
- key,
5651
- bytes: bytes.byteLength,
5652
- decodeMs,
5653
- putMs,
5654
- ms: decodeMs + putMs,
5655
- });
5862
+ recordCoordinatorEvent(
5863
+ 'info',
5864
+ 'coordinator.staged_file_put',
5865
+ '[perf][coordinator.staged_file_put]',
5866
+ {
5867
+ key,
5868
+ bytes: bytes.byteLength,
5869
+ decodeMs,
5870
+ putMs,
5871
+ ms: decodeMs + putMs,
5872
+ },
5873
+ );
5656
5874
  return Response.json({
5657
5875
  ok: true,
5658
5876
  key,
@@ -5931,7 +6149,9 @@ function makeCoordinatorControlBinding():
5931
6149
  if (typeof ctor !== 'function') {
5932
6150
  if (!loggedMissingCoordinatorControlExport) {
5933
6151
  loggedMissingCoordinatorControlExport = true;
5934
- console.warn(
6152
+ recordCoordinatorEvent(
6153
+ 'warn',
6154
+ 'coordinator.control_export.missing',
5935
6155
  '[coordinator] CoordinatorControl is not registered on cloudflare:workers exports; using public coordinator transport.',
5936
6156
  );
5937
6157
  }