feat(ludic.telemetry): objects and lists inside an event's properties, an item made of numbers, and a signature of what was written - all in the kept buffer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d1bea7f10e
commit
78a70765af
5 changed files with 83 additions and 3 deletions
|
|
@ -7,6 +7,7 @@ import "state.ludic"
|
|||
import "facts.ludic"
|
||||
import "ports.ludic"
|
||||
import "props.ludic"
|
||||
import "props_nest.ludic"
|
||||
import "stamp.ludic"
|
||||
import "ring.ludic"
|
||||
import "queue.ludic"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ export const TELEMETRY_LINE: int = 2048 # the longest line an event may be; a
|
|||
|
||||
export property TelemetryProps {
|
||||
sb: StrBuf = null
|
||||
n: int = 0 # properties written
|
||||
n: int = 0 # properties written at the top
|
||||
lv: []int = null # inside an object or a list: how many written at each level
|
||||
d: int = 0 # how deep
|
||||
}
|
||||
|
||||
# the writer, emptied, for the next event's properties
|
||||
|
|
@ -12,6 +14,7 @@ export function telemetry_props(telemetry_st: mut TelemetryState) -> TelemetryPr
|
|||
let p = telemetry_st.telemetry__props
|
||||
sb_clear(p.sb)
|
||||
p.n = 0
|
||||
p.d = 0
|
||||
return p
|
||||
}
|
||||
export function telemetry_str(p: TelemetryProps, k: string, s: string) -> void {
|
||||
|
|
@ -27,10 +30,19 @@ export function telemetry_bool(p: TelemetryProps, k: string, b: bool) -> void {
|
|||
if b { sb_add(p.sb, "true") } else { sb_add(p.sb, "false") }
|
||||
}
|
||||
function tp_key(p: TelemetryProps, k: string) -> void {
|
||||
if p.n > 0 { sb_byte(p.sb, 44) }
|
||||
tp_next(p)
|
||||
tj_str(p.sb, k)
|
||||
sb_byte(p.sb, 58)
|
||||
p.n += 1
|
||||
}
|
||||
# a comma before all but the first at this level, and the count kept
|
||||
function tp_next(p: TelemetryProps) -> void {
|
||||
if p.d == 0 {
|
||||
if p.n > 0 { sb_byte(p.sb, 44) }
|
||||
p.n += 1
|
||||
return
|
||||
}
|
||||
if p.lv[p.d] > 0 { sb_byte(p.sb, 44) }
|
||||
p.lv[p.d] += 1
|
||||
}
|
||||
|
||||
# a JSON string: quoted, a quote or a backslash escaped, a control byte as \u00XX
|
||||
|
|
|
|||
37
packages/ludic.telemetry/props_nest.ludic
Normal file
37
packages/ludic.telemetry/props_nest.ludic
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# props_nest.ludic - an object or a list inside an event's properties ($set, a photograph's subjects, the
|
||||
# party's names), written into the same kept buffer; and a signature of what was written, to tell a
|
||||
# change without keeping a copy
|
||||
export function telemetry_obj(p: TelemetryProps, k: string) -> void { tn_open(p, k, 123) }
|
||||
export function telemetry_list(p: TelemetryProps, k: string) -> void { tn_open(p, k, 91) }
|
||||
export function telemetry_obj_end(p: TelemetryProps) -> void { tn_close(p, 125) }
|
||||
export function telemetry_list_end(p: TelemetryProps) -> void { tn_close(p, 93) }
|
||||
function tn_open(p: TelemetryProps, k: string, c: int) -> void {
|
||||
tp_key(p, k)
|
||||
sb_byte(p.sb, c)
|
||||
if p.lv == null { p.lv = words(8) }
|
||||
if p.d < len(p.lv) - 1 { p.d += 1 }
|
||||
p.lv[p.d] = 0
|
||||
}
|
||||
function tn_close(p: TelemetryProps, c: int) -> void {
|
||||
sb_byte(p.sb, c)
|
||||
if p.d > 0 { p.d -= 1 }
|
||||
}
|
||||
# a string in the list being written
|
||||
export function telemetry_item_str(p: TelemetryProps, s: string) -> void {
|
||||
tp_next(p)
|
||||
tj_str(p.sb, s)
|
||||
}
|
||||
# a string item made of numbers the caller writes itself (sb_int, sb_byte - no quote or backslash)
|
||||
export function telemetry_item_open(p: TelemetryProps) -> StrBuf {
|
||||
tp_next(p)
|
||||
sb_byte(p.sb, 34)
|
||||
return p.sb
|
||||
}
|
||||
export function telemetry_item_close(p: TelemetryProps) -> void { sb_byte(p.sb, 34) }
|
||||
|
||||
# a number standing for what has been written: equal when the bytes are (FNV-1a, 31 bits)
|
||||
export function telemetry_props_sig(p: TelemetryProps) -> int {
|
||||
var h = 2166136261 & 2147483647
|
||||
for i in 0 .. sb_len(p.sb) { h = ((h ^ p.sb.b[i]) * 16777619) & 2147483647 }
|
||||
return h
|
||||
}
|
||||
|
|
@ -97,5 +97,6 @@ function telemetry__facts__new() -> Queue<TelemetryFact> { return queue_new("tel
|
|||
function telemetry__props_new() -> TelemetryProps {
|
||||
let p = new TelemetryProps
|
||||
p.sb = sb_new(TELEMETRY_LINE)
|
||||
p.lv = words(8)
|
||||
return p
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,4 +90,33 @@ program RingTest {
|
|||
expect(Text.contains(telemetry_batch_body(telemetry_st, 4), "\"n\":3,"))
|
||||
expect(not Text.contains(telemetry_batch_body(telemetry_st, 4), "TELEMETRY_PLAYER"))
|
||||
}
|
||||
|
||||
test "an object and a list inside the properties are JSON, and the signature tells a change" (telemetry_st: mut TelemetryState) {
|
||||
start(telemetry_st, 50, 65536)
|
||||
let p = telemetry_props(telemetry_st)
|
||||
telemetry_int(p, "grade", 3)
|
||||
telemetry_list(p, "subjects")
|
||||
telemetry_item_str(p, "elk")
|
||||
telemetry_item_str(p, "deer")
|
||||
telemetry_list_end(p)
|
||||
telemetry_obj(p, "$set")
|
||||
telemetry_str(p, "arch", "arm64")
|
||||
telemetry_list(p, "looks")
|
||||
let sb = telemetry_item_open(p)
|
||||
sb_int(sb, 4)
|
||||
sb_byte(sb, 44)
|
||||
sb_int(sb, 2)
|
||||
telemetry_item_close(p)
|
||||
telemetry_list_end(p)
|
||||
telemetry_obj_end(p)
|
||||
telemetry_bool(p, "last", false)
|
||||
let sig = telemetry_props_sig(p)
|
||||
telemetry_event(telemetry_st, "shot", p)
|
||||
let a = telemetry_line(telemetry_st, 0)
|
||||
expect(Text.contains(a, "{\"grade\":3,\"subjects\":[\"elk\",\"deer\"],\"$set\":{\"arch\":\"arm64\",\"looks\":[\"4,2\"]},\"last\":false,"))
|
||||
expect(Json.parse(a) != null)
|
||||
let q = telemetry_props(telemetry_st)
|
||||
telemetry_int(q, "grade", 3)
|
||||
expect(telemetry_props_sig(q) != sig)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue