T-CREATOR

Node.js OS 情報の取得:os モジュール活用事例

Node.js OS 情報の取得:os モジュール活用事例

Node.js でシステム情報を取得したい場面は多くあります。「このサーバーの CPU 使用率はどのくらいだろう?」「どの OS で動いているのか確認したい」といった疑問を持ったことはありませんか。本記事では、os モジュールを活用して OS 情報を効率的に取得する方法を、初心者の方にもわかりやすく解説していきます。

開発者として成長していく中で、システムの内部を理解することは非常に重要です。os モジュールを使いこなすことで、より堅牢で効率的なアプリケーションを作成できるようになります。

os モジュールとは

Node.js 標準ライブラリの概要

Node.js には豊富な標準ライブラリが用意されており、その中でもosモジュールは特に重要な役割を担っています。このモジュールは、Node.js をインストールした瞬間から利用可能で、外部ライブラリをインストールする必要がありません。

Node.js の標準ライブラリは、開発者が日常的に直面する問題を解決するために設計されています。os モジュールも例外ではなく、システム情報の取得という重要な機能を提供してくれます。

os モジュールの役割と特徴

os モジュールは、実行中のオペレーティングシステムに関する情報を取得するためのユーティリティ関数を提供します。このモジュールの素晴らしい点は、クロスプラットフォーム対応していることです。

項目説明
対応 OSWindows, macOS, Linux
インストール不要(Node.js 標準)
パフォーマンス高速(ネイティブ API 使用)
セキュリティ安全(読み取り専用)

主な特徴として、以下のような点が挙げられます:

  • リアルタイム情報取得:現在のシステム状態を即座に取得
  • 軽量:追加のメモリ使用量が少ない
  • 信頼性:Node.js コアチームによる継続的なメンテナンス

OS 情報取得の必要性

システム監視での活用場面

現代の Web アプリケーション開発では、システム監視は必須の要素となっています。「なぜサーバーが重くなったのか?」「メモリ使用量が急増している原因は何か?」といった疑問に答えるためには、システム情報の取得が欠かせません。

os モジュールを使うことで、以下のような監視が可能になります:

  • CPU 使用率の監視:アプリケーションの負荷状況を把握
  • メモリ使用量の追跡:メモリリークの早期発見
  • ネットワーク状態の確認:接続問題の診断

環境依存処理の実装需要

開発環境と本番環境で異なる処理を実行したい場合や、OS によって処理を変える必要がある場合に、os モジュールは威力を発揮します。

例えば、ファイルパスの区切り文字(Windows: \, Unix 系: ​/​)や、実行可能ファイルの拡張子(Windows: .exe, Unix 系: なし)などの違いを自動的に判定できます。

パフォーマンス測定での重要性

アプリケーションの性能を測定する際、システムリソースの使用状況を把握することは非常に重要です。os モジュールを使うことで、以下のような測定が可能になります:

  • ベンチマークテスト:異なる環境での性能比較
  • ボトルネック特定:リソース不足の原因調査
  • キャパシティプランニング:将来の拡張計画立案

os モジュールの基本的な使い方

モジュールの読み込み方法

os モジュールの使用は、非常にシンプルです。以下のコードで簡単に読み込むことができます:

javascript// osモジュールの読み込み
const os = require('os');

// ES6のimport文を使用する場合
// import os from 'os';

console.log('osモジュールが正常に読み込まれました');

このコードを実行すると、os モジュールが利用可能になります。require関数を使うことで、Node.js の標準ライブラリを簡単に利用できるのです。

主要なメソッドの紹介

os モジュールには、多くの有用なメソッドが用意されています。以下が主要なメソッドの一覧です:

メソッド戻り値説明
platform()stringOS 名を取得
cpus()arrayCPU 情報を取得
totalmem()number総メモリ量を取得
freemem()number空きメモリ量を取得
networkInterfaces()objectネットワーク情報を取得
hostname()stringホスト名を取得

基本的な実装例

まずは、基本的な使い方から始めてみましょう。以下のコードは、システムの基本情報を取得する例です:

javascriptconst os = require('os');

// システムの基本情報を取得
function getSystemInfo() {
  console.log('=== システム基本情報 ===');
  console.log(`プラットフォーム: ${os.platform()}`);
  console.log(`アーキテクチャ: ${os.arch()}`);
  console.log(`ホスト名: ${os.hostname()}`);
  console.log(`Node.jsバージョン: ${process.version}`);
  console.log('========================');
}

// 関数を実行
getSystemInfo();

このコードを実行すると、以下のような出力が得られます:

makefile=== システム基本情報 ===
プラットフォーム: darwin
アーキテクチャ: arm64
ホスト名: MacBook-Pro.local
Node.jsバージョン: v18.17.0
========================

具体的な活用事例

システム情報の取得

プラットフォーム情報の取得

プラットフォーム情報の取得は、クロスプラットフォーム対応のアプリケーションを開発する際に非常に重要です。以下のコードで、詳細なプラットフォーム情報を取得できます:

javascriptconst os = require('os');

// プラットフォーム情報を詳細に取得
function getPlatformInfo() {
  const platform = os.platform();
  const release = os.release();
  const version = os.version();

  console.log('=== プラットフォーム情報 ===');
  console.log(`OS: ${platform}`);
  console.log(`リリース: ${release}`);
  console.log(`バージョン: ${version}`);

  // プラットフォーム別の処理分岐
  switch (platform) {
    case 'win32':
      console.log('Windows環境で実行中');
      break;
    case 'darwin':
      console.log('macOS環境で実行中');
      break;
    case 'linux':
      console.log('Linux環境で実行中');
      break;
    default:
      console.log(`未知のプラットフォーム: ${platform}`);
  }
  console.log('===========================');
}

getPlatformInfo();

CPU 情報の取得

CPU 情報の取得は、パフォーマンス監視やリソース管理において重要な機能です。以下のコードで、詳細な CPU 情報を取得できます:

javascriptconst os = require('os');

// CPU情報を詳細に取得
function getCpuInfo() {
  const cpus = os.cpus();

  console.log('=== CPU情報 ===');
  console.log(`CPU数: ${cpus.length}コア`);
  console.log(`モデル: ${cpus[0].model}`);
  console.log(`速度: ${cpus[0].speed}MHz`);

  // 各CPUの使用率を計算
  cpus.forEach((cpu, index) => {
    const total = Object.values(cpu.times).reduce(
      (acc, time) => acc + time,
      0
    );
    const usage = 100 - (cpu.times.idle / total) * 100;
    console.log(`CPU${index}: ${usage.toFixed(2)}%`);
  });

  console.log('===============');
}

getCpuInfo();

メモリ情報の取得

メモリ情報の取得は、アプリケーションのメモリ使用量を監視する際に重要です。以下のコードでメモリ情報を効率的に取得できます:

javascriptconst os = require('os');

// メモリ情報を詳細に取得
function getMemoryInfo() {
  const totalMem = os.totalmem();
  const freeMem = os.freemem();
  const usedMem = totalMem - freeMem;
  const memUsage = (usedMem / totalMem) * 100;

  console.log('=== メモリ情報 ===');
  console.log(`総メモリ: ${formatBytes(totalMem)}`);
  console.log(`使用中: ${formatBytes(usedMem)}`);
  console.log(`空き: ${formatBytes(freeMem)}`);
  console.log(`使用率: ${memUsage.toFixed(2)}%`);

  // メモリ使用率に応じた警告
  if (memUsage > 80) {
    console.log('⚠️  メモリ使用率が高いです!');
  } else if (memUsage > 60) {
    console.log('⚡ メモリ使用率が中程度です');
  } else {
    console.log('✅ メモリ使用率は正常です');
  }

  console.log('==================');
}

// バイト数を読みやすい形式に変換
function formatBytes(bytes) {
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  if (bytes === 0) return '0 Bytes';
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  return (
    Math.round((bytes / Math.pow(1024, i)) * 100) / 100 +
    ' ' +
    sizes[i]
  );
}

getMemoryInfo();

ネットワーク情報の取得

ネットワークインターフェースの取得

ネットワーク情報の取得は、サーバー管理やネットワーク診断において重要な機能です。以下のコードで、詳細なネットワーク情報を取得できます:

javascriptconst os = require('os');

// ネットワークインターフェース情報を取得
function getNetworkInfo() {
  const networkInterfaces = os.networkInterfaces();

  console.log('=== ネットワーク情報 ===');

  Object.keys(networkInterfaces).forEach(
    (interfaceName) => {
      console.log(`\n--- ${interfaceName} ---`);

      networkInterfaces[interfaceName].forEach(
        (interface) => {
          console.log(`  ファミリー: ${interface.family}`);
          console.log(`  アドレス: ${interface.address}`);
          console.log(
            `  内部: ${
              interface.internal ? 'はい' : 'いいえ'
            }`
          );

          if (
            interface.family === 'IPv4' &&
            !interface.internal
          ) {
            console.log(
              `  🌐 外部IPv4アドレス: ${interface.address}`
            );
          }
        }
      );
    }
  );

  console.log('=======================');
}

getNetworkInfo();

ホスト名の取得

ホスト名の取得は、複数のサーバーを管理する際に便利です。以下のコードで、ホスト名を取得し、活用できます:

javascriptconst os = require('os');

// ホスト名を取得して活用
function getHostInfo() {
  const hostname = os.hostname();
  const userInfo = os.userInfo();

  console.log('=== ホスト情報 ===');
  console.log(`ホスト名: ${hostname}`);
  console.log(`ユーザー名: ${userInfo.username}`);
  console.log(`ホームディレクトリ: ${userInfo.homedir}`);
  console.log(`シェル: ${userInfo.shell}`);

  // ホスト名に基づいた処理分岐の例
  if (hostname.includes('prod')) {
    console.log('🏭 本番環境で実行中');
  } else if (hostname.includes('dev')) {
    console.log('🔧 開発環境で実行中');
  } else {
    console.log('💻 ローカル環境で実行中');
  }

  console.log('==================');
}

getHostInfo();

ファイルシステム情報の取得

ホームディレクトリの取得

ファイルシステム情報の取得は、ファイル操作やパス管理において重要です。以下のコードで、各種ディレクトリ情報を取得できます:

javascriptconst os = require('os');
const path = require('path');

// ディレクトリ情報を取得
function getDirectoryInfo() {
  const homeDir = os.homedir();
  const tmpDir = os.tmpdir();

  console.log('=== ディレクトリ情報 ===');
  console.log(`ホームディレクトリ: ${homeDir}`);
  console.log(`一時ディレクトリ: ${tmpDir}`);

  // OS別のパス区切り文字を取得
  const pathSeparator = path.sep;
  console.log(`パス区切り文字: "${pathSeparator}"`);

  // 実用的な例:設定ファイルの保存場所を決定
  const configDir = path.join(homeDir, '.myapp');
  const logDir = path.join(tmpDir, 'myapp-logs');

  console.log(`設定ファイル保存場所: ${configDir}`);
  console.log(`ログファイル保存場所: ${logDir}`);

  console.log('=======================');
}

getDirectoryInfo();

一時ディレクトリの取得

一時ディレクトリの活用は、ファイル処理やキャッシュ管理において重要です:

javascriptconst os = require('os');
const path = require('path');
const fs = require('fs').promises;

// 一時ディレクトリを活用したファイル操作
async function useTempDirectory() {
  const tmpDir = os.tmpdir();
  const tempFilePath = path.join(
    tmpDir,
    `temp-${Date.now()}.json`
  );

  try {
    // 一時ファイルにデータを保存
    const data = {
      timestamp: new Date().toISOString(),
      platform: os.platform(),
      hostname: os.hostname(),
      memoryUsage: process.memoryUsage(),
    };

    await fs.writeFile(
      tempFilePath,
      JSON.stringify(data, null, 2)
    );
    console.log(
      `一時ファイルを作成しました: ${tempFilePath}`
    );

    // ファイルの内容を読み取り
    const content = await fs.readFile(tempFilePath, 'utf8');
    console.log('ファイル内容:', content);

    // 一時ファイルをクリーンアップ
    await fs.unlink(tempFilePath);
    console.log('一時ファイルを削除しました');
  } catch (error) {
    console.error('ファイル操作エラー:', error.message);
  }
}

useTempDirectory();

実践的な応用例

システム監視ツールの作成

実際のプロジェクトで使える、システム監視ツールを作成してみましょう。このツールは、定期的にシステム情報を取得し、異常を検知します:

javascriptconst os = require('os');
const fs = require('fs').promises;
const path = require('path');

class SystemMonitor {
  constructor(options = {}) {
    this.interval = options.interval || 5000; // 5秒間隔
    this.logFile =
      options.logFile ||
      path.join(os.tmpdir(), 'system-monitor.log');
    this.memoryThreshold = options.memoryThreshold || 80; // 80%で警告
    this.cpuThreshold = options.cpuThreshold || 80; // 80%で警告
    this.running = false;
  }

  // システム情報を取得
  getSystemStats() {
    const totalMem = os.totalmem();
    const freeMem = os.freemem();
    const usedMem = totalMem - freeMem;
    const memUsage = (usedMem / totalMem) * 100;

    return {
      timestamp: new Date().toISOString(),
      platform: os.platform(),
      hostname: os.hostname(),
      memory: {
        total: totalMem,
        used: usedMem,
        free: freeMem,
        usage: Math.round(memUsage * 100) / 100,
      },
      cpuCount: os.cpus().length,
      uptime: os.uptime(),
      loadavg: os.loadavg(),
    };
  }

  // 異常検知
  checkAlerts(stats) {
    const alerts = [];

    if (stats.memory.usage > this.memoryThreshold) {
      alerts.push({
        type: 'memory',
        message: `メモリ使用率が閾値を超えました: ${stats.memory.usage}%`,
        severity: 'warning',
      });
    }

    return alerts;
  }

  // ログ出力
  async logStats(stats, alerts = []) {
    const logEntry = {
      ...stats,
      alerts: alerts,
    };

    const logLine = JSON.stringify(logEntry) + '\n';

    try {
      await fs.appendFile(this.logFile, logLine);
    } catch (error) {
      console.error('ログ書き込みエラー:', error.message);
    }
  }

  // 監視開始
  start() {
    if (this.running) {
      console.log('監視は既に開始されています');
      return;
    }

    this.running = true;
    console.log(
      `システム監視を開始しました (間隔: ${this.interval}ms)`
    );

    this.intervalId = setInterval(() => {
      const stats = this.getSystemStats();
      const alerts = this.checkAlerts(stats);

      // コンソールに出力
      console.log(
        `[${stats.timestamp}] メモリ使用率: ${stats.memory.usage}%`
      );

      // アラートがあれば表示
      alerts.forEach((alert) => {
        console.log(`🚨 ${alert.message}`);
      });

      // ログファイルに保存
      this.logStats(stats, alerts);
    }, this.interval);
  }

  // 監視停止
  stop() {
    if (!this.running) {
      console.log('監視は停止されています');
      return;
    }

    clearInterval(this.intervalId);
    this.running = false;
    console.log('システム監視を停止しました');
  }
}

// 使用例
const monitor = new SystemMonitor({
  interval: 3000,
  memoryThreshold: 70,
});

monitor.start();

// 10秒後に停止
setTimeout(() => {
  monitor.stop();
}, 10000);

環境判定処理の実装

環境によって異なる処理を実行する、実用的な環境判定システムを作成しましょう:

javascriptconst os = require('os');
const path = require('path');

class EnvironmentDetector {
  constructor() {
    this.platform = os.platform();
    this.hostname = os.hostname();
    this.environment = this.detectEnvironment();
    this.config = this.loadConfig();
  }

  // 環境を判定
  detectEnvironment() {
    const hostname = this.hostname.toLowerCase();

    if (
      hostname.includes('prod') ||
      hostname.includes('production')
    ) {
      return 'production';
    } else if (
      hostname.includes('stg') ||
      hostname.includes('staging')
    ) {
      return 'staging';
    } else if (
      hostname.includes('dev') ||
      hostname.includes('development')
    ) {
      return 'development';
    } else {
      return 'local';
    }
  }

  // 環境別の設定を読み込み
  loadConfig() {
    const baseConfig = {
      local: {
        database: {
          host: 'localhost',
          port: 5432,
          ssl: false,
        },
        logging: {
          level: 'debug',
          file: path.join(os.tmpdir(), 'app-local.log'),
        },
      },
      development: {
        database: {
          host: 'dev-db.example.com',
          port: 5432,
          ssl: true,
        },
        logging: {
          level: 'info',
          file: '/var/log/app-dev.log',
        },
      },
      staging: {
        database: {
          host: 'stg-db.example.com',
          port: 5432,
          ssl: true,
        },
        logging: {
          level: 'warn',
          file: '/var/log/app-stg.log',
        },
      },
      production: {
        database: {
          host: 'prod-db.example.com',
          port: 5432,
          ssl: true,
        },
        logging: {
          level: 'error',
          file: '/var/log/app-prod.log',
        },
      },
    };

    return baseConfig[this.environment] || baseConfig.local;
  }

  // 環境情報を表示
  displayEnvironmentInfo() {
    console.log('=== 環境情報 ===');
    console.log(`プラットフォーム: ${this.platform}`);
    console.log(`ホスト名: ${this.hostname}`);
    console.log(`環境: ${this.environment}`);
    console.log(
      `設定:`,
      JSON.stringify(this.config, null, 2)
    );
    console.log('===============');
  }

  // 環境別の処理実行
  executeEnvironmentSpecificTask() {
    switch (this.environment) {
      case 'production':
        console.log('🏭 本番環境の処理を実行中...');
        this.productionTask();
        break;
      case 'staging':
        console.log('🔧 ステージング環境の処理を実行中...');
        this.stagingTask();
        break;
      case 'development':
        console.log('💻 開発環境の処理を実行中...');
        this.developmentTask();
        break;
      default:
        console.log('🏠 ローカル環境の処理を実行中...');
        this.localTask();
    }
  }

  productionTask() {
    console.log('  - 本番データベースに接続');
    console.log('  - エラーログのみ出力');
    console.log('  - パフォーマンス監視を有効化');
  }

  stagingTask() {
    console.log('  - ステージングデータベースに接続');
    console.log('  - 警告レベル以上のログを出力');
    console.log('  - テスト用の機能を有効化');
  }

  developmentTask() {
    console.log('  - 開発データベースに接続');
    console.log('  - 詳細なログを出力');
    console.log('  - デバッグ機能を有効化');
  }

  localTask() {
    console.log('  - ローカルデータベースに接続');
    console.log('  - 全てのログを出力');
    console.log('  - 開発支援ツールを有効化');
  }
}

// 使用例
const envDetector = new EnvironmentDetector();
envDetector.displayEnvironmentInfo();
envDetector.executeEnvironmentSpecificTask();

ログ出力での活用

os モジュールの情報を活用した、高機能なログ出力システムを作成しましょう:

javascriptconst os = require('os');
const fs = require('fs').promises;
const path = require('path');

class SystemLogger {
  constructor(options = {}) {
    this.logDir =
      options.logDir || path.join(os.tmpdir(), 'app-logs');
    this.maxFileSize =
      options.maxFileSize || 10 * 1024 * 1024; // 10MB
    this.maxFiles = options.maxFiles || 5;
    this.systemInfo = this.getSystemInfo();
    this.initializeLogger();
  }

  // システム情報を取得
  getSystemInfo() {
    return {
      platform: os.platform(),
      arch: os.arch(),
      hostname: os.hostname(),
      nodeVersion: process.version,
      pid: process.pid,
      startTime: new Date().toISOString(),
    };
  }

  // ロガーの初期化
  async initializeLogger() {
    try {
      await fs.mkdir(this.logDir, { recursive: true });
      console.log(
        `ログディレクトリを作成しました: ${this.logDir}`
      );
    } catch (error) {
      console.error(
        'ログディレクトリの作成に失敗しました:',
        error.message
      );
    }
  }

  // ログメッセージの作成
  createLogMessage(level, message, additionalInfo = {}) {
    const timestamp = new Date().toISOString();
    const memUsage = process.memoryUsage();

    return {
      timestamp,
      level,
      message,
      system: {
        hostname: this.systemInfo.hostname,
        platform: this.systemInfo.platform,
        pid: this.systemInfo.pid,
        memory: {
          rss: memUsage.rss,
          heapUsed: memUsage.heapUsed,
          external: memUsage.external,
        },
        uptime: process.uptime(),
      },
      ...additionalInfo,
    };
  }

  // ログファイルに書き込み
  async writeLog(logMessage) {
    const logFileName = `app-${
      new Date().toISOString().split('T')[0]
    }.log`;
    const logFilePath = path.join(this.logDir, logFileName);
    const logLine = JSON.stringify(logMessage) + '\n';

    try {
      await fs.appendFile(logFilePath, logLine);

      // ファイルサイズチェックとローテーション
      await this.checkAndRotateLog(logFilePath);
    } catch (error) {
      console.error('ログ書き込みエラー:', error.message);
    }
  }

  // ログローテーション
  async checkAndRotateLog(logFilePath) {
    try {
      const stats = await fs.stat(logFilePath);

      if (stats.size > this.maxFileSize) {
        const timestamp = new Date()
          .toISOString()
          .replace(/[:.]/g, '-');
        const rotatedPath = logFilePath.replace(
          '.log',
          `-${timestamp}.log`
        );

        await fs.rename(logFilePath, rotatedPath);
        console.log(
          `ログファイルをローテーションしました: ${rotatedPath}`
        );

        // 古いログファイルを削除
        await this.cleanupOldLogs();
      }
    } catch (error) {
      console.error(
        'ログローテーションエラー:',
        error.message
      );
    }
  }

  // 古いログファイルのクリーンアップ
  async cleanupOldLogs() {
    try {
      const files = await fs.readdir(this.logDir);
      const logFiles = files
        .filter((file) => file.endsWith('.log'))
        .map((file) => path.join(this.logDir, file));

      if (logFiles.length > this.maxFiles) {
        // ファイルの作成日時でソート
        const fileStats = await Promise.all(
          logFiles.map(async (file) => ({
            path: file,
            mtime: (await fs.stat(file)).mtime,
          }))
        );

        fileStats.sort((a, b) => b.mtime - a.mtime);

        // 古いファイルを削除
        const filesToDelete = fileStats.slice(
          this.maxFiles
        );
        for (const file of filesToDelete) {
          await fs.unlink(file.path);
          console.log(
            `古いログファイルを削除しました: ${file.path}`
          );
        }
      }
    } catch (error) {
      console.error(
        'ログクリーンアップエラー:',
        error.message
      );
    }
  }

  // 各レベルのログメソッド
  async info(message, additionalInfo = {}) {
    const logMessage = this.createLogMessage(
      'INFO',
      message,
      additionalInfo
    );
    await this.writeLog(logMessage);
    console.log(`ℹ️  ${message}`);
  }

  async warn(message, additionalInfo = {}) {
    const logMessage = this.createLogMessage(
      'WARN',
      message,
      additionalInfo
    );
    await this.writeLog(logMessage);
    console.warn(`⚠️  ${message}`);
  }

  async error(message, error = null, additionalInfo = {}) {
    const logMessage = this.createLogMessage(
      'ERROR',
      message,
      {
        error: error
          ? {
              name: error.name,
              message: error.message,
              stack: error.stack,
            }
          : null,
        ...additionalInfo,
      }
    );
    await this.writeLog(logMessage);
    console.error(`🚨 ${message}`);
  }
}

// 使用例
async function demonstrateLogging() {
  const logger = new SystemLogger({
    logDir: path.join(os.homedir(), 'app-logs'),
  });

  await logger.info('アプリケーションを開始しました');
  await logger.warn('設定ファイルが見つかりません', {
    configPath: './config.json',
  });

  try {
    // エラーを発生させる例
    throw new Error('データベース接続エラー');
  } catch (error) {
    await logger.error(
      'データベースエラーが発生しました',
      error,
      {
        database: 'primary',
        attempt: 1,
      }
    );
  }

  await logger.info(
    'ログ出力のデモンストレーションが完了しました'
  );
}

demonstrateLogging();

注意点とベストプラクティス

エラーハンドリングの重要性

os モジュールを使用する際によく発生するエラーと、その対処法について説明します。適切なエラーハンドリングは、堅牢なアプリケーションを作成する上で不可欠です。

javascriptconst os = require('os');

// エラーハンドリングの実装例
function safeGetSystemInfo() {
  try {
    const systemInfo = {
      platform: os.platform(),
      hostname: os.hostname(),
      totalMemory: os.totalmem(),
      freeMemory: os.freemem(),
      cpuCount: os.cpus().length,
    };

    // データの妥当性チェック
    if (systemInfo.totalMemory <= 0) {
      throw new Error(
        'Invalid memory information detected'
      );
    }

    return systemInfo;
  } catch (error) {
    console.error(
      'システム情報の取得に失敗しました:',
      error.message
    );

    // よくあるエラーの例
    if (error.code === 'ENOENT') {
      console.error(
        'ファイルまたはディレクトリが見つかりません'
      );
    } else if (error.code === 'EACCES') {
      console.error('アクセス権限がありません');
    } else if (error.code === 'EMFILE') {
      console.error(
        '開いているファイル数が上限に達しました'
      );
    }

    // フォールバック値を返す
    return {
      platform: 'unknown',
      hostname: 'unknown',
      totalMemory: 0,
      freeMemory: 0,
      cpuCount: 1,
    };
  }
}

// 使用例
const systemInfo = safeGetSystemInfo();
console.log('システム情報:', systemInfo);

パフォーマンス考慮事項

os モジュールのメソッドは軽量ですが、頻繁な呼び出しはパフォーマンスに影響を与える可能性があります。以下に最適化の方法を示します:

javascriptconst os = require('os');

class PerformanceOptimizedMonitor {
  constructor() {
    this.cache = new Map();
    this.cacheTimeout = 1000; // 1秒間キャッシュ
    this.lastCacheTime = 0;
  }

  // キャッシュ機能付きのシステム情報取得
  getSystemInfo() {
    const now = Date.now();
    const cacheKey = 'systemInfo';

    // キャッシュが有効かチェック
    if (
      this.cache.has(cacheKey) &&
      now - this.lastCacheTime < this.cacheTimeout
    ) {
      return this.cache.get(cacheKey);
    }

    // 新しいデータを取得
    const systemInfo = {
      platform: os.platform(),
      hostname: os.hostname(),
      totalMemory: os.totalmem(),
      freeMemory: os.freemem(),
      cpuCount: os.cpus().length,
      uptime: os.uptime(),
      timestamp: now,
    };

    // キャッシュに保存
    this.cache.set(cacheKey, systemInfo);
    this.lastCacheTime = now;

    return systemInfo;
  }

  // 重い処理の最適化例
  getCpuUsage() {
    const cacheKey = 'cpuUsage';
    const now = Date.now();

    if (
      this.cache.has(cacheKey) &&
      now - this.lastCacheTime < this.cacheTimeout
    ) {
      return this.cache.get(cacheKey);
    }

    const startTime = process.hrtime();
    const cpus = os.cpus();
    const endTime = process.hrtime(startTime);

    // 処理時間を記録
    const processingTime =
      endTime[0] * 1000 + endTime[1] / 1000000;
    console.log(
      `CPU情報の取得時間: ${processingTime.toFixed(2)}ms`
    );

    const cpuUsage = cpus.map((cpu, index) => {
      const total = Object.values(cpu.times).reduce(
        (acc, time) => acc + time,
        0
      );
      const usage = 100 - (cpu.times.idle / total) * 100;
      return {
        core: index,
        usage: Math.round(usage * 100) / 100,
        model: cpu.model,
        speed: cpu.speed,
      };
    });

    this.cache.set(cacheKey, cpuUsage);
    this.lastCacheTime = now;

    return cpuUsage;
  }
}

// 使用例
const monitor = new PerformanceOptimizedMonitor();

// 連続して呼び出してもキャッシュが効く
console.log('1回目:', monitor.getSystemInfo().timestamp);
console.log('2回目:', monitor.getSystemInfo().timestamp);

// 1秒後に呼び出すと新しいデータが取得される
setTimeout(() => {
  console.log('1秒後:', monitor.getSystemInfo().timestamp);
}, 1100);

セキュリティ上の注意点

システム情報の取得と使用において、セキュリティ上の配慮が必要です。以下に安全な実装方法を示します:

javascriptconst os = require('os');
const crypto = require('crypto');

class SecureSystemInfo {
  constructor() {
    this.sensitiveFields = [
      'hostname',
      'userInfo',
      'networkInterfaces',
    ];
    this.hashSalt = crypto.randomBytes(32).toString('hex');
  }

  // 機密情報をハッシュ化
  hashSensitiveData(data) {
    const hash = crypto.createHash('sha256');
    hash.update(data + this.hashSalt);
    return hash.digest('hex').substring(0, 8);
  }

  // 安全なシステム情報を取得
  getSecureSystemInfo() {
    const rawInfo = {
      platform: os.platform(),
      arch: os.arch(),
      hostname: os.hostname(),
      totalMemory: os.totalmem(),
      freeMemory: os.freemem(),
      cpuCount: os.cpus().length,
      uptime: os.uptime(),
      userInfo: os.userInfo(),
    };

    // 機密情報をマスク
    const secureInfo = {
      platform: rawInfo.platform,
      arch: rawInfo.arch,
      hostname: this.hashSensitiveData(rawInfo.hostname),
      totalMemory: rawInfo.totalMemory,
      freeMemory: rawInfo.freeMemory,
      cpuCount: rawInfo.cpuCount,
      uptime: rawInfo.uptime,
      userInfo: {
        username: this.hashSensitiveData(
          rawInfo.userInfo.username
        ),
        uid: rawInfo.userInfo.uid,
        gid: rawInfo.userInfo.gid,
        // ホームディレクトリとシェルはログに出力しない
        homedir: '[MASKED]',
        shell: '[MASKED]',
      },
    };

    return secureInfo;
  }

  // ログ出力用の安全なフォーマット
  formatForLogging(systemInfo) {
    const allowedFields = [
      'platform',
      'arch',
      'totalMemory',
      'freeMemory',
      'cpuCount',
      'uptime',
    ];

    const logSafeInfo = {};
    allowedFields.forEach((field) => {
      if (systemInfo[field] !== undefined) {
        logSafeInfo[field] = systemInfo[field];
      }
    });

    return logSafeInfo;
  }

  // 外部送信用の最小限情報
  getMinimalSystemInfo() {
    return {
      platform: os.platform(),
      arch: os.arch(),
      nodeVersion: process.version,
      timestamp: new Date().toISOString(),
    };
  }
}

// 使用例
const secureSystem = new SecureSystemInfo();

// 内部使用(機密情報をハッシュ化)
const secureInfo = secureSystem.getSecureSystemInfo();
console.log('セキュアな内部情報:', secureInfo);

// ログ出力用(最小限の情報)
const logInfo = secureSystem.formatForLogging(secureInfo);
console.log('ログ出力用情報:', logInfo);

// 外部送信用(最小限の情報)
const minimalInfo = secureSystem.getMinimalSystemInfo();
console.log('外部送信用情報:', minimalInfo);

まとめ

Node.js の os モジュールは、システム情報を取得するための強力で使いやすいツールです。この記事では、基本的な使い方から実践的な応用例まで、幅広くご紹介しました。

おさらいポイント:

  • os モジュールの基本:Node.js 標準ライブラリで、追加インストール不要
  • クロスプラットフォーム対応:Windows、macOS、Linux で同じコードが動作
  • リアルタイム情報:CPU、メモリ、ネットワークの現在の状態を取得
  • 実践的な活用:システム監視、環境判定、ログ出力で威力を発揮

システム情報の取得は、単なる技術的な作業ではありません。あなたのアプリケーションがどのような環境で動いているかを理解することで、より良いユーザー体験を提供できるのです。

メモリ不足で困っているユーザーがいるとき、CPU 使用率が高くてレスポンスが遅いとき、os モジュールで取得した情報があなたの判断を助けてくれるでしょう。

最後に、心に留めておいてほしいこと: 技術は人のためにあります。os モジュールを使って取得した情報も、最終的にはユーザーの体験を向上させるために使われるべきです。システムの状態を知ることで、問題を早期に発見し、ユーザーが快適にアプリケーションを使えるよう配慮することが、私たち開発者の使命なのです。

ぜひ、この記事で学んだ知識を活用して、素晴らしいアプリケーションを作成してください。皆さんのプロジェクトが成功することを心より願っています。

関連リンク