Observability that ships only what is worth the bytes as link cost rises, while counting everything. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.
npm install @pamoja/telemetry
This pulls in @pamoja/native, the compiled engine. npm install pamoja is the whole framework in one package.
The test that runs in CI, spliced here as it ran.
From bindings/node/guides/telemetry.ts:
import { Level, LinkCost, Reporter, type TelemetryEvent } from '@pamoja/telemetry'
// What a node does with an event the reporter hands back: on a link it sends it, and with
// no link it keeps it for when one returns.
const fate = (event: TelemetryEvent | null, kept: string) => (event === null ? 'counted only' : kept)
// On the site's own network nothing is held back.
const reporter = new Reporter(Level.Trace)
reporter.adaptTo(LinkCost.Free)
let tick = reporter.record({ level: Level.Debug, code: 'loop.tick' })
console.log(`free nothing is held back: loop.tick ${fate(tick, 'sent')}`)
// On a metered link the bar rises to Info. Routine detail stops going out; a reading and a
// warning still do, and a warning carries the measurement that raised it.
reporter.adaptTo(LinkCost.Metered)
tick = reporter.record({ level: Level.Debug, code: 'loop.tick' })
let reading = reporter.record({ level: Level.Info, code: 'reading.ok', value: 4.8 })
console.log(
`metered nothing below ${reporter.threshold} is sent: loop.tick ${fate(tick, 'sent')}, reading.ok ${fate(reading, 'sent')}`,
)
const warned = reporter.record({ level: Level.Warn, code: 'battery.low', value: 0.18 })!
console.log(`metered ${warned.code} sent, carrying ${warned.value!.toFixed(2)}`)
// On satellite the bar is Warn: the same reading is no longer worth its bytes, and a
// failure still is.
reporter.adaptTo(LinkCost.Expensive)
reading = reporter.record({ level: Level.Info, code: 'reading.ok', value: 4.9 })
let lost = reporter.record({ level: Level.Error, code: 'link.lost' })
console.log(
`satellite nothing below ${reporter.threshold} is sent: reading.ok ${fate(reading, 'sent')}, link.lost ${fate(lost, 'sent')}`,
)
// With no link at all only errors are kept, for the link's return.
reporter.adaptTo(LinkCost.Offline)
const low = reporter.record({ level: Level.Warn, code: 'battery.low', value: 0.17 })
lost = reporter.record({ level: Level.Error, code: 'link.lost' })
console.log(
`offline nothing below ${reporter.threshold} is kept: battery.low ${fate(low, 'kept')}, link.lost ${fate(lost, 'kept')}`,
)
// Only the stream was thinned, not the counts, so every event is still accounted for, and
// the snapshot is what the node ships in place of them.
const snapshot = reporter.snapshot()
console.log(
`counts of ${reporter.total} events, ${snapshot.emitted} passed the bar and ${snapshot.dropped} were counted only`,
)
console.log(
`levels trace ${snapshot.trace}, debug ${snapshot.debug}, info ${snapshot.info}, warn ${snapshot.warn}, error ${snapshot.error}`,
)
| Language | Package | Reference |
|---|---|---|
| Rust | pamoja-telemetry |
reference, docs.rs, install |
| TypeScript | @pamoja/telemetry |
reference, install |
| Python | pamoja-telemetry |
reference, install |
| C# | Pamoja.Telemetry |
reference, install |
@pamoja/telemetry reference, every class, function, and type this package exports.MIT
Ergonomic facade over the generated telemetry binding.
A node that ships every event it produces will spend more on reporting than on the job it was installed to do, and on a satellite link that is money. A reporter ships what is worth its bytes, counts everything either way, and moves its own bar as the link gets more expensive, so the aggregate picture survives even when the detail cannot be sent.
The generated binding decides on the level alone, since that is all the core reporter reads. The event a caller writes travels no further than this layer, which hands it straight back when it should be shipped.