Public/Timing/New-TimingSpanTree.ps1
|
function New-TimingSpanTree { <# .SYNOPSIS Create a timing context that owns an N-level nested span tree. .DESCRIPTION The entry point of the arbitrary-depth timing framework. Returns a context object that carries the root node plus a current-node stack and a monotonic Order counter. Every other timing verb (Measure-TimingSpan, Add-TimingSpanDuration, Initialize-TimingSpanTree) operates on a context passed explicitly. A context object, rather than a module-scoped `$script:` global, is what lets two trees coexist in one process without clobbering each other - the E2E parent's own tree and a child tree imported from another process can both be live at once. The 2-level framework's single global state cannot express that. Node shape (every node, root included): { Order; Name; Status; ElapsedMs; Source; Children } Order - first-contact declaration order across all depths. Name - display name; unique within a parent's Children. Status - 'NotStarted' | 'Running' | 'OK' | 'Failed'. ElapsedMs - $null until timed, then the accumulated total. Source - optional provenance tag used by the cross-process merge. Children - ordered list of child nodes (arbitrary depth). The returned context shape: { Root; Stack; NextOrder } Root - the root node (Order 0). Stack - current-node stack; the top is the parent that the next span attaches under. Seeded with Root. NextOrder - the next Order value to hand out; advanced on creation. .PARAMETER RootName Display name of the root node (e.g. the run name). The total line of the report is this node. .PARAMETER Source Optional provenance tag for the root (e.g. the emitting script's name), carried through export/merge. .EXAMPLE $tree = New-TimingSpanTree -RootName 'runner-lifecycle' Measure-TimingSpan -Tree $tree -Name 'Setup' -Action { Start-Setup } #> [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $RootName, [string] $Source ) # The root is a live container from the moment it exists; a report emitted # mid-run shows it as Running until the run completes. Order 0 anchors the # sort; the first minted child takes 1. $root = New-TimingSpanNode -Order 0 -Name $RootName -Status 'Running' -Source $Source $context = [pscustomobject]@{ Root = $root Stack = [System.Collections.Generic.Stack[object]]::new() # Root took Order 0, so the first minted child gets 1. NextOrder = 1 } # Seed the stack with the root so the first Measure/Add attaches a # top-level span under it without the caller managing the stack. $context.Stack.Push($root) return $context } |