Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions granulate_utils/golang.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#
# Copyright (c) Granulate. All rights reserved.
# Licensed under the AGPL3 License. See LICENSE.md in the project root for license information.
#

import functools
import struct
from typing import Optional

from psutil import NoSuchProcess, Process

from granulate_utils.linux.elf import read_elf_symbol, read_elf_va
from granulate_utils.linux.process import process_exe


def is_golang_process(process: Process) -> bool:
return get_process_golang_version(process) is not None


@functools.lru_cache(maxsize=4096)
def get_process_golang_version(process: Process) -> Optional[str]:
elf_path = process_exe(process)
try:
symbol_data = read_elf_symbol(elf_path, "runtime.buildVersion", 16)
except FileNotFoundError:
raise NoSuchProcess(process.pid)
if symbol_data is None:
return None

# Declaration of go string type:
# type stringStruct struct {
# str unsafe.Pointer
# len int
# }
addr, length = struct.unpack("QQ", symbol_data)
try:
golang_version_bytes = read_elf_va(elf_path, addr, length)
except FileNotFoundError:
raise NoSuchProcess(process.pid)
if golang_version_bytes is None:
return None

return golang_version_bytes.decode()
15 changes: 15 additions & 0 deletions granulate_utils/linux/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
# Licensed under the AGPL3 License. See LICENSE.md in the project root for license information.
#
import os
import re
import struct
from contextlib import contextmanager
from typing import Generator, Optional
from functools import lru_cache

import psutil

Expand Down Expand Up @@ -113,3 +115,16 @@ def _translate_errors(process: psutil.Process) -> Generator[None, None, None]:
if not os.path.exists(f"/proc/{process.pid}"):
raise psutil.NoSuchProcess(process.pid)
raise


@lru_cache(maxsize=512)
def is_process_basename_matching(process: psutil.Process, basename_pattern: str) -> bool:
if re.match(basename_pattern, os.path.basename(process_exe(process))):
return True

# process was executed AS basename (but has different exe name)
cmd = process.cmdline()
if len(cmd) > 0 and re.match(basename_pattern, cmd[0]):
return True

return False
12 changes: 12 additions & 0 deletions granulate_utils/node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#
# Copyright (c) Granulate. All rights reserved.
# Licensed under the AGPL3 License. See LICENSE.md in the project root for license information.
#

from psutil import Process

from granulate_utils.linux.process import is_process_basename_matching


def is_node_process(process: Process) -> bool:
return is_process_basename_matching(process, r"^node$")