go语言获取机器的进程和进程运行参数 获取当前进程的jmx端口 go调用/jstat获取当前Java进程gc情况
这里主要分享go中获取机器进程和进程参数的一些代码
获取当前机器所有的pid:
import "github.com/shirou/gopsutil/process"
pids, err := process.Pids()
for _, pid := range pids {
proc, err := process.NewProcess(pid)
if err != nil {
log.Errorf("get pid %d info error: %s", pid, err.Error())
continue
}
// 获取进程命令行参数
cmdLine, err := proc.Cmdline()
if err != nil {
log.Errorf("get cmdLine of pid %d error: %s", pid, err.Error())
continue
}
log.Infof("cmdline of pid %d is: %s", pid, cmdLine)
if !strings.Contains(cmdLine, "java") {
continue
}
//获取jmx端口:
// 检查命令行参数是否包含"java"和"Dcom.sun.management.jmxremote.port"
var jmxPort string
if strings.Contains(cmdLine, "Dcom.sun.management.jmxremote.port") {
// 提取JMX端口
re := regexp.MustCompile(`Dcom.sun.management.jmxremote.port=(\d+)`)
match := re.FindStringSubmatch(cmdLine)
if len(match) > 1 {
jmxPort = match[1]
log.Infof("PID: %v, JMX Port: %v , %s, cmdLine: %s\n", pid, match[1], jmxPort, cmdLine)
} else {
log.Infof("not found jmxremote.port or jmxremote.rmi.port")
log.Infof("PID: %v, of cmdLine: %s, has no Dcom.sun.management.jmxremote.port \n", pid, cmdLine)
}
}
Process.CmdlineWithContext 方法的实现依赖于 callPsWithContext 函数来获取进程的命令行参数。这个方法的实现如下:
func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false)
if err != nil {
return "", err
}
return strings.Join(r[0], " "), err
}
调用jstat
JSTAT:JSTAT用于监视和收集Java虚拟机(JVM)的各种统计数据,例如垃圾回收情况、类加载情况、线程数量等。它可以实时显示这些统计数据,帮助开发人员了解应用程序的性能状况。
根据pid获取当前java程序的gc情况:
Command := "jstat"
if e.NewJSTAT {
Command = "/usr/local/jdk/bin/jstat"
}
Data, DataErr, Err = util.RunCommandWithTimeout(&util.CommandArgs{
Cmd: Command,
Username: "root",
Groupname: "root",
Args: []string{"-gcutil", strconv.FormatInt(pid, 10)},
}, 2*time.Second)
func RunCommandWithTimeout(command *CommandArgs, timeout time.Duration) (stdout, stderr string, err error) {
userinfo, err := user.Lookup(command.Username)
if err != nil {
return "", fmt.Sprintf("lookup user err:%s", err.Error()), err
}
uid, _ := strconv.Atoi(userinfo.Uid)
gid, _ := strconv.Atoi(userinfo.Gid)
var outb, errb bytes.Buffer
ctxt, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
getBashCommand(command)
cmd := exec.CommandContext(ctxt, command.Cmd, command.Args...)
cmd.Stdout = &outb
cmd.Stderr = &errb
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)},
Setsid: true,
}
cmd.Env = append(os.Environ(), makeEnv(command.Username)...)
if command.Env != nil && len(command.Env) != 0 {
for k, v := range command.Env {
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v))
}
}
if err := cmd.Start(); err != nil {
return outb.String(), errb.String(), err
}
if err := cmd.Wait(); err != nil {
return outb.String(), errb.String(), err
}
return outb.String(), errb.String(), err
}
调用jcmd命令:
log.Debugf("process jcmd data")
JCMD := "jcmd"
if e.NewJSTAT {
Command = "/usr/local/jdk/bin/jcmd"
}
JcmdData, JcmdDataErr, JcmdErr = util.RunCommandWithTimeout(&util.CommandArgs{
Cmd: JCMD,
Username: "root",
Groupname: "root",
Args: []string{strconv.FormatInt(pid, 10), "VM.flags"},
}, 2*time.Second)
if JcmdErr != nil {
log.Errorf("RunCommandWithTimeout Jcmd JcmdDataErr %s JcmdErr %v", JcmdDataErr, JcmdErr)
}
关于jcmd:
jcmd 是一个用于与 Java 虚拟机 (JVM) 进行交互的命令行工具。它是 JDK(Java Development Kit)的一部分,提供了一系列命令来诊断和监控运行中的 Java 应用程序。jcmd 工具可以用于执行各种操作,例如获取线程堆栈、生成堆转储、执行垃圾回收等。
jcmd 的基本用法
jcmd 的基本用法如下:
jcmd <pid | main class> <command> [options]
<pid | main class>:指定目标 JVM 的进程 ID 或主类名。
<command>:要执行的命令。
[options]:命令的可选参数。
常用命令
以下是一些常用的 jcmd 命令:
列出所有可用的命令:
jcmd help
例如:
jcmd 12345 help
列出所有正在运行的 Java 进程:
jcmd
获取 JVM 版本信息:
jcmd VM.version
例如:
jcmd 12345 VM.version
获取系统属性:
jcmd VM.system_properties
获取 JVM 配置:
jcmd VM.command_line
在docker中执行/jstat
在docker中想执行jstat如下:
func RunDockerPsEfWithTimeout(dockerName string) (stdout, stderr string, err error) {
// docker exec sr-broker ps -ef | grep broker
cmd := exec.Command("/usr/bin/docker", "exec", dockerName, "ps", "-ef")
var outb, errb bytes.Buffer
cmd.Stdout = &outb
cmd.Stderr = &errb
err = cmd.Run()
return outb.String(), errb.String(), err
}
func RunDockerJstatWithTimeout(dockerName string, dockerPid string) (stdout, stderr string, err error) {
stdout, stderr, err := RunDockerPsEfWithTimeout(dockerName)
if err != nil {
log.Errorf("RunDockerCMDWithTimeout dockerPsCmd err %v stderr %s", err, stderr)
return "", "", "", err
}
//获取docker中的pid
dockerPid := ""
lines := strings.Split(stdout, "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) >= 8 {
if strings.Contains(line, dockerPName) {
dockerPid = fields[1]
break
}
}
}
defer func() {
if e := recover(); e != nil {
log.Errorf("RunDockerJstatWithTimeout error %v", e)
}
}()
dockerCmd := []string{"bash", "-c", fmt.Sprintf("source /etc/profile && jstat -gcutil %s", dockerPid)}
cmd := exec.Command("/usr/bin/docker", "exec", dockerName)
cmd.Args = append(cmd.Args, dockerCmd...)
var outb, errb bytes.Buffer
cmd.Stdout = &outb
cmd.Stderr = &errb
err = cmd.Run()
return outb.String(), errb.String(), err
}