rendertrace
packageAPI reference for the rendertrace
package.
Imports
(4)TestTraceEnabledAtBootReadsBooleanAndObjectFlags
Parameters
func TestTraceEnabledAtBootReadsBooleanAndObjectFlags(t *testing.T)
{
global := js.Global()
previous := global.Get("RFW_RENDER_TRACE")
defer func() {
if previous.Type() == js.TypeUndefined {
global.Get("Reflect").Call("deleteProperty", global, "RFW_RENDER_TRACE")
return
}
global.Set("RFW_RENDER_TRACE", previous)
}()
global.Set("RFW_RENDER_TRACE", true)
if !traceEnabledAtBoot() {
t.Fatal("boolean true did not enable tracing")
}
global.Set("RFW_RENDER_TRACE", map[string]any{"enabled": true})
if !traceEnabledAtBoot() {
t.Fatal("object enabled flag did not enable tracing")
}
global.Set("RFW_RENDER_TRACE", false)
if traceEnabledAtBoot() {
t.Fatal("boolean false enabled tracing")
}
}
Cause
Cause identifies why a component render was requested.
type Cause struct
Fields
| Name | Type | Description |
|---|---|---|
| Kind | string | |
| Module | string | |
| Store | string | |
| Key | string | |
| Signal | string |
Record
Record is one phase of a render trace. Emit assigns the schema version,
sequence and timestamp so callers only provide render-specific facts.
type Record struct
Fields
Uses
NormalizeCause
NormalizeCause gives callers that have no more specific provenance a stable
explicit cause instead of emitting an empty object.
func NormalizeCause(cause Cause) Cause
{
if cause.Kind == "" {
cause.Kind = "explicit"
}
return cause
}
AppendCause
AppendCause adds one cause unless an identical cause is already present.
func AppendCause(causes []Cause, cause Cause) []Cause
{
cause = NormalizeCause(cause)
for _, existing := range causes {
if existing == cause {
return causes
}
}
return append(causes, cause)
}
Uses
Enabled
Enabled reports that browser tracing is unavailable on native targets.
Returns
func Enabled() bool
{ return false }
SetEnabledForTest
SetEnabledForTest returns a no-op restore function on native targets.
Parameters
Returns
func SetEnabledForTest(bool) func()
{ return func() {} }
NextBatchID
NextBatchID allocates a native stub batch identifier.
Returns
func NextBatchID() uint64
{ return batchSeq.Add(1) }
NextRenderID
NextRenderID allocates a native stub render identifier.
Returns
func NextRenderID() uint64
{ return renderSeq.Add(1) }
NowMS
NowMS returns a wall-clock timestamp for native callers.
Returns
func NowMS() float64
{ return float64(time.Now().UnixNano()) / 1e6 }
Emit
Emit is a no-op because native targets have no browser event transport.
Parameters
func Emit(Record)
{}
Uses
traceEnabledAtBoot
Returns
func traceEnabledAtBoot() bool
{
value := js.Global().Get("RFW_RENDER_TRACE")
if value.Type() == js.TypeBoolean {
return value.Bool()
}
if value.Type() == js.TypeObject {
enabled := value.Get("enabled")
return enabled.Type() == js.TypeBoolean && enabled.Bool()
}
return false
}
Enabled
Enabled reports whether tracing was enabled before WASM startup. The test
override exists inside the module’s internal package so browser tests can
exercise both paths without exposing a production API.
Returns
func Enabled() bool
{
if testOverride >= 0 {
return testOverride == 1
}
return bootEnabled
}
SetEnabledForTest
SetEnabledForTest overrides the boot flag and returns a restoring function.
Parameters
Returns
func SetEnabledForTest(enabled bool) func()
{
previous := testOverride
if enabled {
testOverride = 1
} else {
testOverride = 0
}
return func() { testOverride = previous }
}
NextBatchID
NextBatchID allocates a monotonic render batch identifier.
Returns
func NextBatchID() uint64
{ return batchSeq.Add(1) }
NextRenderID
NextRenderID allocates a monotonic logical render identifier.
Returns
func NextRenderID() uint64
{ return renderSeq.Add(1) }
NowMS
NowMS returns the browser’s monotonic clock when it is available.
Returns
func NowMS() float64
{
performance := js.Global().Get("performance")
if performance.Type() == js.TypeObject && performance.Get("now").Type() == js.TypeFunction {
return performance.Call("now").Float()
}
return js.Global().Get("Date").Call("now").Float()
}
Emit
Emit dispatches one browser-readable trace record. Tracing must never affect
application rendering, so unsupported browser APIs or consumer errors are
contained here.
Parameters
func Emit(record Record)
{
if !Enabled() {
return
}
defer func() { _ = recover() }()
detail := map[string]any{
"schemaVersion": schemaVersion,
"sequence": sequence.Add(1),
"timestampMs": NowMS(),
"event": record.Event,
"batchId": record.BatchID,
"renderId": record.RenderID,
"componentId": record.ComponentID,
"componentName": record.ComponentName,
"depth": record.Depth,
}
if record.ParentComponentID != "" {
detail["parentComponentId"] = record.ParentComponentID
}
if record.Cause.Kind != "" {
detail["cause"] = causeDetail(record.Cause)
}
if len(record.Causes) > 0 {
causes := make([]any, 0, len(record.Causes))
for _, cause := range record.Causes {
causes = append(causes, causeDetail(cause))
}
detail["causes"] = causes
}
if record.QueueDepth > 0 {
detail["queueDepth"] = record.QueueDepth
}
if record.CoalescedCount > 0 || record.Event == "scheduled" || record.Event == "coalesced" || record.Event == "started" || record.Event == "committed" {
detail["coalescedCount"] = record.CoalescedCount
}
if record.Event == "committed" || record.Event == "failed" {
detail["templateMs"] = record.TemplateMS
detail["domMs"] = record.DOMMS
detail["totalMs"] = record.TotalMS
}
if record.Outcome != "" {
detail["outcome"] = record.Outcome
}
if record.Reason != "" {
detail["reason"] = record.Reason
}
if record.SupersededBy != 0 {
detail["supersededByRenderId"] = record.SupersededBy
}
constructor := js.Global().Get("CustomEvent")
dispatch := js.Global().Get("dispatchEvent")
if constructor.Type() != js.TypeFunction || dispatch.Type() != js.TypeFunction {
return
}
options := map[string]any{"detail": detail}
event := constructor.New("rfw:render-trace", options)
js.Global().Call("dispatchEvent", event)
}
Uses
causeDetail
Parameters
Returns
func causeDetail(cause Cause) map[string]any
{
cause = NormalizeCause(cause)
detail := map[string]any{"kind": cause.Kind}
if cause.Module != "" {
detail["module"] = cause.Module
}
if cause.Store != "" {
detail["store"] = cause.Store
}
if cause.Key != "" {
detail["key"] = cause.Key
}
if cause.Signal != "" {
detail["signal"] = cause.Signal
}
return detail
}