본문 바로가기
코딩/NodeJS

Node.js에서 서버 디스크, 시스템 매니지먼트

by Leedius 2025. 4. 1.

Node.js에서 하드디스크 용량을 가져오는 가장 쉬운 방법은 diskusage 패키지를 사용하는 것입니다.

 

1-1 설치 (한 번만 실행)

npm install check-disk-space

 

시스템 및 디스크 정보 확인

/**
 * 디스크 관리 
 */
module.exports.diskMaagement = async (data) => {
    try {
        const dbPath = await getMongDataPath();
        if (!dbPath) {
            console.error("MongoDB 데이터 경로를 찾을 수 없습니다. 디스크 체크를 건너 뜁니다.");
            return;
        }

        const diskStatus = await checkDiskUsage(dbPath);
        const processList = await getRunningProcesses();

        if (!diskStatus) return

        // console.log('diskStatus', diskStatus);
        // console.log('processList', processList);

        const { usedPercentage } = diskStatus;
        const status = usedPercentage > 80 ? "warning" : "normal";
        const action = usedPercentage > 80 ? "delete" : "wait"

        // 디스크 상태 관력 작업
        const deamonPayload = {
            header: {
                url: "/disk-management",
            },
            meta: {
                status: status,
                action: action
            },
            data: {
                timestamp: new Date().toISOString(),
                process: processList.map(proc => ({
                    pid: proc.pid,
                    name: proc.name,
                }))

            }
        };

        // 데몬에 HTTP 요청으로 데이터 전송
        await sendToDaemon(deamonPayload);

        return deamonPayload;
    } catch (error) {
        console.error('디스크 관리 작업 중 오류:', error);
        throw error;
    }
}

/**
 * 데몬에 페이로드 전송
 * @param {Object} payload 데몬에 전송할 페이로드
 */
async function sendToDaemon(payload) {
    try {
        // 데몬 엔드포인트 URL (환경변수나 설정에서 관리)
        const response = await axios.post(process.env.DAEMON_HOST, payload, {
            headers: {
                'Content-Type': 'application/json'
            },
            timestamp: 30000
        });

        console.log('데몬 응답:', response.data);
        return response.data;
    } catch (error) {
        console.error('데몬 전송 실패:', error.message);

        // 재시도 로직
        if (error.response) {
            console.error('서버 응답 에러:', error.response.data);
            console.error('상태 코드:', error.response.status);
        } else if (error.request) {
            console.error('데몬 응답 없음');
        } else {
            console.error('요청 설정 중 에러:', error.message);
        }

        throw error;
    }
}

/**
 * 현재 실행 중인 프로세스 목록 조회
 * @returns {Promise<Array<{pid: number, name: string, cpu: string, memory: string}}
 */
async function getRunningProcesses() {
    const platform = os.platform();

    try {
        if (platform === 'win32') {
            // Windows: wmic 명령어 사용
            const { stdout } = await execPromise(`powershell "Get-Process | Select-Object Id, ProcessName, CPU, WorkingSet | ConvertTo-Json"`);
            const processList = JSON.parse(stdout);
            return processList.map(proc => ({
                pid: proc.Id,
                name: proc.ProcessName,
                cpu: proc.CPU?.toString() ?? 'N/A',
                memory: proc.WorkingSet ? `${(proc.WorkingSet / 1024 / 1024).toFixed(2)} MB` : 'N/A'
            }));
        } else if (platform === 'linux' || platform === 'darwin') {
            // Linux/macOS: ps 명령어 사용
            const { stdout } = await execPromise('ps aux | head -n 50');
            const lines = stdout.trim().split('\m');

            // 헤더 제거 후 파싱
            return lines.slice(1).map(line => {
                const parts = line.trim().split(/\s+/);
                return {
                    pid: parseInt(parts[1]),
                    name: parts[10],
                    cpu: parts[2] + '%',
                    memory: parts[3] + '%'
                };
            });
        }
    } catch (error) {
        console.error('프로세스 목록 조회 실패:', error);
        return [];
    }
}

/**
 * 디스크 용량 조회
 * @param {string} path - 확인할 경로 (MongoDB 데이터 경로)
 * @returns {Promise<{ total: string, used: string, usedPercentage: number } | null>}
 */
async function checkDiskUsage(path) {
    if (!path) {
        console.error("checkDiskUsage: 경로가 제공되지 않았습니다.");
        return null;
    }

    const platform = os.platform();
    try {
        if (platform === 'win32') {
            // Windows 환경: `powershell` 명령어 사용
            const { stdout } = await execPromise(`powershell -NoProfile -Command "Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DeviceID = \\"${path.charAt(0)}:\\"' | Select-Object Size,FreeSpace | ConvertTo-Json -Compress"`);
            const stdoutResult = JSON.parse(stdout.trim());

            const total = parseInt(stdoutResult.Size); // 디스크 전체 크기
            const free = parseInt(stdoutResult.FreeSpace); // 디스크 빈공간
            const used = total - free; // 디스크 사용중인 용량
            const usedPercentage = ((used / total) * 100).toFixed(2); // 디스크 사용율

            return {
                total: `${(total / (1024 ** 3)).toFixed(2)} GB`,
                used: `${(used / (1024 ** 3)).toFixed(2)} GB`,
                usedPercentage: parseFloat(usedPercentage)
            };
        } else if (platform === 'linux' || platform === 'darwin') {
            // Linux/macOS 환경
            const { stdout } = await execPromise(`df -h "${path}"`);
            const lines = stdout.trim().split('\n');
            const diskInfo = lines[1].split(/\s+/);

            return {
                total: diskInfo[1],
                used: diskInfo[2],
                usedPercentage: parseFloat(diskInfo[4].replace('%', ''))
            };
        }
    } catch (e) {
        console.error("하드디스크 용량 조회 실패:", e);
        return null;
    }
}

/**
 * MongDB 데이터 경로 가져오기
 * @returns {Promise<string | null>}
 */
async function getMongDataPath() {
    const client = new MongoClient(`mongodb://${process.env.MONGO_HOST}:${process.env.MONGO_PORT}`);  // 몽고 디비 주소

    try {
        await client.connect();
        const adminDb = client.db().admin();
        const cmdLineOpts = await adminDb.command({ getCmdLineOpts: 1 });

        // getCmdLineOpts에서 dbPath 가져오기
        const dbPath = cmdLineOpts.parsed?.storage?.dbPath;
        if (dbPath) {
            console.log(`MongoDB Data Path (from getCmdLineOpts): ${dbPath}`);
            return dbPath;
        } else {
            console.warn("getCmdLineOpts에서 dbPath를 찾을 수 없음. 설정 파일에서 검색 중...");
            return getMongDataPathFromConfig();
        }
    } catch (e) {
        console.error('MongoDB 데이터 경로를 찾을 수 없습니다. 설정 파일을 확인합니다', e);
        return getMongDataPathFromConfig();
    } finally {
        await client.close(); // 접속 종료
    }
}

/**
 * MongoDB 설정 파일에서 데이터 경로(dbPath)를 추출합니다.
 * 운영체제(Windows / Linux / macOS)에 따라 여러 설정 파일 경로를 탐색하며,
 * 설정 파일 내의 dbPath 항목을 파싱하여 반환합니다.
 * @returns {Promise<string | null>} - 설정 파일에서 추출한 데이터 경로 또는 실패 시 null
 */
async function getMongDataPathFromConfig() {
    const platform = os.platform();
    let configPaths = [];

    if (platform === "win32") {
        // Windows에서 설정 파일 경로
        configPaths = [
            "C:\\Program Files\\MongoDB\\Server\\4.4\\bin\\mongod.cfg", // 기본 경로
            "C:\\ProgramData\\MongoDB\\mongod.cfg" // 일부 Windows 환경
        ];
    } else {
        // Linux/macOS에서 설정 파일 경로
        configPaths = [
            "/etc/mongod.conf", //Ubuntu/Degian 기본 설정 파일
            "/usr/local/etc/mongod.conf" // macOS Homebrew 설치
        ];
    }

    for (const configPath of configPaths) {
        if (fs.existsSync(configPath)) {
            const configContent = fs.readFileSync(configPath, 'utf8');
            const match = configContent.match(/dbPath\s*:\s*(.*)/); // Linux/macOS
            const matchWin = configContent.match(/dbPath\s*=\s*(.*)/); // Windows

            if (match || matchWin) {
                const path = match ? match[1].trim() : matchWin[1].trim();
                console.log(`MongoDB Data Path (from config file): ${path}`);
                return path
            }
        }
    }

    console.error("MongoDB 데이터 경로를 찾을 수 없습니다.");
    return null;
}

 

* 경로는 Linux & macOS: "/", Windows: "C:\\"

댓글