UNPKG

node-os-utils

Version:

Advanced cross-platform operating system monitoring utilities with TypeScript support

465 lines 17.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DiskMonitor = void 0; const base_monitor_1 = require("../core/base-monitor"); const types_1 = require("../types"); /** * 磁盘监控器 * * 提供磁盘相关的监控功能,包括空间使用、I/O统计、挂载点等 */ class DiskMonitor extends base_monitor_1.BaseMonitor { constructor(adapter, config = {}, cache) { super(adapter, config, cache); this.diskConfig = { ...this.getDefaultConfig(), ...config }; } /** * 获取所有磁盘信息 */ async info() { const cacheKey = 'disk-info'; return this.executeWithCache(cacheKey, async () => { this.validatePlatformSupport('disk.info'); const rawData = await this.adapter.getDiskInfo(); return this.transformDiskInfo(rawData); }, this.diskConfig.cacheTTL || 30000 // 磁盘信息缓存 30 秒 ); } /** * 获取指定磁盘的信息 */ async infoByDevice(device) { const allDisksResult = await this.info(); if (!allDisksResult.success || !allDisksResult.data) { return allDisksResult; } const diskInfo = allDisksResult.data.find(disk => disk.device === device || disk.mountpoint === device); return this.createSuccessResult(diskInfo || null); } /** * 获取磁盘使用情况 */ async usage() { const cacheKey = 'disk-usage'; return this.executeWithCache(cacheKey, async () => { this.validatePlatformSupport('disk.usage'); const rawData = await this.adapter.getDiskUsage(); return this.transformDiskUsage(rawData); }, this.diskConfig.cacheTTL || 10000); } /** * 获取总体磁盘使用率(百分比) */ async overallUsage() { const usageResult = await this.usage(); if (!usageResult.success || !usageResult.data) { return usageResult; } // 计算所有磁盘的加权平均使用率 let totalBytes = 0; let usedBytes = 0; for (const disk of usageResult.data) { if (this.diskConfig.excludeTypes && this.diskConfig.excludeTypes.includes(disk.filesystem)) { continue; } totalBytes += disk.total.toBytes(); usedBytes += disk.used.toBytes(); } const usagePercentage = totalBytes > 0 ? (usedBytes / totalBytes) * 100 : 0; return this.createSuccessResult(Math.round(usagePercentage * 100) / 100); } /** * 获取指定挂载点的使用情况 */ async usageByMountPoint(mountPoint) { const allUsageResult = await this.usage(); if (!allUsageResult.success || !allUsageResult.data) { return allUsageResult; } const usage = allUsageResult.data.find(disk => disk.mountpoint === mountPoint); return this.createSuccessResult(usage || null); } /** * 获取磁盘 I/O 统计 */ async stats() { if (!this.diskConfig.includeStats) { return this.createErrorResult(this.createUnsupportedError('disk.stats (disabled in config)')); } const cacheKey = 'disk-stats'; return this.executeWithCache(cacheKey, async () => { this.validatePlatformSupport('disk.stats'); const rawData = await this.adapter.getDiskStats(); return this.transformDiskStats(rawData); }, this.diskConfig.cacheTTL || 5000); } /** * 获取挂载点信息 */ async mounts() { const cacheKey = 'disk-mounts'; return this.executeWithCache(cacheKey, async () => { this.validatePlatformSupport('disk.mounts'); const rawData = await this.adapter.getMounts(); return this.transformMountPoints(rawData); }, this.diskConfig.cacheTTL || 30000); } /** * 获取文件系统信息 */ async filesystems() { const cacheKey = 'disk-filesystems'; return this.executeWithCache(cacheKey, async () => { this.validatePlatformSupport('disk.filesystems'); const rawData = await this.adapter.getFileSystems(); return this.transformFileSystems(rawData); }, this.diskConfig.cacheTTL || 60000 // 文件系统信息变化较少 ); } /** * 获取磁盘空间总览 */ async spaceOverview() { const cacheKey = 'disk-space-overview'; return this.executeWithCache(cacheKey, async () => { const usageResult = await this.usage(); if (!usageResult.success || !usageResult.data) { throw new Error('Failed to get disk usage data'); } let totalBytes = 0; let usedBytes = 0; let availableBytes = 0; for (const disk of usageResult.data) { if (this.diskConfig.excludeTypes && this.diskConfig.excludeTypes.includes(disk.filesystem)) { continue; } totalBytes += disk.total.toBytes(); usedBytes += disk.used.toBytes(); availableBytes += disk.available.toBytes(); } const usagePercentage = totalBytes > 0 ? (usedBytes / totalBytes) * 100 : 0; return { total: new types_1.DataSize(totalBytes), used: new types_1.DataSize(usedBytes), available: new types_1.DataSize(availableBytes), usagePercentage: Math.round(usagePercentage * 100) / 100, disks: usageResult.data.length }; }, this.diskConfig.cacheTTL || 15000); } /** * 获取磁盘健康状态检查 */ async healthCheck() { const cacheKey = 'disk-health'; return this.executeWithCache(cacheKey, async () => { const issues = []; const checks = { spaceUsage: true, mountStatus: true, ioErrors: true }; // 检查磁盘空间使用率 try { const usageResult = await this.usage(); if (usageResult.success && usageResult.data) { for (const disk of usageResult.data) { if (disk.usagePercentage > 90) { issues.push(`High disk usage on ${disk.mountpoint}: ${disk.usagePercentage.toFixed(1)}%`); checks.spaceUsage = false; } else if (disk.usagePercentage > 80) { issues.push(`Disk usage warning on ${disk.mountpoint}: ${disk.usagePercentage.toFixed(1)}%`); } } } } catch (error) { issues.push('Failed to check disk usage'); checks.spaceUsage = false; } // 检查挂载状态 try { const mountsResult = await this.mounts(); if (mountsResult.success && mountsResult.data) { const readOnlyMounts = mountsResult.data.filter(mount => mount.options.includes('ro') && !mount.mountpoint.startsWith('/proc')); if (readOnlyMounts.length > 0) { issues.push(`Read-only filesystems detected: ${readOnlyMounts.map(m => m.mountpoint).join(', ')}`); checks.mountStatus = false; } } } catch (error) { issues.push('Failed to check mount status'); checks.mountStatus = false; } // 确定整体健康状态 let status = 'healthy'; if (!checks.spaceUsage || !checks.mountStatus || !checks.ioErrors) { status = 'critical'; } else if (issues.length > 0) { status = 'warning'; } return { status, issues, checks }; }, this.diskConfig.cacheTTL || 30000); } /** * 配置是否包含 I/O 统计 */ withStats(include) { this.diskConfig.includeStats = include; return this; } /** * 配置排除的文件系统类型 */ withExcludeTypes(types) { this.diskConfig.excludeTypes = types; return this; } /** * 配置只监控指定的挂载点 */ withMountPoints(mountPoints) { this.diskConfig.mountPoints = mountPoints; return this; } /** * 配置磁盘单位 */ withUnit(unit) { this.diskConfig.unit = unit; return this; } /** * 获取默认配置 */ getDefaultConfig() { return { interval: 5000, timeout: 10000, cacheEnabled: true, cacheTTL: 15000, samples: 1, includeDetails: true, includeStats: false, // I/O 统计可能对性能有影响 excludeTypes: ['proc', 'sysfs', 'devtmpfs', 'tmpfs', 'devpts'], unit: 'GB' }; } // 私有转换方法 /** * 转换磁盘基本信息 */ transformDiskInfo(rawData) { if (!Array.isArray(rawData)) { return []; } return rawData.map(disk => ({ device: disk.device || disk.name || 'unknown', mountpoint: disk.mountPoint || disk.mount || '/', filesystem: disk.filesystem || disk.fs || disk.type || 'unknown', total: new types_1.DataSize(this.safeParseNumber(disk.total || disk.size)), used: new types_1.DataSize(this.safeParseNumber(disk.used)), available: new types_1.DataSize(this.safeParseNumber(disk.available || disk.free)), usagePercentage: this.calculateUsagePercentage(disk), type: this.normalizeDeviceType(disk.type || disk.device), model: disk.model, serial: disk.serial, interface: disk.interface })); } /** * 转换磁盘使用情况 */ transformDiskUsage(rawData) { if (!Array.isArray(rawData)) { return []; } return rawData .filter(disk => this.shouldIncludeDisk(disk)) .map(disk => ({ device: disk.device || disk.filesystem || 'unknown', mountpoint: disk.mountPoint || disk.mount || '/', filesystem: disk.filesystem || disk.fs || disk.type || 'unknown', total: new types_1.DataSize(this.safeParseNumber(disk.total || disk.size)), used: new types_1.DataSize(this.safeParseNumber(disk.used)), available: new types_1.DataSize(this.safeParseNumber(disk.available || disk.free)), usagePercentage: this.calculateUsagePercentage(disk) })); } /** * 转换磁盘 I/O 统计 */ transformDiskStats(rawData) { if (!Array.isArray(rawData)) { return []; } return rawData.map(stats => { const readCount = this.safeParseNumber(stats.reads || stats.read_ios); const writeCount = this.safeParseNumber(stats.writes || stats.write_ios); const readSectors = stats.readSectors ?? stats.read_sectors; const writeSectors = stats.writeSectors ?? stats.write_sectors; const readBytesRaw = stats.readBytes ?? stats.read_bytes; const writeBytesRaw = stats.writeBytes ?? stats.write_bytes; // Linux 适配器默认返回扇区数量,需要在此统一换算为字节;如果已有明确字节值则直接使用 const readSectorsValue = readSectors !== undefined ? this.safeParseNumber(readSectors) : 0; const writeSectorsValue = writeSectors !== undefined ? this.safeParseNumber(writeSectors) : 0; const readBytesValue = readBytesRaw !== undefined && readBytesRaw !== null ? this.safeParseNumber(readBytesRaw) : readSectorsValue * 512; const writeBytesValue = writeBytesRaw !== undefined && writeBytesRaw !== null ? this.safeParseNumber(writeBytesRaw) : writeSectorsValue * 512; return { device: stats.device || 'unknown', readCount, writeCount, readBytes: new types_1.DataSize(readBytesValue), writeBytes: new types_1.DataSize(writeBytesValue), readTime: this.safeParseNumber(stats.readTime || stats.read_ticks), writeTime: this.safeParseNumber(stats.writeTime || stats.write_ticks), ioTime: this.safeParseNumber(stats.ioTime || stats.io_ticks), weightedIOTime: this.safeParseNumber(stats.weightedIOTime || stats.time_in_queue) }; }); } /** * 转换挂载点信息 */ transformMountPoints(rawData) { if (!Array.isArray(rawData)) { return []; } return rawData.map(mount => ({ device: mount.device || mount.source || 'unknown', mountpoint: mount.mountPoint || mount.target || mount.mount || '/', filesystem: mount.filesystem || mount.fstype || mount.type || 'unknown', options: (mount.options || mount.opts || '').toString(), dump: this.safeParseNumber(mount.dump), pass: this.safeParseNumber(mount.pass) })); } /** * 转换文件系统信息 */ transformFileSystems(rawData) { if (!Array.isArray(rawData)) { return []; } return rawData.map(fs => ({ name: fs.name || fs.filesystem || 'unknown', type: fs.type || fs.fstype || 'unknown', description: fs.description || '', supported: fs.supported !== false, features: fs.features || [] })); } /** * 计算使用率百分比 */ calculateUsagePercentage(disk) { const total = this.safeParseNumber(disk.total || disk.size); const used = this.safeParseNumber(disk.used); if (total <= 0) { return 0; } return Math.round((used / total) * 10000) / 100; // 保留两位小数 } /** * 判断是否应该包含该磁盘 */ shouldIncludeDisk(disk) { const filesystem = disk.filesystem || disk.fs || disk.type || ''; // 排除指定的文件系统类型 if (this.diskConfig.excludeTypes && this.diskConfig.excludeTypes.includes(filesystem)) { return false; } // 如果配置了特定挂载点,只包含这些挂载点 if (this.diskConfig.mountPoints && this.diskConfig.mountPoints.length > 0) { // 适配不同来源字段(mountPoint/mountpoint/mount),确保定向监控精确生效 const mountPoint = disk.mountPoint || disk.mountpoint || disk.mount || '/'; return this.diskConfig.mountPoints.includes(mountPoint); } return true; } /** * 规范化设备类型 */ normalizeDeviceType(type) { if (!type) return 'Unknown'; const normalizedType = type.toLowerCase(); if (normalizedType.includes('ssd')) return 'SSD'; if (normalizedType.includes('hdd') || normalizedType.includes('hard')) return 'HDD'; if (normalizedType.includes('nvme')) return 'NVMe'; if (normalizedType.includes('emmc')) return 'eMMC'; return 'Unknown'; } /** * 安全解析数字 */ safeParseNumber(value) { if (typeof value === 'number') { return isNaN(value) ? 0 : value; } if (typeof value === 'string') { const parsed = parseFloat(value); return isNaN(parsed) ? 0 : parsed; } return 0; } // ==================== 向后兼容的同步方法 ==================== /** * 获取指定路径的空闲磁盘空间(同步版本,向后兼容) * @param path 路径(默认为根目录) * @returns 空闲磁盘空间对象或 'not supported' */ free(path = '/') { try { // 对于同步版本,我们无法调用异步的适配器方法 // 这里返回一个基本的结构,实际值需要通过异步方法获取 return { size: 0, // 总大小 used: 0, // 已用空间 available: 0 // 可用空间 }; } catch (error) { return 'not supported'; } } /** * 获取指定路径的已用磁盘空间(同步版本,向后兼容) * @param path 路径(默认为根目录) * @returns 已用磁盘空间对象或 'not supported' */ used(path = '/') { try { // 对于同步版本,我们无法调用异步的适配器方法 // 这里返回一个基本的结构,实际值需要通过异步方法获取 return { size: 0, // 总大小 used: 0, // 已用空间 available: 0 // 可用空间 }; } catch (error) { return 'not supported'; } } } exports.DiskMonitor = DiskMonitor; //# sourceMappingURL=disk-monitor.js.map