| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- package ebpftracer
- import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "os"
- "os/exec"
- "regexp"
- "strconv"
- "strings"
- "unicode"
- )
- func GetJvmVersion(filePath, libjvmPath string) (string, error) {
- minLength := 4
- var maxFileSize int64 = 3 * 1024 * 1024 // 3MB
- // 打开文件
- sofile, err := os.Open(filePath)
- if err != nil {
- return "", fmt.Errorf("failed to open file: %w", err)
- }
- defer sofile.Close()
- // 检查文件大小
- fileInfo, err := sofile.Stat()
- if err != nil {
- return "", fmt.Errorf("failed to stat file: %w", err)
- }
- if fileInfo.Size() > maxFileSize {
- return "", fmt.Errorf("file size exceeds limit of %d bytes", maxFileSize)
- }
- var result []string
- var buffer []rune
- // 逐字节读取文件
- buf := make([]byte, 4096) // 4KB 缓冲区
- for {
- n, err := sofile.Read(buf)
- if n > 0 {
- for _, b := range buf[:n] {
- // 检查是否是可打印字符
- if unicode.IsPrint(rune(b)) {
- buffer = append(buffer, rune(b))
- } else if len(buffer) >= minLength {
- // 如果当前缓冲区长度满足要求,则存入结果
- result = append(result, string(buffer))
- buffer = nil
- } else {
- // 清空缓冲区
- buffer = nil
- }
- }
- }
- if err != nil {
- if err.Error() != "EOF" {
- return "", fmt.Errorf("failed to read file: %w", err)
- }
- break
- }
- }
- // 如果缓冲区有剩余字符串,添加到结果中
- if len(buffer) >= minLength {
- result = append(result, string(buffer))
- }
- // 查找 `java.version` 的下一行
- keyword := "java.version"
- for i, str := range result {
- if str == keyword && i+1 < len(result) {
- return result[i+1], nil // 返回关键字下一行内容
- }
- }
- // 其他版本从jvm获取
- f, err := os.Open(libjvmPath)
- if err != nil {
- return "", fmt.Errorf("failed to open file: %w", err)
- }
- defer f.Close()
- // 读取整个文件(libjvm.so 一般几十 MB 内)
- br := bufio.NewReader(f)
- data, err := io.ReadAll(br)
- if err != nil {
- return "", fmt.Errorf("failed to read file: %w", err)
- }
- if err != nil {
- return "", fmt.Errorf("failed to read file: %w", err)
- }
- text := string(stringsLike(data))
- if m := regexp.MustCompile(`JRE \(([^)]+)\)`).FindStringSubmatch(text); len(m) == 2 {
- return m[1], nil
- }
- return "", fmt.Errorf("failed to extract java version from %s", filePath)
- }
- func stringsLike(b []byte) []byte {
- var out bytes.Buffer
- var buf []byte
- flush := func() {
- if len(buf) >= 4 {
- out.Write(buf)
- out.WriteByte('\n')
- }
- buf = buf[:0]
- }
- for _, c := range b {
- if c >= 32 && c <= 126 { // 可打印 ASCII(不含换行)
- buf = append(buf, c)
- } else {
- flush()
- }
- }
- flush()
- return out.Bytes()
- }
- // 解析版本号为大版本、中间版本和小版本
- func ParseVersion(version string) (int, int, int, error) {
- re := regexp.MustCompile(`^(\d+)\.(\d+)\.(\d+)`)
- matches := re.FindStringSubmatch(version)
- if len(matches) != 4 {
- return 0, 0, 0, fmt.Errorf("invalid version format")
- }
- major, _ := strconv.Atoi(matches[1])
- minor, _ := strconv.Atoi(matches[2])
- patch, _ := strconv.Atoi(matches[3])
- return major, minor, patch, nil
- }
- func parseQuotedString(input string) (string, error) {
- // 找到第一个双引号的位置
- start := strings.Index(input, "\"")
- if start == -1 {
- return "", fmt.Errorf("no start quote found")
- }
- // 找到第二个双引号的位置
- end := strings.Index(input[start+1:], "\"")
- if end == -1 {
- return "", fmt.Errorf("no end quote found")
- }
- // 提取开始和结束引号之间的内容
- content := input[start+1 : start+1+end]
- return content, nil
- }
- // getExecutablePath 根据进程ID获取可执行文件的真实路径。
- func getExecutablePath(pid uint32) (string, error) {
- // 构造文件路径
- link := fmt.Sprintf("/proc/%d/exe", pid)
- // 使用os.Readlink获取符号链接指向的路径
- execPath, err := os.Readlink(link)
- if err != nil {
- return "", err
- }
- return execPath, nil
- }
- func UsePIDToGetJDKVersion(pid uint32) string {
- execPath, err := getExecutablePath(pid)
- if err != nil {
- fmt.Println("Error:", err)
- return ""
- }
- // 构建Command对象
- cmd := exec.Command(execPath, "-version")
- // 创建缓冲区保存输出
- var out bytes.Buffer
- var stderr bytes.Buffer
- cmd.Stdout = &out
- cmd.Stderr = &stderr // java -version 实际是写入Stderr
- // 运行命令
- err = cmd.Run()
- if err != nil {
- fmt.Println("Command execution error:", err)
- fmt.Println("Error output:", stderr.String())
- return ""
- }
- // 打印输出信息
- version, err := parseQuotedString(stderr.String())
- if err != nil {
- fmt.Println("Error:", err)
- return ""
- }
- return version
- }
|