Skip to content

Commit f4c94d4

Browse files
committed
feat(Cosmos InternalMetrics): Group by Container
1 parent 2b66792 commit f4c94d4

File tree

2 files changed

+65
-59
lines changed

2 files changed

+65
-59
lines changed

src/Equinox.CosmosStore/CosmosStore.fs

+63-57
Original file line numberDiff line numberDiff line change
@@ -267,80 +267,86 @@ module Log =
267267
type internal Counter =
268268
{ mutable rux100: int64; mutable count: int64; mutable ms: int64 }
269269
static member Create() = { rux100 = 0L; count = 0L; ms = 0L }
270-
member x.Ingest(ru, ms) =
270+
member x.Ingest(ms, ru) =
271271
Interlocked.Increment(&x.count) |> ignore
272-
Interlocked.Add(&x.rux100, int64 (ru*100.)) |> ignore
272+
Interlocked.Add(&x.rux100, int64 (ru * 100.)) |> ignore
273273
Interlocked.Add(&x.ms, ms) |> ignore
274-
let inline private (|RcMs|) ({ interval = i; ru = ru }: Measurement) =
275-
ru, int64 i.ElapsedMilliseconds
274+
type internal Counters() =
275+
let containers = System.Collections.Concurrent.ConcurrentDictionary<string, Counter>()
276+
let create (_name: string) = Counter.Create()
277+
member _.Ingest(container, ms, ru) = containers.GetOrAdd(container, create).Ingest(ms, ru)
278+
member _.Containers = containers.Keys
279+
member _.TryContainer container = match containers.TryGetValue container with true, t -> Some t | false, _ -> None
280+
type Epoch() =
281+
let epoch = System.Diagnostics.Stopwatch.StartNew()
282+
member val internal Read = Counters() with get, set
283+
member val internal Write = Counters() with get, set
284+
member val internal Resync = Counters() with get, set
285+
member val internal Conflict = Counters() with get, set
286+
member val internal Prune = Counters() with get, set
287+
member val internal Delete = Counters() with get, set
288+
member val internal Trim = Counters() with get, set
289+
member _.Stop() = epoch.Stop()
290+
member _.Elapsed = epoch.Elapsed
291+
let inline private (|BucketMsRu|) ({ container = c; interval = i; ru = ru }: Measurement) =
292+
c, int64 i.ElapsedMilliseconds, ru
276293
type LogSink() =
277-
static let epoch = System.Diagnostics.Stopwatch.StartNew()
278-
static member val internal Read = Counter.Create() with get, set
279-
static member val internal Write = Counter.Create() with get, set
280-
static member val internal Resync = Counter.Create() with get, set
281-
static member val internal Conflict = Counter.Create() with get, set
282-
static member val internal Prune = Counter.Create() with get, set
283-
static member val internal Delete = Counter.Create() with get, set
284-
static member val internal Trim = Counter.Create() with get, set
294+
static let mutable epoch = Epoch()
285295
static member Restart() =
286-
LogSink.Read <- Counter.Create()
287-
LogSink.Write <- Counter.Create()
288-
LogSink.Resync <- Counter.Create()
289-
LogSink.Conflict <- Counter.Create()
290-
LogSink.Prune <- Counter.Create()
291-
LogSink.Delete <- Counter.Create()
292-
LogSink.Trim <- Counter.Create()
293-
let span = epoch.Elapsed
294-
epoch.Restart()
295-
span
296+
let fresh = Epoch()
297+
let outgoing = Interlocked.Exchange(&epoch, fresh)
298+
outgoing.Stop()
299+
outgoing
296300
interface Serilog.Core.ILogEventSink with
297301
member _.Emit logEvent =
298302
match logEvent with
299303
| MetricEvent cm ->
300304
match cm with
301-
| Op ((Operation.Tip | Operation.Tip404 | Operation.Tip304 | Operation.Query), RcMs m) ->
302-
LogSink.Read.Ingest m
305+
| Op ((Operation.Tip | Operation.Tip404 | Operation.Tip304 | Operation.Query), BucketMsRu m) ->
306+
epoch.Read.Ingest m
303307
| QueryRes (_direction, _) -> ()
304-
| Op (Operation.Write, RcMs m) -> LogSink.Write.Ingest m
305-
| Op (Operation.Conflict, RcMs m) -> LogSink.Conflict.Ingest m
306-
| Op (Operation.Resync, RcMs m) -> LogSink.Resync.Ingest m
307-
| Op (Operation.Prune, RcMs m) -> LogSink.Prune.Ingest m
308+
| Op (Operation.Write, BucketMsRu m) -> epoch.Write.Ingest m
309+
| Op (Operation.Conflict, BucketMsRu m) -> epoch.Conflict.Ingest m
310+
| Op (Operation.Resync, BucketMsRu m) -> epoch.Resync.Ingest m
311+
| Op (Operation.Prune, BucketMsRu m) -> epoch.Prune.Ingest m
308312
| PruneRes _ -> ()
309-
| Op (Operation.Delete, RcMs m) -> LogSink.Delete.Ingest m
310-
| Op (Operation.Trim, RcMs m) -> LogSink.Trim.Ingest m
313+
| Op (Operation.Delete, BucketMsRu m) -> epoch.Delete.Ingest m
314+
| Op (Operation.Trim, BucketMsRu m) -> epoch.Trim.Ingest m
311315
| _ -> ()
312316

313317
/// Relies on feeding of metrics from Log through to Stats.LogSink
314318
/// Use Stats.LogSink.Restart() to reset the start point (and stats) where relevant
315319
let dump (log: ILogger) =
320+
let res = Stats.LogSink.Restart()
316321
let stats =
317-
[ "Read", Stats.LogSink.Read
318-
"Write", Stats.LogSink.Write
319-
"Resync", Stats.LogSink.Resync
320-
"Conflict", Stats.LogSink.Conflict
321-
"Prune", Stats.LogSink.Prune
322-
"Delete", Stats.LogSink.Delete
323-
"Trim", Stats.LogSink.Trim ]
324-
let mutable rows, totalCount, totalRRu, totalWRu, totalMs = 0, 0L, 0., 0., 0L
325-
let logActivity name count ru lat =
326-
let aru, ams = (if count = 0L then Double.NaN else ru/float count), (if count = 0L then Double.NaN else float lat/float count)
327-
let rut = name |> function
328-
| "TOTAL" -> "" | "Read" | "Prune" -> totalRRu <- totalRRu + ru; "R"
329-
| _ -> totalWRu <- totalWRu + ru; "W"
330-
log.Information("{name}: {count:n0}r {ru:n0}{rut:l}RU Average {avgRu:n1}RU {lat:n0}ms", name, count, ru, rut, aru, ams)
331-
for name, stat in stats do
332-
if stat.count <> 0L then
333-
let ru = float stat.rux100 / 100.
334-
totalCount <- totalCount + stat.count
335-
totalMs <- totalMs + stat.ms
336-
logActivity name stat.count ru stat.ms
337-
rows <- rows + 1
338-
// Yes, there's a minor race here between the use of the values and the reset
339-
let duration = Stats.LogSink.Restart()
340-
if rows > 1 then logActivity "TOTAL" totalCount (totalRRu + totalWRu) totalMs
341-
let measures: (string * (TimeSpan -> float)) list = [ "s", _.TotalSeconds(*; "m", _.TotalMinutes; "h", _.TotalHours*) ]
342-
let logPeriodicRate name count rru wru = log.Information("{rru:n1}R/{wru:n1}W CU @ {count:n0} rp{unit}", rru, wru, count, name)
343-
for uom, f in measures do let d = f duration in if d <> 0. then logPeriodicRate uom (float totalCount/d |> int64) (totalRRu/d) (totalWRu/d)
322+
[|nameof res.Read, res.Read
323+
nameof res.Write, res.Write
324+
nameof res.Resync, res.Resync
325+
nameof res.Conflict, res.Conflict
326+
nameof res.Prune, res.Prune
327+
nameof res.Delete, res.Delete
328+
nameof res.Trim, res.Trim |]
329+
for container in stats |> Seq.collect (fun (_n, stat) -> stat.Containers) |> Seq.distinct |> Seq.sort do
330+
let mutable rows, totalCount, totalRRu, totalWRu, totalMs = 0, 0L, 0., 0., 0L
331+
let logActivity name count ru lat =
332+
let aru, ams = (if count = 0L then Double.NaN else ru/float count), (if count = 0L then Double.NaN else float lat/float count)
333+
let rut = name |> function
334+
| "TOTAL" -> "" | nameof res.Read | nameof res.Prune -> totalRRu <- totalRRu + ru; "R"
335+
| _ -> totalWRu <- totalWRu + ru; "W"
336+
log.Information("{container} {name}: {count:n0}r {ru:n0}{rut:l}RU Average {avgRu:n1}RU {lat:n0}ms", container, name, count, ru, rut, aru, ams)
337+
for name, stat in stats do
338+
match stat.TryContainer container with
339+
| Some stat when stat.count <> 0L ->
340+
let ru = float stat.rux100 / 100.
341+
totalCount <- totalCount + stat.count
342+
totalMs <- totalMs + stat.ms
343+
logActivity name stat.count ru stat.ms
344+
rows <- rows + 1
345+
| _ -> ()
346+
if rows > 1 then logActivity "TOTAL" totalCount (totalRRu + totalWRu) totalMs
347+
let measures: (string * (TimeSpan -> float)) list = [ "s", _.TotalSeconds(*; "m", _.TotalMinutes; "h", _.TotalHours*) ]
348+
let logPeriodicRate name count rru wru = log.Information("{container} {rru:n1}R/{wru:n1}W RU @ {count:n0} rp{unit}", container, rru, wru, count, name)
349+
for uom, f in measures do let d = f res.Elapsed in if d <> 0. then logPeriodicRate uom (float totalCount/d |> int64) (totalRRu/d) (totalWRu/d)
344350

345351
[<AutoOpen>]
346352
module private MicrosoftAzureCosmosWrappers =

src/Equinox.DynamoStore/DynamoStore.fs

+2-2
Original file line numberDiff line numberDiff line change
@@ -339,15 +339,15 @@ module Log =
339339
let dump (log: ILogger) =
340340
let res = Stats.LogSink.Restart()
341341
let stats =
342-
[ nameof res.Tip, res.Tip
342+
[| nameof res.Tip, res.Tip
343343
nameof res.Query, res.Query
344344
nameof res.Append, res.Append
345345
nameof res.Append409, res.Append409
346346
nameof res.Calve, res.Calve
347347
nameof res.Calve409, res.Calve409
348348
nameof res.Prune, res.Prune
349349
nameof res.Delete, res.Delete
350-
nameof res.Trim, res.Trim ]
350+
nameof res.Trim, res.Trim |]
351351
for table in stats |> Seq.collect (fun (_n, stat) -> stat.Tables) |> Seq.distinct |> Seq.sort do
352352
let mutable rows, totalCount, totalRRu, totalWRu, totalMs = 0, 0L, 0., 0., 0L
353353
let logActivity name count ru lat =

0 commit comments

Comments
 (0)