157 lines
3.8 KiB
Go
157 lines
3.8 KiB
Go
package instana
|
|
|
|
import (
|
|
"runtime"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// SnapshotPeriod is the amount of time in seconds between snapshot reports.
|
|
SnapshotPeriod = 600
|
|
)
|
|
|
|
// SnapshotS struct to hold snapshot data.
|
|
type SnapshotS struct {
|
|
Name string `json:"name"`
|
|
Version string `json:"version"`
|
|
Root string `json:"goroot"`
|
|
MaxProcs int `json:"maxprocs"`
|
|
Compiler string `json:"compiler"`
|
|
NumCPU int `json:"cpu"`
|
|
}
|
|
|
|
// MemoryS struct to hold snapshot data.
|
|
type MemoryS struct {
|
|
Alloc uint64 `json:"alloc"`
|
|
TotalAlloc uint64 `json:"total_alloc"`
|
|
Sys uint64 `json:"sys"`
|
|
Lookups uint64 `json:"lookups"`
|
|
Mallocs uint64 `json:"mallocs"`
|
|
Frees uint64 `json:"frees"`
|
|
HeapAlloc uint64 `json:"heap_alloc"`
|
|
HeapSys uint64 `json:"heap_sys"`
|
|
HeapIdle uint64 `json:"heap_idle"`
|
|
HeapInuse uint64 `json:"heap_in_use"`
|
|
HeapReleased uint64 `json:"heap_released"`
|
|
HeapObjects uint64 `json:"heap_objects"`
|
|
PauseTotalNs uint64 `json:"pause_total_ns"`
|
|
PauseNs uint64 `json:"pause_ns"`
|
|
NumGC uint32 `json:"num_gc"`
|
|
GCCPUFraction float64 `json:"gc_cpu_fraction"`
|
|
}
|
|
|
|
// MetricsS struct to hold snapshot data.
|
|
type MetricsS struct {
|
|
CgoCall int64 `json:"cgo_call"`
|
|
Goroutine int `json:"goroutine"`
|
|
Memory *MemoryS `json:"memory"`
|
|
}
|
|
|
|
// EntityData struct to hold snapshot data.
|
|
type EntityData struct {
|
|
PID int `json:"pid"`
|
|
Snapshot *SnapshotS `json:"snapshot,omitempty"`
|
|
Metrics *MetricsS `json:"metrics"`
|
|
}
|
|
|
|
type meterS struct {
|
|
sensor *sensorS
|
|
numGC uint32
|
|
ticker *time.Ticker
|
|
snapshotCountdown int
|
|
}
|
|
|
|
func (r *meterS) init() {
|
|
r.ticker = time.NewTicker(1 * time.Second)
|
|
go func() {
|
|
r.snapshotCountdown = 1
|
|
for range r.ticker.C {
|
|
if r.sensor.agent.canSend() {
|
|
r.snapshotCountdown--
|
|
var s *SnapshotS
|
|
if r.snapshotCountdown == 0 {
|
|
r.snapshotCountdown = SnapshotPeriod
|
|
s = r.collectSnapshot()
|
|
log.debug("collected snapshot")
|
|
} else {
|
|
s = nil
|
|
}
|
|
|
|
pid, _ := strconv.Atoi(r.sensor.agent.from.PID)
|
|
d := &EntityData{
|
|
PID: pid,
|
|
Snapshot: s,
|
|
Metrics: r.collectMetrics()}
|
|
|
|
go r.send(d)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (r *meterS) send(d *EntityData) {
|
|
_, err := r.sensor.agent.request(r.sensor.agent.makeURL(agentDataURL), "POST", d)
|
|
|
|
if err != nil {
|
|
r.sensor.agent.reset()
|
|
}
|
|
}
|
|
|
|
func (r *meterS) collectMemoryMetrics() *MemoryS {
|
|
var memStats runtime.MemStats
|
|
runtime.ReadMemStats(&memStats)
|
|
ret := &MemoryS{
|
|
Alloc: memStats.Alloc,
|
|
TotalAlloc: memStats.TotalAlloc,
|
|
Sys: memStats.Sys,
|
|
Lookups: memStats.Lookups,
|
|
Mallocs: memStats.Mallocs,
|
|
Frees: memStats.Frees,
|
|
HeapAlloc: memStats.HeapAlloc,
|
|
HeapSys: memStats.HeapSys,
|
|
HeapIdle: memStats.HeapIdle,
|
|
HeapInuse: memStats.HeapInuse,
|
|
HeapReleased: memStats.HeapReleased,
|
|
HeapObjects: memStats.HeapObjects,
|
|
PauseTotalNs: memStats.PauseTotalNs,
|
|
NumGC: memStats.NumGC,
|
|
GCCPUFraction: memStats.GCCPUFraction}
|
|
|
|
if r.numGC < memStats.NumGC {
|
|
ret.PauseNs = memStats.PauseNs[(memStats.NumGC+255)%256]
|
|
r.numGC = memStats.NumGC
|
|
} else {
|
|
ret.PauseNs = 0
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func (r *meterS) collectMetrics() *MetricsS {
|
|
return &MetricsS{
|
|
CgoCall: runtime.NumCgoCall(),
|
|
Goroutine: runtime.NumGoroutine(),
|
|
Memory: r.collectMemoryMetrics()}
|
|
}
|
|
|
|
func (r *meterS) collectSnapshot() *SnapshotS {
|
|
return &SnapshotS{
|
|
Name: r.sensor.serviceName,
|
|
Version: runtime.Version(),
|
|
Root: runtime.GOROOT(),
|
|
MaxProcs: runtime.GOMAXPROCS(0),
|
|
Compiler: runtime.Compiler,
|
|
NumCPU: runtime.NumCPU()}
|
|
}
|
|
|
|
func (r *sensorS) initMeter() *meterS {
|
|
|
|
log.debug("initializing meter")
|
|
|
|
ret := new(meterS)
|
|
ret.sensor = r
|
|
ret.init()
|
|
|
|
return ret
|
|
}
|