public SentryStats(ContainerStatsResponse response) { ContainerId = response.ID; Time = response.Read; Pids = response.PidsStats.Current; // cpu if (response.CPUStats.SystemUsage - response.PreCPUStats.SystemUsage > 0 && response.CPUStats.CPUUsage.TotalUsage - response.PreCPUStats.CPUUsage.TotalUsage >= 0) { CpuPercent = (((decimal)(response.CPUStats.CPUUsage.TotalUsage - response.PreCPUStats.CPUUsage.TotalUsage) / (decimal)(response.CPUStats.SystemUsage - response.PreCPUStats.SystemUsage)) * 100M).ToFixed(2); } // 缓存 var cache = 0UL; if (response.MemoryStats.Stats.TryGetValue("cache", out var c)) { cache = c; } var memoryByte = response.MemoryStats.Usage - cache; MemoryValue = ByteUnitConvert(memoryByte); MemoryPercent = ((decimal)memoryByte / (decimal)response.MemoryStats.MaxUsage * 100M).ToFixed(2); MemoryLimit = ByteUnitConvert(response.MemoryStats.Limit); // net Nets = response.Networks?.ToDictionary( x => x.Key, x => new SentryStatsReadWrite { Read = ByteUnitConvert(x.Value.RxBytes, 1000, 1), Write = ByteUnitConvert(x.Value.TxBytes, 1000, 1) } ); // block Block = new SentryStatsReadWrite { Read = ByteUnitConvert(response.BlkioStats.IoServiceBytesRecursive .Where(x => x.Op == "Read") .Sum(x => (decimal)x.Value), 1000, 1), Write = ByteUnitConvert(response.BlkioStats.IoServiceBytesRecursive .Where(x => x.Op == "Write") .Sum(x => (decimal)x.Value), 1000, 1) }; }
/// <summary> /// Formats the statistics data as required and writes to elasticsearch /// </summary> /// <param name="stats">Statistics for the container</param> private void GetPerformanceStats(ContainerStatsResponse stats) { if (stats == null) { return; } var perfData = new PerfData { TotalCpuUsage = stats.CPUStats?.CPUUsage?.TotalUsage, TotalMemoryUsage = stats.MemoryStats?.Usage, ReadBytes = stats.StorageStats?.ReadSizeBytes, WriteBytes = stats.StorageStats?.WriteSizeBytes, Timestamp = stats.Read, ContainerName = stats.Name.Trim('/'), ContainerId = stats.ID }; Console.WriteLine("Writing data to elasticsearch"); _elasticClient.WriteToEs(perfData); }
private void GetPerformanceStats(ContainerStatsResponse stats) { if (stats == null) { return; } var perfData = new PerfData { TotalCpuUsage = stats.CPUStats?.CPUUsage?.TotalUsage, TotalMemoryUsage = stats.MemoryStats?.Usage, MemoryLimit = stats.MemoryStats?.Limit, ReadBytes = stats.StorageStats?.ReadSizeBytes, WriteBytes = stats.StorageStats?.WriteSizeBytes, Timestamp = stats.Read, ContainerName = stats.Name.Trim('/'), ContainerId = stats.ID }; // Console.WriteLine("Writing data to PerfDictByName, and Container ID is:" + perfData.ContainerId.ToString()); //_elasticClient.WriteToEs(perfData); if (PerfDictByName.ContainsKey(perfData.ContainerName)) { PerfDictByName[perfData.ContainerName] = perfData; } else { PerfDictByName.Add(perfData.ContainerName, perfData); } if (PerfDictByID.ContainsKey(perfData.ContainerId)) { PerfDictByID[perfData.ContainerId] = perfData; } else { PerfDictByID.Add(perfData.ContainerId, perfData); } }
private void UpdateResourceMetrics(ContainerTrackerResourceMetrics metrics, ContainerInspectResponse container, ContainerStatsResponse resources) { // The resource reporting is very different for different operating systems. // This field is only used on Windows. We assume a container can't exist with 0 memory. bool isWindowsContainer = resources.MemoryStats.Commit != 0; // CPU usage // The mechanism of calculation is the rate of increase in container CPU time versus available ("system") CPU time. // The idea here is that we build two series - one counting used CPU in whatever units // the other counting potentially available CPU in whatever units. The % always comes right. // Docker CPU usage on Windows counts 100ns ticks. // Docker CPU usage on Linux counts unspecified ticks in relation to some other stats. // See https://github.com/moby/moby/blob/eb131c5383db8cac633919f82abad86c99bffbe5/cli/command/container/stats_helpers.go#L175 if (isWindowsContainer) { // To compensate for core count on Windows, we normalize the container usage to a single core. // We also normalize the available CPU time to a single core. // This way the Windows calculation is always per-core averaged. // A .NET DateTimeOffset tick is 100ns, exactly, so matches what Docker uses. metrics.CpuCapacity.Set(CpuBaselineTimer.Elapsed.Ticks); metrics.CpuUsage.Set(resources.CPUStats.CPUUsage.TotalUsage / resources.NumProcs); } else { // This is counting all cores (right?). metrics.CpuCapacity.Set(resources.CPUStats.SystemUsage); metrics.CpuUsage.Set(resources.CPUStats.CPUUsage.TotalUsage); } // Memory usage if (isWindowsContainer) { // Windows reports Private Working Set in Docker stats... but seems to use Commit Bytes to enforce limit! // We want to report the same metric that is limited, so there we go. metrics.MemoryUsage.Set(resources.MemoryStats.Commit); } else { metrics.MemoryUsage.Set(resources.MemoryStats.Usage); } // Network I/O if (resources.Networks == null) { metrics.TotalNetworkBytesIn.Set(0); metrics.TotalNetworkBytesOut.Set(0); } else { metrics.TotalNetworkBytesIn.Set(resources.Networks.Values.Sum(n => (double)n.RxBytes)); metrics.TotalNetworkBytesOut.Set(resources.Networks.Values.Sum(n => (double)n.TxBytes)); } // Disk I/O if (isWindowsContainer) { metrics.TotalDiskBytesRead.Set(resources.StorageStats.ReadSizeBytes); metrics.TotalDiskBytesWrite.Set(resources.StorageStats.WriteSizeBytes); } else { var readEntries = resources.BlkioStats.IoServiceBytesRecursive? .Where(entry => entry.Op.Equals("read", StringComparison.InvariantCultureIgnoreCase)) .ToArray(); var writeEntries = resources.BlkioStats.IoServiceBytesRecursive? .Where(entry => entry.Op.Equals("write", StringComparison.InvariantCultureIgnoreCase)) .ToArray(); var totalRead = readEntries == null ? 0 : readEntries.Any() ? readEntries.Sum(entry => (long)entry.Value) : 0; var totalWrite = writeEntries == null ? 0 : writeEntries.Any() ? writeEntries.Sum(entry => (long)entry.Value) : 0; metrics.TotalDiskBytesRead.Set(totalRead); metrics.TotalDiskBytesWrite.Set(totalWrite); } }