1// (c) Copyright IBM Corp. 2021
2// (c) Copyright Instana Inc. 2020
3
4package acceptor
5
6import "github.com/instana/go-sensor/process"
7
8// ProcessData is a representation of a running process for com.instana.plugin.process plugin
9type ProcessData struct {
10	PID           int                          `json:"pid"`
11	Exec          string                       `json:"exec"`
12	Args          []string                     `json:"args,omitempty"`
13	Env           map[string]string            `json:"env,omitempty"`
14	User          string                       `json:"user,omitempty"`
15	Group         string                       `json:"group,omitempty"`
16	ContainerID   string                       `json:"container,omitempty"`
17	ContainerPid  int                          `json:"containerPid,string,omitempty"`
18	ContainerType string                       `json:"containerType,omitempty"`
19	Start         int64                        `json:"start"`
20	HostName      string                       `json:"com.instana.plugin.host.name"`
21	HostPID       int                          `json:"com.instana.plugin.host.pid,string"`
22	CPU           *ProcessCPUStatsDelta        `json:"cpu,omitempty"`
23	Memory        *ProcessMemoryStatsUpdate    `json:"mem,omitempty"`
24	OpenFiles     *ProcessOpenFilesStatsUpdate `json:"openFiles,omitempty"`
25}
26
27// NewProcessPluginPayload returns payload for the process plugin of Instana acceptor
28func NewProcessPluginPayload(entityID string, data ProcessData) PluginPayload {
29	const pluginName = "com.instana.plugin.process"
30
31	return PluginPayload{
32		Name:     pluginName,
33		EntityID: entityID,
34		Data:     data,
35	}
36}
37
38// ProcessCPUStatsDelta represents the CPU stats that have changed since the last measurement
39type ProcessCPUStatsDelta struct {
40	User   float64 `json:"user,omitempty"`
41	System float64 `json:"sys,omitempty"`
42}
43
44// NewProcessCPUStatsDelta calculates the difference between two CPU usage stats.
45// It returns nil if stats are equal or if the stats were taken at the same time (ticks).
46// The stats are considered to be equal if the change is less then 1%.
47func NewProcessCPUStatsDelta(prev, next process.CPUStats, ticksElapsed int) *ProcessCPUStatsDelta {
48	if prev == next || ticksElapsed == 0 {
49		return nil
50	}
51
52	delta := &ProcessCPUStatsDelta{}
53	if d := float64(next.System-prev.System) / float64(ticksElapsed); d >= 0.01 {
54		delta.System = d
55	}
56	if d := float64(next.User-prev.User) / float64(ticksElapsed); d >= 0.01 {
57		delta.User = d
58	}
59
60	if delta.User == 0 && delta.System == 0 {
61		return nil
62	}
63
64	return delta
65}
66
67// ProcessMemoryStatsUpdate represents the memory stats that have changed since the last measurement
68type ProcessMemoryStatsUpdate struct {
69	Total  *int `json:"virtual,omitempty"`
70	Rss    *int `json:"resident,omitempty"`
71	Shared *int `json:"share,omitempty"`
72}
73
74// NewProcessMemoryStatsUpdate returns the fields that have been updated since the last measurement.
75// It returns nil if nothing has changed.
76func NewProcessMemoryStatsUpdate(prev, next process.MemStats) *ProcessMemoryStatsUpdate {
77	if prev == next {
78		return nil
79	}
80
81	update := &ProcessMemoryStatsUpdate{}
82	if prev.Total != next.Total {
83		update.Total = &next.Total
84	}
85	if prev.Rss != next.Rss {
86		update.Rss = &next.Rss
87	}
88	if prev.Shared != next.Shared {
89		update.Shared = &next.Shared
90	}
91
92	return update
93}
94
95// ProcessOpenFilesStatsUpdate represents the open file stats and limits that have changed since the last measurement
96type ProcessOpenFilesStatsUpdate struct {
97	Current *int `json:"current,omitempty"`
98	Max     *int `json:"max,omitempty"`
99}
100
101// NewProcessOpenFilesStatsUpdate returns the (process.ResourceLimits).OpenFiles fields that have been updated
102// since the last measurement. It returns nil if nothing has changed.
103func NewProcessOpenFilesStatsUpdate(prev, next process.ResourceLimits) *ProcessOpenFilesStatsUpdate {
104	if prev.OpenFiles == next.OpenFiles {
105		return nil
106	}
107
108	update := &ProcessOpenFilesStatsUpdate{}
109	if prev.OpenFiles.Current != next.OpenFiles.Current {
110		update.Current = &next.OpenFiles.Current
111	}
112	if prev.OpenFiles.Max != next.OpenFiles.Max {
113		update.Max = &next.OpenFiles.Max
114	}
115
116	return update
117}
118