github.com/elfadel/cilium@v1.6.12/pkg/loadinfo/loadinfo.go (about)

     1  // Copyright 2018-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package loadinfo
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/cilium/cilium/pkg/logging"
    23  	"github.com/cilium/cilium/pkg/logging/logfields"
    24  
    25  	"github.com/shirou/gopsutil/load"
    26  	"github.com/shirou/gopsutil/mem"
    27  	"github.com/shirou/gopsutil/process"
    28  	"github.com/sirupsen/logrus"
    29  )
    30  
    31  const (
    32  	// backgroundInterval is the interval in which system load information is logged
    33  	backgroundInterval = 5 * time.Second
    34  
    35  	// cpuWatermark is the minimum percentage of CPU to have a process
    36  	// listed in the log
    37  	cpuWatermark = 1.0
    38  )
    39  
    40  var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "loadinfo")
    41  
    42  // LogFunc is the function to used to log the system load
    43  type LogFunc func(format string, args ...interface{})
    44  
    45  func toMB(total uint64) uint64 {
    46  	return total / 1024 / 1024
    47  }
    48  
    49  // LogCurrentSystemLoad logs the current system load and lists all processes
    50  // consuming more than cpuWatermark of the CPU
    51  func LogCurrentSystemLoad(logFunc LogFunc) {
    52  	loadInfo, err := load.Avg()
    53  	if err == nil {
    54  		logFunc("Load 1-min: %.2f 5-min: %.2f 15min: %.2f",
    55  			loadInfo.Load1, loadInfo.Load5, loadInfo.Load15)
    56  	}
    57  
    58  	memInfo, err := mem.VirtualMemory()
    59  	if err == nil && memInfo != nil {
    60  		logFunc("Memory: Total: %d Used: %d (%.2f%%) Free: %d Buffers: %d Cached: %d",
    61  			toMB(memInfo.Total), toMB(memInfo.Used), memInfo.UsedPercent, toMB(memInfo.Free), toMB(memInfo.Buffers), toMB(memInfo.Cached))
    62  	}
    63  
    64  	swapInfo, err := mem.SwapMemory()
    65  	if err == nil && swapInfo != nil {
    66  		logFunc("Swap: Total: %d Used: %d (%.2f%%) Free: %d",
    67  			toMB(swapInfo.Total), toMB(swapInfo.Used), swapInfo.UsedPercent, toMB(swapInfo.Free))
    68  	}
    69  
    70  	procs, err := process.Processes()
    71  	if err == nil {
    72  		for _, p := range procs {
    73  			cpuPercent, _ := p.CPUPercent()
    74  			if cpuPercent > cpuWatermark {
    75  				name, _ := p.Name()
    76  				status, _ := p.Status()
    77  				memPercent, _ := p.MemoryPercent()
    78  				cmdline, _ := p.Cmdline()
    79  
    80  				memExt := ""
    81  				if memInfo, err := p.MemoryInfo(); memInfo != nil && err == nil {
    82  					memExt = fmt.Sprintf("RSS: %d VMS: %d Data: %d Stack: %d Locked: %d Swap: %d",
    83  						toMB(memInfo.RSS), toMB(memInfo.VMS), toMB(memInfo.Data),
    84  						toMB(memInfo.Stack), toMB(memInfo.Locked), toMB(memInfo.Swap))
    85  				}
    86  
    87  				logFunc("NAME %s STATUS %s PID %d CPU: %.2f%% MEM: %.2f%% CMDLINE: %s MEM-EXT: %s",
    88  					name, status, p.Pid, cpuPercent, memPercent, cmdline, memExt)
    89  			}
    90  		}
    91  	}
    92  }
    93  
    94  // LogPeriodicSystemLoad logs the system load in the interval specified until
    95  // the given ctx is canceled.
    96  func LogPeriodicSystemLoad(ctx context.Context, logFunc LogFunc, interval time.Duration) {
    97  	go func() {
    98  		LogCurrentSystemLoad(logFunc)
    99  
   100  		t := time.NewTimer(interval)
   101  		defer t.Stop()
   102  		for {
   103  			select {
   104  			case <-ctx.Done():
   105  				return
   106  			case <-t.C:
   107  				LogCurrentSystemLoad(logFunc)
   108  				t.Reset(interval)
   109  			}
   110  		}
   111  	}()
   112  }
   113  
   114  // StartBackgroundLogger starts background logging
   115  func StartBackgroundLogger() {
   116  	LogPeriodicSystemLoad(context.Background(), log.WithFields(logrus.Fields{"type": "background"}).Debugf, backgroundInterval)
   117  }