diff --git a/chronos/asyncloop.nim b/chronos/asyncloop.nim index a644b778c..955e3e9bd 100644 --- a/chronos/asyncloop.nim +++ b/chronos/asyncloop.nim @@ -15,6 +15,12 @@ import std/[tables, strutils, heapqueue, deques] import stew/results import "."/[config, futures, osdefs, oserrno, osutils, timer] +when chronosEnableCallbackDurationMetric: + import std/monotimes + import pkg/metrics + + declareGauge(chronosCallbackDuration, "chronos callback duration") + export Port export futures, timer, results @@ -260,8 +266,15 @@ template processCallbacks(loop: untyped) = if isSentinel(callable): break if not(isNil(callable.function)): + when chronosEnableCallbackDurationMetric: + let startTime = getMonoTime().ticks + callable.function(callable.udata) + when chronosEnableCallbackDurationMetric: + let durationUs = (getMonoTime().ticks - startTime) div 1000 + chronosCallbackDuration.set(durationUs) + proc raiseAsDefect*(exc: ref Exception, msg: string) {.noreturn, noinline.} = # Reraise an exception as a Defect, where it's unexpected and can't be handled # We include the stack trace in the message because otherwise, it's easily diff --git a/chronos/config.nim b/chronos/config.nim index bd6c2b9d1..63da54055 100644 --- a/chronos/config.nim +++ b/chronos/config.nim @@ -70,6 +70,10 @@ when (NimMajor, NimMinor) >= (1, 4): "" ## OS polling engine type which is going to be used by chronos. + chronosEnableCallbackDurationMetric* {.booldefine.} = defined(chronosEnableCallbackDurationMetric) + ## At the cost of some performance, produce a 'chronosCallbackDuration' metric. + ## Useful for detecting application stalling/blocking. + else: # 1.2 doesn't support `booldefine` in `when` properly const