Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.d/feature/ZBXNEXT-65961
-rw-r--r--src/go/pkg/zbxlib/checks_linux.go2
-rw-r--r--src/go/plugins/proc/proc_linux.go110
-rw-r--r--src/go/plugins/proc/procfs_linux.go24
-rw-r--r--src/go/plugins/zabbix/sync/sync_nix.go1
5 files changed, 132 insertions, 6 deletions
diff --git a/ChangeLog.d/feature/ZBXNEXT-6596 b/ChangeLog.d/feature/ZBXNEXT-6596
new file mode 100644
index 00000000000..34bca246711
--- /dev/null
+++ b/ChangeLog.d/feature/ZBXNEXT-6596
@@ -0,0 +1 @@
+...G...... [ZBXNEXT-6596] added native linux proc.num support plugin to Zabbix agent 2 (esneiders)
diff --git a/src/go/pkg/zbxlib/checks_linux.go b/src/go/pkg/zbxlib/checks_linux.go
index 99cefa30cc2..206ad9542d8 100644
--- a/src/go/pkg/zbxlib/checks_linux.go
+++ b/src/go/pkg/zbxlib/checks_linux.go
@@ -74,8 +74,6 @@ func resolveMetric(key string) (cfunc unsafe.Pointer) {
cfunc = unsafe.Pointer(C.NET_DNS)
case "net.dns.record":
cfunc = unsafe.Pointer(C.NET_DNS_RECORD)
- case "proc.num":
- cfunc = unsafe.Pointer(C.PROC_NUM)
case "system.boottime":
cfunc = unsafe.Pointer(C.SYSTEM_BOOTTIME)
case "net.tcp.listen":
diff --git a/src/go/plugins/proc/proc_linux.go b/src/go/plugins/proc/proc_linux.go
index 5b58d120719..20af05f34f8 100644
--- a/src/go/plugins/proc/proc_linux.go
+++ b/src/go/plugins/proc/proc_linux.go
@@ -121,6 +121,7 @@ type procQuery struct {
name string
user string
cmdline string
+ state string
}
const (
@@ -128,6 +129,7 @@ const (
procInfoName
procInfoUser
procInfoCmdline
+ procInfoState
)
type procInfo struct {
@@ -136,6 +138,7 @@ type procInfo struct {
userid int64
cmdline string
arg0 string
+ state string
}
type cpuUtil struct {
@@ -169,6 +172,7 @@ func newCpuUtilQuery(q *procQuery, pattern *regexp.Regexp) (query *cpuUtilQuery,
return
}
}
+
query.cmdlinePattern = pattern
return
}
@@ -181,13 +185,13 @@ func (p *Plugin) prepareQueries() (queries []*cpuUtilQuery, flags int) {
p.mutex.Lock()
for q, stats := range p.queries {
if now.Sub(stats.accessed) > maxInactivityPeriod {
- p.Debugf("removed unused CPU utilisation query %+v", q)
+ p.Debugf("removed unused CPU utilization query %+v", q)
delete(p.queries, q)
continue
}
var query *cpuUtilQuery
if query, stats.err = newCpuUtilQuery(&q, stats.cmdlinePattern); stats.err != nil {
- p.Debugf("cannot create CPU utilisation query %+v: %s", q, stats.err)
+ p.Debugf("cannot create CPU utilization query %+v: %s", q, stats.err)
continue
}
queries = append(queries, query)
@@ -411,9 +415,45 @@ func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider)
}
return
}
+func (p *PluginExport) prepareQuery(q *procQuery) (query *cpuUtilQuery, flags int, err error) {
+ regxp, err := regexp.Compile(q.cmdline)
+ if err != nil {
+ return nil, 0, fmt.Errorf("cannot compile regex for %s: %s", q.cmdline, err.Error())
+ }
+
+ if query, err = newCpuUtilQuery(q, regxp); err != nil {
+ return nil, 0, fmt.Errorf("cannot create CPU utilization query %+v: %s", q, err.Error())
+ }
+
+ if q.name != "" {
+ flags |= procInfoName | procInfoCmdline
+ }
+ if q.user != "" {
+ flags |= procInfoUser
+ }
+ if q.cmdline != "" {
+ flags |= procInfoCmdline
+ }
+ if q.state != "" {
+ flags |= procInfoState
+ }
+
+ return
+}
// Export -
func (p *PluginExport) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) {
+ switch key {
+ case "proc.mem":
+ return p.exportProcMem(params)
+ case "proc.num":
+ return p.exportProcNum(params)
+ }
+
+ return nil, plugin.UnsupportedMetricError
+}
+
+func (p *PluginExport) exportProcMem(params []string) (result interface{}, err error) {
var name, mode, cmdline, memtype string
var usr *user.User
@@ -592,6 +632,67 @@ func (p *PluginExport) Export(key string, params []string, ctx plugin.ContextPro
return memSize, nil
}
+func (p *PluginExport) exportProcNum(params []string) (interface{}, error) {
+ var name, userName, state, cmdline string
+ switch len(params) {
+ case 4:
+ cmdline = params[3]
+ fallthrough
+ case 3:
+ switch params[2] {
+ case "all", "":
+ case "disk":
+ state = "D"
+ case "run":
+ state = "R"
+ case "sleep":
+ state = "S"
+ case "trace":
+ state = "T"
+ case "zomb":
+ state = "Z"
+ default:
+ return nil, errors.New("Invalid third parameter.")
+ }
+ fallthrough
+ case 2:
+ userName = params[1]
+ fallthrough
+ case 1:
+ name = params[0]
+ case 0:
+ default:
+ return nil, errors.New("Too many parameters.")
+ }
+
+ var count int
+
+ query, flags, err := p.prepareQuery(&procQuery{name, userName, cmdline, state})
+ if err != nil {
+ p.Debugf("Failed to prepare query: %s", err.Error())
+ return count, nil
+ }
+
+ procs, err := getProcesses(flags)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to get local processes: %s", err.Error())
+ }
+
+ for _, proc := range procs {
+ if !query.match(proc) {
+ continue
+ }
+
+ if state != proc.state && state != "" {
+ continue
+ }
+
+ count++
+ }
+
+ return count, nil
+}
+
func getMax(a, b float64) float64 {
if a > b {
return a
@@ -675,5 +776,8 @@ func (p *PluginExport) validFile(proc *procInfo, name string, uid int64, cmdRgx
func init() {
plugin.RegisterMetrics(&impl, "Proc", "proc.cpu.util", "Process CPU utilization percentage.")
- plugin.RegisterMetrics(&implExport, "ProcExporter", "proc.mem", "Process memory utilization values.")
+ plugin.RegisterMetrics(&implExport, "ProcExporter",
+ "proc.mem", "Process memory utilization values.",
+ "proc.num", "The number of processes.",
+ )
}
diff --git a/src/go/plugins/proc/procfs_linux.go b/src/go/plugins/proc/procfs_linux.go
index cd9427647a4..e6e16379336 100644
--- a/src/go/plugins/proc/procfs_linux.go
+++ b/src/go/plugins/proc/procfs_linux.go
@@ -27,6 +27,7 @@ import (
"io"
"os"
"strconv"
+ "strings"
"syscall"
"zabbix.com/pkg/procfs"
@@ -61,6 +62,22 @@ func getProcessName(pid string) (name string, err error) {
return string(data[left+1 : right]), nil
}
+func getProcessState(pid string) (name string, err error) {
+ var data []byte
+ if data, err = read2k("/proc/" + pid + "/status"); err != nil {
+ return
+ }
+
+ s := strings.Split(string(data), "\n")
+ for _, tmp := range s {
+ if strings.HasPrefix(tmp, "State:") && len(tmp) > 7 {
+ return string(tmp[7:8]), nil
+ }
+ }
+
+ return "", fmt.Errorf("cannot find process state /proc/%s/status", pid)
+}
+
func getProcessUserID(pid string) (userid int64, err error) {
var fi os.FileInfo
if fi, err = os.Stat("/proc/" + pid); err != nil {
@@ -167,6 +184,13 @@ func getProcesses(flags int) (processes []*procInfo, err error) {
continue
}
}
+ if flags&procInfoState != 0 {
+ if info.state, tmperr = getProcessState(entries[0].Name()); tmperr != nil {
+ impl.Debugf("cannot get process %s state: %s", entries[0].Name(), tmperr)
+ continue
+ }
+ }
+
processes = append(processes, info)
}
diff --git a/src/go/plugins/zabbix/sync/sync_nix.go b/src/go/plugins/zabbix/sync/sync_nix.go
index b743d2e050c..f22ef75fa78 100644
--- a/src/go/plugins/zabbix/sync/sync_nix.go
+++ b/src/go/plugins/zabbix/sync/sync_nix.go
@@ -25,7 +25,6 @@ func getMetrics() []string {
return []string{
"net.dns", "Checks if DNS service is up.",
"net.dns.record", "Performs DNS query.",
- "proc.num", "The number of processes.",
"system.hw.chassis", "Chassis information.",
"system.hw.devices", "Listing of PCI or USB devices.",
"vfs.dir.count", "Directory entry count.",