github.com/mier85/go-sensor@v1.30.1-0.20220920111756-9bf41b3bc7e0/acceptor/docker.go (about) 1 // (c) Copyright IBM Corp. 2021 2 // (c) Copyright Instana Inc. 2020 3 4 package acceptor 5 6 import ( 7 "time" 8 9 "github.com/mier85/go-sensor/aws" 10 "github.com/mier85/go-sensor/docker" 11 ) 12 13 // DockerData is a representation of a Docker container for com.instana.plugin.docker plugin 14 type DockerData struct { 15 ID string `json:"Id"` 16 Command string `json:"Command"` 17 CreatedAt time.Time `json:"Created"` 18 StartedAt time.Time `json:"Started"` 19 Image string `json:"Image"` 20 Labels aws.ContainerLabels `json:"Labels,omitempty"` 21 Ports string `json:"Ports,omitempty"` 22 PortBindings string `json:"PortBindings,omitempty"` 23 Names []string `json:"Names,omitempty"` 24 NetworkMode string `json:"NetworkMode,omitempty"` 25 StorageDriver string `json:"StorageDriver,omitempty"` 26 DockerVersion string `json:"docker_version,omitempty"` 27 DockerAPIVersion string `json:"docker_api_version,omitempty"` 28 Network *DockerNetworkAggregatedStatsDelta `json:"network,omitempty"` 29 CPU *DockerCPUStatsDelta `json:"cpu,omitempty"` 30 Memory *DockerMemoryStatsUpdate `json:"memory,omitempty"` 31 BlockIO *DockerBlockIOStatsDelta `json:"blkio,omitempty"` 32 } 33 34 // NewDockerPluginPayload returns payload for the Docker plugin of Instana acceptor 35 func NewDockerPluginPayload(entityID string, data DockerData) PluginPayload { 36 const pluginName = "com.instana.plugin.docker" 37 38 return PluginPayload{ 39 Name: pluginName, 40 EntityID: entityID, 41 Data: data, 42 } 43 } 44 45 // DockerNetworkStatsDelta represents the difference between two network interface stats 46 type DockerNetworkStatsDelta struct { 47 Bytes int `json:"bytes,omitempty"` 48 Packets int `json:"packets,omitempty"` 49 Dropped int `json:"dropped,omitempty"` 50 Errors int `json:"errors,omitempty"` 51 } 52 53 // IsZero returns true is there is no difference between interface stats 54 func (d DockerNetworkStatsDelta) IsZero() bool { 55 return d.Bytes == 0 && d.Packets == 0 && d.Dropped == 0 && d.Errors == 0 56 } 57 58 // DockerNetworkAggregatedStatsDelta represents the difference between two network interface stats 59 type DockerNetworkAggregatedStatsDelta struct { 60 Rx *DockerNetworkStatsDelta `json:"rx,omitempty"` 61 Tx *DockerNetworkStatsDelta `json:"tx,omitempty"` 62 } 63 64 // NewDockerNetworkAggregatedStatsDelta calculates the aggregated difference between two snapshots 65 // of network interface stats. It returns nil if aggregated stats for both snapshots are equal. 66 func NewDockerNetworkAggregatedStatsDelta(prev, next map[string]docker.ContainerNetworkStats) *DockerNetworkAggregatedStatsDelta { 67 var rxDelta, txDelta DockerNetworkStatsDelta 68 69 for _, stats := range next { 70 rxDelta.Bytes += stats.RxBytes 71 rxDelta.Packets += stats.RxPackets 72 rxDelta.Dropped += stats.RxDropped 73 rxDelta.Errors += stats.RxErrors 74 75 txDelta.Bytes += stats.TxBytes 76 txDelta.Packets += stats.TxPackets 77 txDelta.Dropped += stats.TxDropped 78 txDelta.Errors += stats.TxErrors 79 } 80 81 for _, stats := range prev { 82 rxDelta.Bytes -= stats.RxBytes 83 rxDelta.Packets -= stats.RxPackets 84 rxDelta.Dropped -= stats.RxDropped 85 rxDelta.Errors -= stats.RxErrors 86 87 txDelta.Bytes -= stats.TxBytes 88 txDelta.Packets -= stats.TxPackets 89 txDelta.Dropped -= stats.TxDropped 90 txDelta.Errors -= stats.TxErrors 91 } 92 93 if rxDelta.IsZero() && txDelta.IsZero() { 94 return nil 95 } 96 97 var delta DockerNetworkAggregatedStatsDelta 98 if !rxDelta.IsZero() { 99 delta.Rx = &rxDelta 100 } 101 if !txDelta.IsZero() { 102 delta.Tx = &txDelta 103 } 104 105 return &delta 106 } 107 108 // DockerCPUStatsDelta represents the difference between two CPU usage stats 109 type DockerCPUStatsDelta struct { 110 Total float64 `json:"total_usage,omitempty"` 111 User float64 `json:"user_usage,omitempty"` 112 System float64 `json:"system_usage,omitempty"` 113 ThrottlingCount int `json:"throttling_count,omitempty"` 114 ThrottlingTime int `json:"throttling_time,omitempty"` 115 } 116 117 // NewDockerCPUStatsDelta calculates the difference between two CPU usage stats. It returns nil if stats are equal. 118 func NewDockerCPUStatsDelta(prev, next docker.ContainerCPUStats) *DockerCPUStatsDelta { 119 if prev == next { 120 return nil 121 } 122 123 delta := DockerCPUStatsDelta{ 124 ThrottlingCount: next.Throttling.Periods - prev.Throttling.Periods, 125 ThrottlingTime: next.Throttling.Time - prev.Throttling.Time, 126 } 127 128 if systemDelta := next.System - prev.System; systemDelta > 0 { 129 if totalDelta := next.Usage.Total - prev.Usage.Total; totalDelta > 0 { 130 delta.Total = (float64(totalDelta) / float64(systemDelta)) * float64(next.OnlineCPUs) 131 } 132 if kernelDelta := next.Usage.Kernel - prev.Usage.Kernel; kernelDelta > 0 { 133 delta.System = (float64(kernelDelta) / float64(systemDelta)) * float64(next.OnlineCPUs) 134 } 135 if userDelta := next.Usage.User - prev.Usage.User; userDelta > 0 { 136 delta.User = (float64(userDelta) / float64(systemDelta)) * float64(next.OnlineCPUs) 137 } 138 } 139 140 return &delta 141 } 142 143 // DockerMemoryStatsUpdate represents the memory stats that have changed since the last measurement 144 type DockerMemoryStatsUpdate struct { 145 ActiveAnon *int `json:"active_anon,omitempty"` 146 ActiveFile *int `json:"active_file,omitempty"` 147 InactiveAnon *int `json:"inactive_anon,omitempty"` 148 InactiveFile *int `json:"inactive_file,omitempty"` 149 TotalCache *int `json:"total_cache,omitempty"` 150 TotalRss *int `json:"total_rss,omitempty"` 151 Usage *int `json:"usage,omitempty"` 152 MaxUsage *int `json:"max_usage,omitempty"` 153 Limit *int `json:"limit,omitempty"` 154 } 155 156 // NewDockerMemoryStatsUpdate returns the fields that have been updated since the last measurement. 157 // It returns nil if nothing has changed. 158 func NewDockerMemoryStatsUpdate(prev, next docker.ContainerMemoryStats) *DockerMemoryStatsUpdate { 159 if prev == next { 160 return nil 161 } 162 163 var delta DockerMemoryStatsUpdate 164 if prev.Usage != next.Usage { 165 delta.Usage = &next.Usage 166 } 167 if prev.MaxUsage != next.MaxUsage { 168 delta.MaxUsage = &next.MaxUsage 169 } 170 if prev.Limit != next.Limit { 171 delta.Limit = &next.Limit 172 } 173 174 if prev.Stats == next.Stats { 175 return &delta 176 } 177 178 if prev.Stats.ActiveAnon != next.Stats.ActiveAnon { 179 delta.ActiveAnon = &next.Stats.ActiveAnon 180 } 181 if prev.Stats.ActiveFile != next.Stats.ActiveFile { 182 delta.ActiveFile = &next.Stats.ActiveFile 183 } 184 if prev.Stats.InactiveAnon != next.Stats.InactiveAnon { 185 delta.InactiveAnon = &next.Stats.InactiveAnon 186 } 187 if prev.Stats.InactiveFile != next.Stats.InactiveFile { 188 delta.InactiveFile = &next.Stats.InactiveFile 189 } 190 if prev.Stats.TotalCache != next.Stats.TotalCache { 191 delta.TotalCache = &next.Stats.TotalCache 192 } 193 if prev.Stats.TotalRss != next.Stats.TotalRss { 194 delta.TotalRss = &next.Stats.TotalRss 195 } 196 197 return &delta 198 } 199 200 // DockerBlockIOStatsDelta represents the difference between two block I/O usage stats 201 type DockerBlockIOStatsDelta struct { 202 Read int `json:"blk_read,omitempty"` 203 Write int `json:"blk_write,omitempty"` 204 } 205 206 // IsZero returns true if both usage stats are equal 207 func (d DockerBlockIOStatsDelta) IsZero() bool { 208 return d.Read == 0 && d.Write == 0 209 } 210 211 // NewDockerBlockIOStatsDelta sums up block I/O reads and writes and calculates the difference between two stat snapshots. 212 // It returns nil if aggregated stats are equal. 213 func NewDockerBlockIOStatsDelta(prev, next docker.ContainerBlockIOStats) *DockerBlockIOStatsDelta { 214 var delta DockerBlockIOStatsDelta 215 216 for _, stat := range next.ServiceBytes { 217 switch stat.Operation { 218 case docker.BlockIOReadOp: 219 delta.Read += stat.Value 220 case docker.BlockIOWriteOp: 221 delta.Write += stat.Value 222 } 223 } 224 225 for _, stat := range prev.ServiceBytes { 226 switch stat.Operation { 227 case docker.BlockIOReadOp: 228 delta.Read -= stat.Value 229 case docker.BlockIOWriteOp: 230 delta.Write -= stat.Value 231 } 232 } 233 234 if delta.IsZero() { 235 return nil 236 } 237 238 return &delta 239 }