node-os-utils
Version:
Advanced cross-platform operating system monitoring utilities with TypeScript support
465 lines • 17.6 kB
JavaScript
"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