Embedded observability for industrial Go gateways and other edge Go services.
pulse is a Go library you embed directly into your process to collect runtime metrics, application metrics, and local hardware telemetry with offline-first buffering and export.
Use it when you need:
- in-process observability with minimal operational overhead
- local buffering during network or backend outages
- Linux edge visibility without depending on a cloud agent
- a small integration surface for Go services and gateways
Start here:
- Install:
go get github.com/vagnercazarotto/pulse - Minimal integration: see
Quick startbelow - Runnable examples:
examples/basicandexamples/custom-exporter - Reference docs:
docs/index.html,docs/quickstart.html,docs/current-reference.html
Early implementation (v0.1.0 in progress).
Implemented baseline:
- Agent lifecycle contract
Stop()is idempotentStart()afterStop()on the same instance returnsErrAgentStopped
- Metrics registry with canonical label identity (
name|k=v|...) - Runtime sample collection integrated into the agent loop
- Linux hardware collection integrated into the agent loop (cpu, mem, disk, load, temp when available)
- Ring buffer integrated into agent flow with overflow tracking (
overflow_count) - WAL persistence integrated into agent flow with replay on startup
- Export loop with context-based timeout, configurable retry/backoff, and requeue-on-error behavior
- Runtime collector
- Linux hardware collector (CPU, memory, disk, load, temperature when available)
- Metrics core (counter, gauge, histogram, timer)
- Ring buffer + WAL
- HTTP exporter + log exporter
- Local dashboard + health endpoints
Deferred to v0.2:
- Full cross-platform temperature support
- Full Windows PDH implementation
- Additional advanced exporters
Add pulse to your Go module:
go get github.com/vagnercazarotto/pulseImport it in your application:
import "github.com/vagnercazarotto/pulse"- Basic integration:
examples/basic - Custom exporter:
examples/custom-exporter
package main
import (
"log"
"github.com/vagnercazarotto/pulse"
)
func main() {
agent := pulse.New(pulse.Config{})
if err := agent.Start(); err != nil {
log.Fatal(err)
}
defer agent.Stop()
errors := agent.Metrics().Counter("modbus.errors", map[string]string{
"device": "boiler-01",
"protocol": "tcp",
})
errors.Inc()
}package main
import (
"log"
"time"
"github.com/vagnercazarotto/pulse"
)
func main() {
agent := pulse.New(pulse.Config{
CollectInterval: 2 * time.Second,
})
requests := agent.Metrics().Counter("app.requests_total", map[string]string{
"service": "gateway",
})
temperature := agent.Metrics().Gauge("app.temperature_c", map[string]string{
"device": "boiler-01",
})
if err := agent.Start(); err != nil {
log.Fatal(err)
}
defer agent.Stop()
requests.Inc()
temperature.Set(72.4)
time.Sleep(5 * time.Second)
}package main
import (
"log"
"github.com/vagnercazarotto/pulse"
)
func main() {
httpExporter := pulse.NewHTTPExporter(pulse.HTTPExporterConfig{
Addr: "127.0.0.1:9090",
})
agent := pulse.New(pulse.Config{
Exporters: []pulse.Exporter{httpExporter},
})
if err := agent.Start(); err != nil {
log.Fatal(err)
}
defer agent.Stop()
select {}
}Available endpoints:
//health/metrics.json/metrics
package main
import (
"log"
"time"
"github.com/vagnercazarotto/pulse"
)
func main() {
logExporter := pulse.NewLogExporter(pulse.LogExporterConfig{Pretty: true})
agent := pulse.New(pulse.Config{
ExportInterval: 1 * time.Second,
Exporters: []pulse.Exporter{logExporter},
WAL: &pulse.WALConfig{
Dir: "./pulse-wal",
},
})
errors := agent.Metrics().Counter("modbus.errors_total", map[string]string{
"device": "boiler-01",
})
if err := agent.Start(); err != nil {
log.Fatal(err)
}
defer agent.Stop()
errors.Inc()
time.Sleep(2 * time.Second)
}- Home: Documentation Home
- Quickstart: Quickstart Guide
- Current reference: Current Reference
When zero values are provided in pulse.Config, defaults are applied:
CollectInterval: 10sExportInterval: 10sExportTimeout: 3sBufferSize: 10,000 samplesShutdownTimeout: 5sExportMaxRetries: 5ExportBackoffInitial: 500msExportBackoffMax: 30sExportBackoffJitter: 0.20
Optional WAL:
- Set
Config.WALwith a valid directory to enable disk persistence and replay. - Successful exports acknowledge WAL segments and trigger compaction of acknowledged files.
The agent currently includes runtime metrics in each sample, including:
runtime.goroutinesruntime.heap_alloc_bytesruntime.heap_inuse_bytesruntime.heap_sys_bytesruntime.stack_inuse_bytesruntime.gc_countruntime.gc_pause_ns_lastruntime.gc_pause_total_nsruntime.next_gc_bytesruntime.mallocs_totalruntime.frees_totalruntime.cgo_calls_totalruntime.gc_cpu_fraction
Application metrics from the registry are merged into the same sample payload.
hw.cpu_percenthw.mem_total_byteshw.mem_available_byteshw.mem_used_percenthw.disk_total_byteshw.disk_used_byteshw.disk_used_percenthw.cpu_temp_celsius(when exposed by the Linux host)hw.load1hw.load5hw.load15
Linux (runtime target):
- Linux hardware metrics are implemented and collected from
/procand filesystem stats. - Recommended target for edge runtime and deployment baseline.
Windows (development notes):
- Project builds and root package tests are supported for development workflows.
- In environments with Application Control/AppLocker,
go test ./...may fail because Go executes temporary test binaries from build cache paths. - Practical workaround in restricted environments: prefer
go build ./...for validation and run targeted tests where policy allows execution. - Hardware collector on non-Linux platforms uses a safe no-op stub by design.
- Retryable failures use exponential backoff with jitter.
- Non-retryable failures can be marked with
NonRetryable(err). - Non-retryable failures fail fast (no retry attempts).
- Failed export batches are re-queued in memory.
Implemented now:
- Core agent lifecycle and loops
- Runtime sample generation
- Linux hardware sample generation
- In-memory ring buffer
- WAL write/replay primitives and startup replay path
- Exporter contract and export loop wiring with configurable retry/backoff
Planned next:
- Dashboard endpoints expansion
- Export reliability hardening (error classification by exporter type)
- Additional integration tests and benchmarks