Observability
-- Doc example: observability. `log` is real; `trace`/`measure`/`checkpoint` are
-- decorative markers — they RUN their body but don't persist timing/snapshots.
intent: "doc example: observability"
let answer be 0
measure "demo"
set answer to 41 + 1
print("measure ran → answer = " + text(answer))
test "measure runs its body (the timing instrumentation is decorative)"
let x be 0
measure "compute"
set x to 41 + 1
assert_eq(x, 42)
Logging (real)
log takes a full expression (it's also an expression). Under serve, log/print reach the terminal with a [serve] prefix.
log "Processing order " + order_id
logis a statement, not a function.log "msg"works;log("msg")parses withcheckbut crashes at runtime.
Logs under serve (request logging)
serve does not write an access log for you — by default the terminal is quiet, which makes development hard. Add a log in your handlers to see traffic live:
route "GET /:lang/:version/:slug"
log "GET " + (path of request)
give render_page(...)
Each request then prints in the server's terminal as [serve] [LOG] GET /…. print works there too (same [serve] prefix). (This docs site logs its own requests this way.)
Markers — trace / measure / checkpoint (decorative)
These run their body but the timing/snapshot instrumentation is currently a stub — they do not persist anything. trace/measure take a literal name; checkpoint takes an expression.
measure "db_query"
run_query(sql)
For real crash-resume / step tracking, use the progress builtins, not checkpoint — see Memory & state.
Error diagnostics (opt-in)
Plain run prints a stable one-liner (Runtime error: file:line:col: msg). For a rich report — source context, call stack, visible variables, classification, suggestions — opt in:
synsema run --explain program.syn # human-readable, on stderr
synsema run --explain --format json program.syn # structured, for tools/agents
The exit code is unchanged (1 on failure, 0 on success) either way.