1
0
Fork 0
telegraf/plugins/inputs/internal/internal.go

143 lines
4 KiB
Go
Raw Normal View History

//go:generate ../../../tools/readme_config_includer/generator
package internal
import (
_ "embed"
"fmt"
"runtime"
"runtime/metrics"
"strings"
"github.com/influxdata/telegraf"
inter "github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/selfstat"
)
//go:embed sample.conf
var sampleConfig string
type Internal struct {
CollectMemstats bool `toml:"collect_memstats"`
CollectGostats bool `toml:"collect_gostats"`
}
func (*Internal) SampleConfig() string {
return sampleConfig
}
func (s *Internal) Gather(acc telegraf.Accumulator) error {
for _, m := range selfstat.Metrics() {
if m.Name() == "internal_agent" {
m.AddTag("go_version", strings.TrimPrefix(runtime.Version(), "go"))
}
m.AddTag("version", inter.Version)
acc.AddFields(m.Name(), m.Fields(), m.Tags(), m.Time())
}
if s.CollectMemstats {
collectMemStat(acc)
}
if s.CollectGostats {
collectGoStat(acc)
}
return nil
}
func collectMemStat(acc telegraf.Accumulator) {
m := &runtime.MemStats{}
runtime.ReadMemStats(m)
fields := map[string]any{
"alloc_bytes": m.Alloc, // bytes allocated and not yet freed
"total_alloc_bytes": m.TotalAlloc, // bytes allocated (even if freed)
"sys_bytes": m.Sys, // bytes obtained from system (sum of XxxSys below)
"pointer_lookups": m.Lookups, // number of pointer lookups
"mallocs": m.Mallocs, // number of mallocs
"frees": m.Frees, // number of frees
// Main allocation heap statistics.
"heap_alloc_bytes": m.HeapAlloc, // bytes allocated and not yet freed (same as Alloc above)
"heap_sys_bytes": m.HeapSys, // bytes obtained from system
"heap_idle_bytes": m.HeapIdle, // bytes in idle spans
"heap_in_use_bytes": m.HeapInuse, // bytes in non-idle span
"heap_released_bytes": m.HeapReleased, // bytes released to the OS
"heap_objects": m.HeapObjects, // total number of allocated objects
"num_gc": m.NumGC,
}
acc.AddFields("internal_memstats", fields, make(map[string]string))
}
func collectGoStat(acc telegraf.Accumulator) {
descs := metrics.All()
samples := make([]metrics.Sample, len(descs))
for i := range samples {
samples[i].Name = descs[i].Name
}
metrics.Read(samples)
fields := make(map[string]any, len(samples))
for _, sample := range samples {
name := sanitizeName(sample.Name)
switch sample.Value.Kind() {
case metrics.KindUint64:
fields[name] = sample.Value.Uint64()
case metrics.KindFloat64:
fields[name] = sample.Value.Float64()
case metrics.KindFloat64Histogram:
// The histogram may be quite large, so let's just pull out
// a crude estimate for the median for the sake of this example.
fields[name] = medianBucket(sample.Value.Float64Histogram())
default:
// This may happen as new metrics get added.
//
// The safest thing to do here is to simply log it somewhere
// as something to look into, but ignore it for now.
// In the worst case, you might temporarily miss out on a new metric.
fmt.Printf("%s: unexpected metric Kind: %v\n", name, sample.Value.Kind())
}
}
tags := map[string]string{
"go_version": strings.TrimPrefix(runtime.Version(), "go"),
}
acc.AddFields("internal_gostats", fields, tags)
}
// Converts /cpu/classes/gc/mark/assist:cpu-seconds to cpu_classes_gc_mark_assist_cpu_seconds
func sanitizeName(name string) string {
name = strings.TrimPrefix(name, "/")
name = strings.ReplaceAll(name, "/", "_")
name = strings.ReplaceAll(name, ":", "_")
name = strings.ReplaceAll(name, "-", "_")
return name
}
func medianBucket(h *metrics.Float64Histogram) float64 {
total := uint64(0)
for _, count := range h.Counts {
total += count
}
thresh := total / 2
total = 0
for i, count := range h.Counts {
total += count
if total >= thresh {
return h.Buckets[i]
}
}
// default value in case something above did not work
return 0.0
}
func init() {
inputs.Add("internal", func() telegraf.Input {
return &Internal{
CollectMemstats: true,
}
})
}