@@ -92,6 +92,10 @@ type TelemetryExporterDiagnosticEvent = Extract<
9292 DiagnosticEventPayload ,
9393 { type : "telemetry.exporter" }
9494> ;
95+ type FetchTimeoutDelayedDiagnosticEvent = Extract <
96+ DiagnosticEventPayload ,
97+ { type : "fetch.timeout.delayed" }
98+ > ;
9599type SessionRecoveryDiagnosticEvent = Extract <
96100 DiagnosticEventPayload ,
97101 { type : "session.recovery.requested" | "session.recovery.completed" }
@@ -961,6 +965,31 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
961965 description : "CPU core ratio reported by diagnostic liveness warnings" ,
962966 } ,
963967 ) ;
968+ const fetchTimeoutDelayedCounter = meter . createCounter ( "openclaw.fetch.timeout.delayed" , {
969+ unit : "1" ,
970+ description : "Fetch timeout timers that fired late enough to indicate event-loop delay" ,
971+ } ) ;
972+ const fetchTimeoutConfiguredMsHistogram = meter . createHistogram (
973+ "openclaw.fetch.timeout.configured_ms" ,
974+ {
975+ unit : "ms" ,
976+ description : "Configured fetch timeout for delayed timeout diagnostics" ,
977+ } ,
978+ ) ;
979+ const fetchTimeoutElapsedMsHistogram = meter . createHistogram (
980+ "openclaw.fetch.timeout.elapsed_ms" ,
981+ {
982+ unit : "ms" ,
983+ description : "Elapsed time before delayed fetch timeout aborts" ,
984+ } ,
985+ ) ;
986+ const fetchTimeoutTimerDelayMsHistogram = meter . createHistogram (
987+ "openclaw.fetch.timeout.timer_delay_ms" ,
988+ {
989+ unit : "ms" ,
990+ description : "Timer delay reported by delayed fetch timeout diagnostics" ,
991+ } ,
992+ ) ;
964993 const telemetryExporterCounter = meter . createCounter ( "openclaw.telemetry.exporter.events" , {
965994 unit : "1" ,
966995 description : "Diagnostic telemetry exporter lifecycle and failure events" ,
@@ -2309,6 +2338,33 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
23092338 span . end ( evt . ts ) ;
23102339 } ;
23112340
2341+ const recordFetchTimeoutDelayed = ( evt : FetchTimeoutDelayedDiagnosticEvent ) => {
2342+ const attrs = {
2343+ "openclaw.operation" : lowCardinalityAttr ( evt . operation , "unknown" ) ,
2344+ } ;
2345+ fetchTimeoutDelayedCounter . add ( 1 , attrs ) ;
2346+ fetchTimeoutConfiguredMsHistogram . record ( evt . timeoutMs , attrs ) ;
2347+ fetchTimeoutElapsedMsHistogram . record ( evt . elapsedMs , attrs ) ;
2348+ fetchTimeoutTimerDelayMsHistogram . record ( evt . timerDelayMs , attrs ) ;
2349+ if ( ! tracesEnabled ) {
2350+ return ;
2351+ }
2352+ const spanAttrs : Record < string , string | number > = {
2353+ ...attrs ,
2354+ "openclaw.fetch.timeout_ms" : evt . timeoutMs ,
2355+ "openclaw.fetch.elapsed_ms" : evt . elapsedMs ,
2356+ "openclaw.fetch.timer_delay_ms" : evt . timerDelayMs ,
2357+ } ;
2358+ const span = spanWithDuration ( "openclaw.fetch.timeout.delayed" , spanAttrs , 0 , {
2359+ endTimeMs : evt . ts ,
2360+ } ) ;
2361+ span . setStatus ( {
2362+ code : SpanStatusCode . ERROR ,
2363+ message : "fetch timeout delayed" ,
2364+ } ) ;
2365+ span . end ( evt . ts ) ;
2366+ } ;
2367+
23122368 const recordTelemetryExporter = (
23132369 evt : TelemetryExporterDiagnosticEvent ,
23142370 metadata : DiagnosticEventMetadata ,
@@ -2398,6 +2454,9 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
23982454 case "diagnostic.liveness.warning" :
23992455 recordLivenessWarning ( evt ) ;
24002456 return ;
2457+ case "fetch.timeout.delayed" :
2458+ recordFetchTimeoutDelayed ( evt ) ;
2459+ return ;
24012460 case "diagnostic.phase.completed" :
24022461 recordDiagnosticPhaseCompleted ( evt ) ;
24032462 return ;
0 commit comments