
Metrics.pudu
Pudu66 lines2.7 KB
1/** @Handlers.Metrics.Module — counts and durations of the requests through a pipeline */2module PuduLangHttpClient.Handlers.Metrics34import Std.Concurrent.Cancel as Cancel5import Std.Json as Json6import Std.Math as Math7import PuduLangHttpClient.Handler as Handler8import PuduLangHttpClient as HttpClient9import PuduLangHttpClient.Request as Request10import PuduLangHttpClient.Response as Response11import PuduLangHttpClient.Utils.Shared as Shared1213/** @Handlers.Metrics.Snapshot — what the requests measured so far add up to */14export type Snapshot = {15 requests: Int,16 active: Int,17 informational: Int,18 successful: Int,19 redirected: Int,20 clientErrors: Int,21 serverErrors: Int,22 failed: Int,23 totalMillis: Int,24 longestMillis: Int25} derives Json.Encode2627/** @Handlers.Metrics.Meter — a snapshot shared by every request a handler measures */28export type Meter = { held: Shared.Shared[Snapshot] }293031export fn meter() -> Meter {32 Meter{held: Shared.shared(Snapshot{requests: 0, active: 0, informational: 0, successful: 0, redirected: 0, clientErrors: 0, serverErrors: 0, failed: 0, totalMillis: 0, longestMillis: 0})}33}34353637export fn handler(target: &Meter) -> Handler.Handler {38 let held = *target39 fn(request: Request.Request, token: Cancel.Token, next: Handler.Send) -> HttpClient.Outcome[Response.Response] {40 Shared.update(&held.held, |now: Snapshot| Snapshot{..now, requests: now.requests + 1, active: now.active + 1})41 let began = clock()42 let outcome = next(request, token)43 let took = clock() - began44 let code = match outcome {45 case Ok(response) => response.status.code46 case Err(_) => 047 }48 Shared.update(&held.held, |now: Snapshot| counted(&now, code, took))49 outcome50 }51}525354export fn snapshot(source: &Meter) -> Snapshot { Shared.current(&source.held) }555657fn counted(now: &Snapshot, code: Int, took: Int) -> Snapshot {58 let timed = Snapshot{..*now, active: now.active - 1, totalMillis: now.totalMillis + took, longestMillis: Math.max(took, now.longestMillis)}59 if code == 0 { Snapshot{..timed, failed: timed.failed + 1} }60 else if code < 200 { Snapshot{..timed, informational: timed.informational + 1} }61 else if code < 300 { Snapshot{..timed, successful: timed.successful + 1} }62 else if code < 400 { Snapshot{..timed, redirected: timed.redirected + 1} }63 else if code < 500 { Snapshot{..timed, clientErrors: timed.clientErrors + 1} }64 else { Snapshot{..timed, serverErrors: timed.serverErrors + 1} }65}66