traefik/vendor/github.com/instana/go-sensor/meter.go
2019-02-18 16:52:03 +01:00

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
}