| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | // Copyright (c) 2015-2022 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2023-10-01 04:40:20 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-20 08:53:08 +08:00
										 |  |  | 	"github.com/minio/madmin-go/v3" | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 	"github.com/minio/minio/internal/disk" | 
					
						
							| 
									
										
										
										
											2023-07-14 02:41:19 +08:00
										 |  |  | 	"github.com/minio/minio/internal/net" | 
					
						
							| 
									
										
										
										
											2023-10-01 04:40:20 +08:00
										 |  |  | 	c "github.com/shirou/gopsutil/v3/cpu" | 
					
						
							|  |  |  | 	"github.com/shirou/gopsutil/v3/load" | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-03 17:10:15 +08:00
										 |  |  | type collectMetricsOpts struct { | 
					
						
							|  |  |  | 	hosts map[string]struct{} | 
					
						
							|  |  |  | 	disks map[string]struct{} | 
					
						
							|  |  |  | 	jobID string | 
					
						
							| 
									
										
										
										
											2022-11-14 23:16:40 +08:00
										 |  |  | 	depID string | 
					
						
							| 
									
										
										
										
											2022-10-03 17:10:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func collectLocalMetrics(types madmin.MetricType, opts collectMetricsOpts) (m madmin.RealtimeMetrics) { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	if types == madmin.MetricsNone { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-03 17:10:15 +08:00
										 |  |  | 	if types.Contains(madmin.MetricsDisk) { | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 		m.ByDisk = make(map[string]madmin.DiskMetric) | 
					
						
							|  |  |  | 		aggr := madmin.DiskMetric{ | 
					
						
							|  |  |  | 			CollectedAt: time.Now(), | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-10-03 17:10:15 +08:00
										 |  |  | 		for name, disk := range collectLocalDisksMetrics(opts.disks) { | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 			m.ByDisk[name] = disk | 
					
						
							|  |  |  | 			aggr.Merge(&disk) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		m.Aggregated.Disk = &aggr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	if types.Contains(madmin.MetricsScanner) { | 
					
						
							|  |  |  | 		metrics := globalScannerMetrics.report() | 
					
						
							|  |  |  | 		m.Aggregated.Scanner = &metrics | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if types.Contains(madmin.MetricsOS) { | 
					
						
							|  |  |  | 		metrics := globalOSMetrics.report() | 
					
						
							|  |  |  | 		m.Aggregated.OS = &metrics | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-10-03 17:10:15 +08:00
										 |  |  | 	if types.Contains(madmin.MetricsBatchJobs) { | 
					
						
							|  |  |  | 		m.Aggregated.BatchJobs = globalBatchJobsMetrics.report(opts.jobID) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-11-14 23:16:40 +08:00
										 |  |  | 	if types.Contains(madmin.MetricsSiteResync) { | 
					
						
							|  |  |  | 		m.Aggregated.SiteResync = globalSiteResyncMetrics.report(opts.depID) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-07-14 02:41:19 +08:00
										 |  |  | 	if types.Contains(madmin.MetricNet) { | 
					
						
							|  |  |  | 		m.Aggregated.Net = &madmin.NetMetrics{ | 
					
						
							|  |  |  | 			CollectedAt:   UTCNow(), | 
					
						
							|  |  |  | 			InterfaceName: globalInternodeInterface, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		netStats, err := net.GetInterfaceNetStats(globalInternodeInterface) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2023-10-10 08:27:11 +08:00
										 |  |  | 			m.Errors = append(m.Errors, fmt.Sprintf("%s: %v  (nicstats)", globalMinioAddr, err.Error())) | 
					
						
							| 
									
										
										
										
											2023-07-14 02:41:19 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			m.Aggregated.Net.NetStats = netStats | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-01 04:40:20 +08:00
										 |  |  | 	if types.Contains(madmin.MetricsMem) { | 
					
						
							|  |  |  | 		m.Aggregated.Mem = &madmin.MemMetrics{ | 
					
						
							|  |  |  | 			CollectedAt: UTCNow(), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		m.Aggregated.Mem.Info = madmin.GetMemInfo(GlobalContext, globalMinioAddr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if types.Contains(madmin.MetricsCPU) { | 
					
						
							|  |  |  | 		m.Aggregated.CPU = &madmin.CPUMetrics{ | 
					
						
							|  |  |  | 			CollectedAt: UTCNow(), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cm, err := c.Times(false) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2023-12-07 05:19:59 +08:00
										 |  |  | 			m.Errors = append(m.Errors, fmt.Sprintf("%s: %v (cpuTimes)", globalMinioAddr, err.Error())) | 
					
						
							| 
									
										
										
										
											2023-10-01 04:40:20 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			// not collecting per-cpu stats, so there will be only one element
 | 
					
						
							|  |  |  | 			if len(cm) == 1 { | 
					
						
							|  |  |  | 				m.Aggregated.CPU.TimesStat = &cm[0] | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2023-10-10 08:27:11 +08:00
										 |  |  | 				m.Errors = append(m.Errors, fmt.Sprintf("%s: Expected one CPU stat, got %d", globalMinioAddr, len(cm))) | 
					
						
							| 
									
										
										
										
											2023-10-01 04:40:20 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-07 05:19:59 +08:00
										 |  |  | 		cpuCount, err := c.Counts(true) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			m.Errors = append(m.Errors, fmt.Sprintf("%s: %v (cpuCount)", globalMinioAddr, err.Error())) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			m.Aggregated.CPU.CPUCount = cpuCount | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-01 04:40:20 +08:00
										 |  |  | 		loadStat, err := load.Avg() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2023-10-10 08:27:11 +08:00
										 |  |  | 			m.Errors = append(m.Errors, fmt.Sprintf("%s: %v (loadStat)", globalMinioAddr, err.Error())) | 
					
						
							| 
									
										
										
										
											2023-10-01 04:40:20 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			m.Aggregated.CPU.LoadStat = loadStat | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	// Add types...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ByHost is a shallow reference, so careful about sharing.
 | 
					
						
							| 
									
										
										
										
											2023-10-10 08:27:11 +08:00
										 |  |  | 	m.ByHost = map[string]madmin.Metrics{globalMinioAddr: m.Aggregated} | 
					
						
							|  |  |  | 	m.Hosts = append(m.Hosts, globalMinioAddr) | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return m | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | func collectLocalDisksMetrics(disks map[string]struct{}) map[string]madmin.DiskMetric { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	objLayer := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objLayer == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	metrics := make(map[string]madmin.DiskMetric) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	procStats, procErr := disk.GetAllDrivesIOStats() | 
					
						
							|  |  |  | 	if procErr != nil { | 
					
						
							|  |  |  | 		return metrics | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-22 08:56:43 +08:00
										 |  |  | 	storageInfo := objLayer.LocalStorageInfo(GlobalContext, true) | 
					
						
							| 
									
										
										
										
											2022-12-02 06:31:35 +08:00
										 |  |  | 	for _, d := range storageInfo.Disks { | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 		if len(disks) != 0 { | 
					
						
							|  |  |  | 			_, ok := disks[d.Endpoint] | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 06:31:35 +08:00
										 |  |  | 		if d.State != madmin.DriveStateOk && d.State != madmin.DriveStateUnformatted { | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 			metrics[d.Endpoint] = madmin.DiskMetric{NDisks: 1, Offline: 1} | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var dm madmin.DiskMetric | 
					
						
							|  |  |  | 		dm.NDisks = 1 | 
					
						
							|  |  |  | 		if d.Healing { | 
					
						
							|  |  |  | 			dm.Healing++ | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 		if d.Metrics != nil { | 
					
						
							|  |  |  | 			dm.LifeTimeOps = make(map[string]uint64, len(d.Metrics.APICalls)) | 
					
						
							|  |  |  | 			for k, v := range d.Metrics.APICalls { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 				if v != 0 { | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 					dm.LifeTimeOps[k] = v | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 			dm.LastMinute.Operations = make(map[string]madmin.TimedAction, len(d.Metrics.APICalls)) | 
					
						
							|  |  |  | 			for k, v := range d.Metrics.LastMinute { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 				if v.Count != 0 { | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 					dm.LastMinute.Operations[k] = v | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// get disk
 | 
					
						
							|  |  |  | 		if procErr == nil { | 
					
						
							|  |  |  | 			st := procStats[disk.DevID{Major: d.Major, Minor: d.Minor}] | 
					
						
							|  |  |  | 			dm.IOStats = madmin.DiskIOStats{ | 
					
						
							|  |  |  | 				ReadIOs:        st.ReadIOs, | 
					
						
							|  |  |  | 				ReadMerges:     st.ReadMerges, | 
					
						
							|  |  |  | 				ReadSectors:    st.ReadSectors, | 
					
						
							|  |  |  | 				ReadTicks:      st.ReadTicks, | 
					
						
							|  |  |  | 				WriteIOs:       st.WriteIOs, | 
					
						
							|  |  |  | 				WriteMerges:    st.WriteMerges, | 
					
						
							|  |  |  | 				WriteSectors:   st.WriteSectors, | 
					
						
							|  |  |  | 				WriteTicks:     st.WriteTicks, | 
					
						
							|  |  |  | 				CurrentIOs:     st.CurrentIOs, | 
					
						
							|  |  |  | 				TotalTicks:     st.TotalTicks, | 
					
						
							|  |  |  | 				ReqTicks:       st.ReqTicks, | 
					
						
							|  |  |  | 				DiscardIOs:     st.DiscardIOs, | 
					
						
							|  |  |  | 				DiscardMerges:  st.DiscardMerges, | 
					
						
							|  |  |  | 				DiscardSectors: st.DiscardSectors, | 
					
						
							|  |  |  | 				DiscardTicks:   st.DiscardTicks, | 
					
						
							|  |  |  | 				FlushIOs:       st.FlushIOs, | 
					
						
							|  |  |  | 				FlushTicks:     st.FlushTicks, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		metrics[d.Endpoint] = dm | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-16 22:13:49 +08:00
										 |  |  | 	return metrics | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-03 17:10:15 +08:00
										 |  |  | func collectRemoteMetrics(ctx context.Context, types madmin.MetricType, opts collectMetricsOpts) (m madmin.RealtimeMetrics) { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	if !globalIsDistErasure { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-10-03 17:10:15 +08:00
										 |  |  | 	all := globalNotificationSys.GetMetrics(ctx, types, opts) | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	for _, remote := range all { | 
					
						
							|  |  |  | 		m.Merge(&remote) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return m | 
					
						
							|  |  |  | } |