Monitoring cpu and memory in one goroutine (#919)
This commit is contained in:
Родитель
dba6ed537b
Коммит
855347ccdc
|
@ -38,11 +38,12 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
BlobfuseStats = "blobfuse_stats"
|
||||
FileCacheMon = "file_cache_monitor"
|
||||
CpuProfiler = "cpu_profiler"
|
||||
MemoryProfiler = "memory_profiler"
|
||||
NetworkProfiler = "network_profiler"
|
||||
BlobfuseStats = "blobfuse_stats"
|
||||
FileCacheMon = "file_cache_monitor"
|
||||
CpuProfiler = "cpu_profiler"
|
||||
MemoryProfiler = "memory_profiler"
|
||||
CpuMemoryProfiler = "cpu_mem_profiler"
|
||||
NetworkProfiler = "network_profiler"
|
||||
|
||||
BfuseMon = "bfusemon"
|
||||
|
||||
|
@ -85,3 +86,8 @@ type CacheEvent struct {
|
|||
EvictedFilesCnt int64 `json:"evictedFilesCount"`
|
||||
Value map[string]string `json:"value"`
|
||||
}
|
||||
|
||||
type CpuMemStat struct {
|
||||
CpuUsage string
|
||||
MemUsage string
|
||||
}
|
||||
|
|
|
@ -49,11 +49,10 @@ import (
|
|||
|
||||
func getMonitors() []hminternal.Monitor {
|
||||
compMap := map[string]bool{
|
||||
hmcommon.BlobfuseStats: hmcommon.NoBfsMon,
|
||||
hmcommon.CpuProfiler: hmcommon.NoCpuProf,
|
||||
hmcommon.MemoryProfiler: hmcommon.NoMemProf,
|
||||
hmcommon.NetworkProfiler: hmcommon.NoNetProf,
|
||||
hmcommon.FileCacheMon: hmcommon.NoFileCacheMon,
|
||||
hmcommon.BlobfuseStats: hmcommon.NoBfsMon,
|
||||
hmcommon.CpuMemoryProfiler: (hmcommon.NoCpuProf && hmcommon.NoMemProf),
|
||||
hmcommon.NetworkProfiler: hmcommon.NoNetProf,
|
||||
hmcommon.FileCacheMon: hmcommon.NoFileCacheMon,
|
||||
}
|
||||
|
||||
comps := make([]hminternal.Monitor, 0)
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
_____ _____ _____ ____ ______ _____ ------
|
||||
| | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | |
|
||||
| --- | | | | |-----| |---- | | |-----| |----- ------
|
||||
| | | | | | | | | | | | |
|
||||
| ____| |_____ | ____| | ____| | |_____| _____| |_____ |_____
|
||||
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
|
||||
Copyright © 2020-2022 Microsoft Corporation. All rights reserved.
|
||||
Author : <blobfusedev@microsoft.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
*/
|
||||
|
||||
package cpu_mem_profiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-storage-fuse/v2/common/log"
|
||||
hmcommon "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/common"
|
||||
hminternal "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/internal"
|
||||
)
|
||||
|
||||
type CpuMemProfiler struct {
|
||||
name string
|
||||
pid string
|
||||
pollInterval int
|
||||
}
|
||||
|
||||
func (cm *CpuMemProfiler) GetName() string {
|
||||
return cm.name
|
||||
}
|
||||
|
||||
func (cm *CpuMemProfiler) SetName(name string) {
|
||||
cm.name = name
|
||||
}
|
||||
|
||||
func (cm *CpuMemProfiler) Monitor() error {
|
||||
err := cm.Validate()
|
||||
if err != nil {
|
||||
log.Err("cpu_mem_monitor::Monitor : [%v]", err)
|
||||
return err
|
||||
}
|
||||
log.Debug("cpu_mem_monitor::Monitor : started")
|
||||
|
||||
ticker := time.NewTicker(time.Duration(cm.pollInterval) * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for t := range ticker.C {
|
||||
c, err := cm.getCpuMemoryUsage()
|
||||
if err != nil {
|
||||
log.Err("cpu_mem_monitor::Monitor : [%v]", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if !hmcommon.NoCpuProf {
|
||||
cm.ExportStats(t.Format(time.RFC3339), c.CpuUsage)
|
||||
}
|
||||
if !hmcommon.NoMemProf {
|
||||
cm.ExportStats(t.Format(time.RFC3339), c.MemUsage)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *CpuMemProfiler) ExportStats(timestamp string, st interface{}) {
|
||||
se, err := hminternal.NewStatsExporter()
|
||||
if err != nil || se == nil {
|
||||
log.Err("cpu_mem_monitor::ExportStats : Error in creating stats exporter instance [%v]", err)
|
||||
return
|
||||
}
|
||||
|
||||
s := st.(string)
|
||||
if s[len(s)-1] == '%' {
|
||||
se.AddMonitorStats(hmcommon.CpuProfiler, timestamp, st)
|
||||
} else {
|
||||
se.AddMonitorStats(hmcommon.MemoryProfiler, timestamp, st)
|
||||
}
|
||||
}
|
||||
|
||||
func (cm *CpuMemProfiler) Validate() error {
|
||||
if len(cm.pid) == 0 {
|
||||
return fmt.Errorf("pid of blobfuse2 is not given")
|
||||
}
|
||||
|
||||
if cm.pollInterval == 0 {
|
||||
return fmt.Errorf("process-monitor-interval-sec should be non-zero")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *CpuMemProfiler) getCpuMemoryUsage() (*hmcommon.CpuMemStat, error) {
|
||||
topCmd := "top -b -n 1 -d 0.2 -p " + cm.pid + " | tail -2"
|
||||
|
||||
cliOut, err := exec.Command("bash", "-c", topCmd).Output()
|
||||
if err != nil {
|
||||
log.Err("cpu_mem_monitor::getCpuMemoryUsage : Blobfuse2 is not running on pid %v [%v]", cm.pid, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
processes := strings.Split(strings.Trim(string(cliOut), "\n"), "\n")
|
||||
if len(processes) < 2 {
|
||||
log.Err("cpu_mem_monitor::getCpuMemoryUsage : Blobfuse2 is not running on pid %v", cm.pid)
|
||||
return nil, fmt.Errorf("blobfuse2 is not running on pid %v", cm.pid)
|
||||
}
|
||||
|
||||
cpuIndex, memIndex := getCpuMemIndex(processes[0])
|
||||
stats := strings.Fields(processes[1])
|
||||
if cpuIndex == -1 || memIndex == -1 || len(stats) <= int(math.Max(float64(cpuIndex), float64(memIndex))) || len(stats[cpuIndex]) == 0 || len(stats[memIndex]) == 0 {
|
||||
log.Debug("cpu_mem_monitor::getCpuMemoryUsage : %v", processes)
|
||||
log.Err("cpu_mem_monitor::getCpuMemoryUsage : Blobfuse2 is not running on pid %v", cm.pid)
|
||||
return nil, fmt.Errorf("blobfuse2 is not running on pid %v", cm.pid)
|
||||
}
|
||||
|
||||
cpuMemStat := &hmcommon.CpuMemStat{
|
||||
CpuUsage: stats[cpuIndex],
|
||||
MemUsage: stats[memIndex],
|
||||
}
|
||||
cpuMemStat.CpuUsage += "%"
|
||||
if cpuMemStat.MemUsage[len(cpuMemStat.MemUsage)-1] >= '0' && cpuMemStat.MemUsage[len(cpuMemStat.MemUsage)-1] <= '9' {
|
||||
cpuMemStat.MemUsage += "k"
|
||||
}
|
||||
|
||||
return cpuMemStat, nil
|
||||
}
|
||||
|
||||
func getCpuMemIndex(process string) (int, int) {
|
||||
cols := strings.Fields(process)
|
||||
var cpuIndex, memIndex int = -1, -1
|
||||
for i, col := range cols {
|
||||
if col == "%CPU" {
|
||||
cpuIndex = i
|
||||
} else if col == "VIRT" {
|
||||
memIndex = i
|
||||
}
|
||||
}
|
||||
return cpuIndex, memIndex
|
||||
}
|
||||
|
||||
func NewCpuMemoryMonitor() hminternal.Monitor {
|
||||
cm := &CpuMemProfiler{
|
||||
pid: hmcommon.Pid,
|
||||
pollInterval: hmcommon.ProcMonInterval,
|
||||
}
|
||||
|
||||
cm.SetName(hmcommon.CpuMemoryProfiler)
|
||||
|
||||
return cm
|
||||
}
|
||||
|
||||
func init() {
|
||||
hminternal.AddMonitor(hmcommon.CpuMemoryProfiler, NewCpuMemoryMonitor)
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
_____ _____ _____ ____ ______ _____ ------
|
||||
| | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | |
|
||||
| --- | | | | |-----| |---- | | |-----| |----- ------
|
||||
| | | | | | | | | | | | |
|
||||
| ____| |_____ | ____| | ____| | |_____| _____| |_____ |_____
|
||||
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
|
||||
Copyright © 2020-2022 Microsoft Corporation. All rights reserved.
|
||||
Author : <blobfusedev@microsoft.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
*/
|
||||
|
||||
package cpu_mem_profiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-storage-fuse/v2/common"
|
||||
"github.com/Azure/azure-storage-fuse/v2/common/log"
|
||||
hmcommon "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type cpuMemMonitorTestSuite struct {
|
||||
suite.Suite
|
||||
assert *assert.Assertions
|
||||
}
|
||||
|
||||
func (suite *cpuMemMonitorTestSuite) SetupTest() {
|
||||
suite.assert = assert.New(suite.T())
|
||||
err := log.SetDefaultLogger("silent", common.LogConfig{Level: common.ELogLevel.LOG_DEBUG()})
|
||||
if err != nil {
|
||||
panic("Unable to set silent logger as default.")
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *cpuMemMonitorTestSuite) TestGetCpuMemoryUsage() {
|
||||
cm := &CpuMemProfiler{
|
||||
name: hmcommon.CpuMemoryProfiler,
|
||||
pid: fmt.Sprintf("%v", os.Getpid()),
|
||||
pollInterval: 5,
|
||||
}
|
||||
|
||||
c, err := cm.getCpuMemoryUsage()
|
||||
suite.assert.NotNil(c)
|
||||
suite.assert.Nil(err)
|
||||
}
|
||||
|
||||
func (suite *cpuMemMonitorTestSuite) TestGetCpuMemoryUsageFailure() {
|
||||
cm := &CpuMemProfiler{
|
||||
name: hmcommon.CpuMemoryProfiler,
|
||||
pid: "abcd",
|
||||
pollInterval: 5,
|
||||
}
|
||||
|
||||
c, err := cm.getCpuMemoryUsage()
|
||||
suite.assert.Nil(c)
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func TestCpuMemMonitor(t *testing.T) {
|
||||
suite.Run(t, new(cpuMemMonitorTestSuite))
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
_____ _____ _____ ____ ______ _____ ------
|
||||
| | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | |
|
||||
| --- | | | | |-----| |---- | | |-----| |----- ------
|
||||
| | | | | | | | | | | | |
|
||||
| ____| |_____ | ____| | ____| | |_____| _____| |_____ |_____
|
||||
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
|
||||
Copyright © 2020-2022 Microsoft Corporation. All rights reserved.
|
||||
Author : <blobfusedev@microsoft.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
*/
|
||||
|
||||
package cpu_profiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-storage-fuse/v2/common/log"
|
||||
hmcommon "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/common"
|
||||
hminternal "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/internal"
|
||||
)
|
||||
|
||||
type CpuProfiler struct {
|
||||
name string
|
||||
pid string
|
||||
pollInterval int
|
||||
}
|
||||
|
||||
func (cpu *CpuProfiler) GetName() string {
|
||||
return cpu.name
|
||||
}
|
||||
|
||||
func (cpu *CpuProfiler) SetName(name string) {
|
||||
cpu.name = name
|
||||
}
|
||||
|
||||
func (cpu *CpuProfiler) Monitor() error {
|
||||
err := cpu.Validate()
|
||||
if err != nil {
|
||||
log.Err("cpu_monitor::Monitor : [%v]", err)
|
||||
return err
|
||||
}
|
||||
log.Debug("cpu_monitor::Monitor : started")
|
||||
|
||||
ticker := time.NewTicker(time.Duration(cpu.pollInterval) * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for t := range ticker.C {
|
||||
c, err := cpu.getCpuUsage()
|
||||
if err != nil {
|
||||
log.Err("cpu_monitor::Monitor : [%v]", err)
|
||||
return err
|
||||
}
|
||||
|
||||
cpu.ExportStats(t.Format(time.RFC3339), c)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cpu *CpuProfiler) ExportStats(timestamp string, st interface{}) {
|
||||
se, err := hminternal.NewStatsExporter()
|
||||
if err != nil || se == nil {
|
||||
log.Err("cpu_monitor::ExportStats : Error in creating stats exporter instance [%v]", err)
|
||||
return
|
||||
}
|
||||
|
||||
se.AddMonitorStats(cpu.GetName(), timestamp, st)
|
||||
}
|
||||
|
||||
func (cpu *CpuProfiler) Validate() error {
|
||||
if len(cpu.pid) == 0 {
|
||||
return fmt.Errorf("pid of blobfuse2 is not given")
|
||||
}
|
||||
|
||||
if cpu.pollInterval == 0 {
|
||||
return fmt.Errorf("process-monitor-interval-sec should be non-zero")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cpu *CpuProfiler) getCpuUsage() (string, error) {
|
||||
topCmd := "top -b -n 1 -d 0.2 -p " + cpu.pid + " | tail -1 | awk '{print $9}'"
|
||||
|
||||
cliOut, err := exec.Command("bash", "-c", topCmd).Output()
|
||||
if err != nil {
|
||||
log.Err("cpu_monitor::getCpuUsage : Blobfuse2 is not running on pid %v [%v]", cpu.pid, err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
stats := strings.Split(strings.Split(string(cliOut), "\n")[0], " ")
|
||||
|
||||
if stats[0] == "%CPU" {
|
||||
log.Err("cpu_monitor::getCpuUsage : Blobfuse2 is not running on pid %v", cpu.pid)
|
||||
return "", fmt.Errorf("blobfuse2 is not running on pid %v", cpu.pid)
|
||||
}
|
||||
|
||||
return stats[0] + "%", nil
|
||||
}
|
||||
|
||||
func NewCpuMonitor() hminternal.Monitor {
|
||||
cpu := &CpuProfiler{
|
||||
pid: hmcommon.Pid,
|
||||
pollInterval: hmcommon.ProcMonInterval,
|
||||
}
|
||||
|
||||
cpu.SetName(hmcommon.CpuProfiler)
|
||||
|
||||
return cpu
|
||||
}
|
||||
|
||||
func init() {
|
||||
hminternal.AddMonitor(hmcommon.CpuProfiler, NewCpuMonitor)
|
||||
}
|
|
@ -35,8 +35,7 @@ package monitor
|
|||
|
||||
import (
|
||||
_ "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/monitor/blobfuse_stats"
|
||||
_ "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/monitor/cpu_profiler"
|
||||
_ "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/monitor/cpu_mem_profiler"
|
||||
_ "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/monitor/file_cache"
|
||||
_ "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/monitor/memory_profiler"
|
||||
_ "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/monitor/network_profiler"
|
||||
)
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
_____ _____ _____ ____ ______ _____ ------
|
||||
| | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | |
|
||||
| --- | | | | |-----| |---- | | |-----| |----- ------
|
||||
| | | | | | | | | | | | |
|
||||
| ____| |_____ | ____| | ____| | |_____| _____| |_____ |_____
|
||||
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
|
||||
Copyright © 2020-2022 Microsoft Corporation. All rights reserved.
|
||||
Author : <blobfusedev@microsoft.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
*/
|
||||
|
||||
package memory_profiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-storage-fuse/v2/common/log"
|
||||
hmcommon "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/common"
|
||||
hminternal "github.com/Azure/azure-storage-fuse/v2/tools/health-monitor/internal"
|
||||
)
|
||||
|
||||
type MemoryProfiler struct {
|
||||
name string
|
||||
pid string
|
||||
pollInterval int
|
||||
}
|
||||
|
||||
func (mem *MemoryProfiler) GetName() string {
|
||||
return mem.name
|
||||
}
|
||||
|
||||
func (mem *MemoryProfiler) SetName(name string) {
|
||||
mem.name = name
|
||||
}
|
||||
|
||||
func (mem *MemoryProfiler) Monitor() error {
|
||||
err := mem.Validate()
|
||||
if err != nil {
|
||||
log.Err("memory_monitor::Monitor : [%v]", err)
|
||||
return err
|
||||
}
|
||||
log.Debug("memory_monitor::Monitor : started")
|
||||
|
||||
ticker := time.NewTicker(time.Duration(mem.pollInterval) * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for t := range ticker.C {
|
||||
c, err := mem.getMemoryUsage()
|
||||
if err != nil {
|
||||
log.Err("memory_monitor::Monitor : [%v]", err)
|
||||
return err
|
||||
}
|
||||
|
||||
mem.ExportStats(t.Format(time.RFC3339), c)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mem *MemoryProfiler) ExportStats(timestamp string, st interface{}) {
|
||||
se, err := hminternal.NewStatsExporter()
|
||||
if err != nil || se == nil {
|
||||
log.Err("memory_monitor::ExportStats : Error in creating stats exporter instance [%v]", err)
|
||||
return
|
||||
}
|
||||
|
||||
se.AddMonitorStats(mem.GetName(), timestamp, st)
|
||||
}
|
||||
|
||||
func (mem *MemoryProfiler) Validate() error {
|
||||
if len(mem.pid) == 0 {
|
||||
return fmt.Errorf("pid of blobfuse2 is not given")
|
||||
}
|
||||
|
||||
if mem.pollInterval == 0 {
|
||||
return fmt.Errorf("process-monitor-interval-sec should be non-zero")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mem *MemoryProfiler) getMemoryUsage() (string, error) {
|
||||
topCmd := "top -b -n 1 -d 0.2 -p " + mem.pid + " | tail -1 | awk '{print $5}'"
|
||||
|
||||
cliOut, err := exec.Command("bash", "-c", topCmd).Output()
|
||||
if err != nil {
|
||||
log.Err("memory_monitor::getMemoryUsage : Blobfuse2 is not running on pid %v [%v]", mem.pid, err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
stats := strings.Split(strings.Split(string(cliOut), "\n")[0], " ")
|
||||
|
||||
if stats[0] == "VIRT" {
|
||||
log.Err("memory_monitor::getMemoryUsage : Blobfuse2 is not running on pid %v", mem.pid)
|
||||
return "", fmt.Errorf("blobfuse2 is not running on pid %v", mem.pid)
|
||||
}
|
||||
|
||||
return stats[0], nil
|
||||
}
|
||||
|
||||
func NewMemoryMonitor() hminternal.Monitor {
|
||||
mem := &MemoryProfiler{
|
||||
pid: hmcommon.Pid,
|
||||
pollInterval: hmcommon.ProcMonInterval,
|
||||
}
|
||||
|
||||
mem.SetName(hmcommon.MemoryProfiler)
|
||||
|
||||
return mem
|
||||
}
|
||||
|
||||
func init() {
|
||||
hminternal.AddMonitor(hmcommon.MemoryProfiler, NewMemoryMonitor)
|
||||
}
|
Загрузка…
Ссылка в новой задаче