@deniscuciuc/redis-analyzer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +244 -0
- package/analyzerrc.example.json +17 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +137 -0
- package/dist/src/analyzers/memory-analyzer.d.ts +5 -0
- package/dist/src/analyzers/memory-analyzer.d.ts.map +1 -0
- package/dist/src/analyzers/memory-analyzer.js +54 -0
- package/dist/src/analyzers/performance-analyzer.d.ts +6 -0
- package/dist/src/analyzers/performance-analyzer.d.ts.map +1 -0
- package/dist/src/analyzers/performance-analyzer.js +78 -0
- package/dist/src/analyzers/persistence-analyzer.d.ts +5 -0
- package/dist/src/analyzers/persistence-analyzer.d.ts.map +1 -0
- package/dist/src/analyzers/persistence-analyzer.js +59 -0
- package/dist/src/analyzers/replication-analyzer.d.ts +5 -0
- package/dist/src/analyzers/replication-analyzer.d.ts.map +1 -0
- package/dist/src/analyzers/replication-analyzer.js +52 -0
- package/dist/src/cli/options.d.ts +24 -0
- package/dist/src/cli/options.d.ts.map +1 -0
- package/dist/src/cli/options.js +155 -0
- package/dist/src/cli/runner.d.ts +13 -0
- package/dist/src/cli/runner.d.ts.map +1 -0
- package/dist/src/cli/runner.js +214 -0
- package/dist/src/collectors/stats-collector.d.ts +15 -0
- package/dist/src/collectors/stats-collector.d.ts.map +1 -0
- package/dist/src/collectors/stats-collector.js +151 -0
- package/dist/src/config/loader.d.ts +13 -0
- package/dist/src/config/loader.d.ts.map +1 -0
- package/dist/src/config/loader.js +63 -0
- package/dist/src/constants.d.ts +52 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +93 -0
- package/dist/src/health.d.ts +10 -0
- package/dist/src/health.d.ts.map +1 -0
- package/dist/src/health.js +100 -0
- package/dist/src/interactive/display.d.ts +13 -0
- package/dist/src/interactive/display.d.ts.map +1 -0
- package/dist/src/interactive/display.js +130 -0
- package/dist/src/interactive/index.d.ts +23 -0
- package/dist/src/interactive/index.d.ts.map +1 -0
- package/dist/src/interactive/index.js +236 -0
- package/dist/src/interactive/menus.d.ts +25 -0
- package/dist/src/interactive/menus.d.ts.map +1 -0
- package/dist/src/interactive/menus.js +49 -0
- package/dist/src/reporters/diff-reporter.d.ts +21 -0
- package/dist/src/reporters/diff-reporter.d.ts.map +1 -0
- package/dist/src/reporters/diff-reporter.js +96 -0
- package/dist/src/reporters/html-reporter.d.ts +9 -0
- package/dist/src/reporters/html-reporter.d.ts.map +1 -0
- package/dist/src/reporters/html-reporter.js +140 -0
- package/dist/src/reporters/report-generator.d.ts +23 -0
- package/dist/src/reporters/report-generator.d.ts.map +1 -0
- package/dist/src/reporters/report-generator.js +239 -0
- package/dist/src/types.d.ts +184 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/utils/format.d.ts +6 -0
- package/dist/src/utils/format.d.ts.map +1 -0
- package/dist/src/utils/format.js +32 -0
- package/dist/src/utils/print.d.ts +8 -0
- package/dist/src/utils/print.d.ts.map +1 -0
- package/dist/src/utils/print.js +42 -0
- package/dist/src/watch/runner.d.ts +8 -0
- package/dist/src/watch/runner.d.ts.map +1 -0
- package/dist/src/watch/runner.js +49 -0
- package/dist/tests/analysis-and-reports.test.d.ts +2 -0
- package/dist/tests/analysis-and-reports.test.d.ts.map +1 -0
- package/dist/tests/analysis-and-reports.test.js +172 -0
- package/dist/tests/collector-and-options.test.d.ts +2 -0
- package/dist/tests/collector-and-options.test.d.ts.map +1 -0
- package/dist/tests/collector-and-options.test.js +110 -0
- package/package.json +82 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StatsCollector = void 0;
|
|
4
|
+
exports.parseSlowLogEntries = parseSlowLogEntries;
|
|
5
|
+
exports.parseRedisInfo = parseRedisInfo;
|
|
6
|
+
function parseSlowLogEntries(entries) {
|
|
7
|
+
return entries.map((entry) => {
|
|
8
|
+
const args = Array.isArray(entry[3]) ? entry[3] : [];
|
|
9
|
+
return {
|
|
10
|
+
id: Number(entry[0]),
|
|
11
|
+
timestamp: Number(entry[1]),
|
|
12
|
+
durationMicros: Number(entry[2]),
|
|
13
|
+
durationMs: Number(entry[2]) / 1000,
|
|
14
|
+
command: args,
|
|
15
|
+
commandPreview: args.slice(0, 3).join(" ").substring(0, 80),
|
|
16
|
+
clientAddr: entry[4]?.toString(),
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function parseRedisInfo(raw) {
|
|
21
|
+
const lines = raw.split("\r\n");
|
|
22
|
+
const map = {};
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
if (line.startsWith("#") || !line.includes(":")) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const [key, ...rest] = line.split(":");
|
|
28
|
+
map[key.trim()] = rest.join(":").trim();
|
|
29
|
+
}
|
|
30
|
+
const keyspaces = [];
|
|
31
|
+
for (const [key, value] of Object.entries(map)) {
|
|
32
|
+
if (!key.startsWith("db")) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const db = Number(key.slice(2));
|
|
36
|
+
if (Number.isNaN(db)) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const parts = {};
|
|
40
|
+
for (const part of value.split(",")) {
|
|
41
|
+
const [partKey, partValue] = part.split("=");
|
|
42
|
+
parts[partKey] = Number(partValue);
|
|
43
|
+
}
|
|
44
|
+
keyspaces.push({
|
|
45
|
+
db,
|
|
46
|
+
keys: parts.keys ?? 0,
|
|
47
|
+
expires: parts.expires ?? 0,
|
|
48
|
+
avgTtl: parts.avg_ttl ?? 0,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const get = (key, fallback = "0") => map[key] ?? fallback;
|
|
52
|
+
const number = (key) => Number(get(key));
|
|
53
|
+
return {
|
|
54
|
+
redisVersion: get("redis_version", "unknown"),
|
|
55
|
+
redisMode: get("redis_mode", "standalone"),
|
|
56
|
+
os: get("os", "unknown"),
|
|
57
|
+
uptimeInSeconds: number("uptime_in_seconds"),
|
|
58
|
+
uptimeInDays: number("uptime_in_days"),
|
|
59
|
+
tcpPort: number("tcp_port"),
|
|
60
|
+
executablePath: get("executable"),
|
|
61
|
+
configFile: get("config_file"),
|
|
62
|
+
connectedClients: number("connected_clients"),
|
|
63
|
+
blockedClients: number("blocked_clients"),
|
|
64
|
+
maxClients: number("maxclients"),
|
|
65
|
+
clientRecentMaxInputBuffer: number("client_recent_max_input_buffer"),
|
|
66
|
+
clientRecentMaxOutputBuffer: number("client_recent_max_output_buffer"),
|
|
67
|
+
usedMemory: number("used_memory"),
|
|
68
|
+
usedMemoryHuman: get("used_memory_human"),
|
|
69
|
+
usedMemoryRss: number("used_memory_rss"),
|
|
70
|
+
usedMemoryRssHuman: get("used_memory_rss_human"),
|
|
71
|
+
usedMemoryPeak: number("used_memory_peak"),
|
|
72
|
+
usedMemoryPeakHuman: get("used_memory_peak_human"),
|
|
73
|
+
usedMemoryPeakPerc: Number(get("used_memory_peak_perc", "0").replace("%", "")),
|
|
74
|
+
usedMemoryOverhead: number("used_memory_overhead"),
|
|
75
|
+
usedMemoryDataset: number("used_memory_dataset"),
|
|
76
|
+
memFragmentationRatio: Number(get("mem_fragmentation_ratio", "0")),
|
|
77
|
+
memFragmentationBytes: number("mem_fragmentation_bytes"),
|
|
78
|
+
maxmemory: number("maxmemory"),
|
|
79
|
+
maxmemoryHuman: get("maxmemory_human"),
|
|
80
|
+
maxmemoryPolicy: get("maxmemory_policy", "noeviction"),
|
|
81
|
+
totalCommandsProcessed: number("total_commands_processed"),
|
|
82
|
+
instantaneousOpsPerSec: number("instantaneous_ops_per_sec"),
|
|
83
|
+
totalNetInputBytes: number("total_net_input_bytes"),
|
|
84
|
+
totalNetOutputBytes: number("total_net_output_bytes"),
|
|
85
|
+
rejectedConnections: number("rejected_connections"),
|
|
86
|
+
expiredKeys: number("expired_keys"),
|
|
87
|
+
evictedKeys: number("evicted_keys"),
|
|
88
|
+
keyspaceHits: number("keyspace_hits"),
|
|
89
|
+
keyspaceMisses: number("keyspace_misses"),
|
|
90
|
+
role: get("role", "master"),
|
|
91
|
+
connectedSlaves: number("connected_slaves"),
|
|
92
|
+
masterLinkStatus: map.master_link_status,
|
|
93
|
+
masterLastIoSecondsAgo: map.master_last_io_seconds_ago
|
|
94
|
+
? number("master_last_io_seconds_ago")
|
|
95
|
+
: undefined,
|
|
96
|
+
masterSyncInProgress: map.master_sync_in_progress
|
|
97
|
+
? get("master_sync_in_progress") === "1"
|
|
98
|
+
: undefined,
|
|
99
|
+
masterReplOffset: map.master_repl_offset
|
|
100
|
+
? number("master_repl_offset")
|
|
101
|
+
: undefined,
|
|
102
|
+
slaveReplOffset: map.slave_repl_offset
|
|
103
|
+
? number("slave_repl_offset")
|
|
104
|
+
: undefined,
|
|
105
|
+
rdbChangesSinceLastSave: number("rdb_changes_since_last_save"),
|
|
106
|
+
rdbBgsaveInProgress: get("rdb_bgsave_in_progress") === "1",
|
|
107
|
+
rdbLastSaveTime: number("rdb_last_save_time"),
|
|
108
|
+
rdbLastBgsaveStatus: get("rdb_last_bgsave_status", "ok"),
|
|
109
|
+
rdbLastBgsaveTimeSec: number("rdb_last_bgsave_time_sec"),
|
|
110
|
+
aofEnabled: get("aof_enabled") === "1",
|
|
111
|
+
aofRewriteInProgress: get("aof_rewrite_in_progress") === "1",
|
|
112
|
+
aofLastRewriteTimeSec: number("aof_last_rewrite_time_sec"),
|
|
113
|
+
aofLastBgrewriteStatus: get("aof_last_bgrewrite_status", "ok"),
|
|
114
|
+
aofCurrentSize: map.aof_current_size
|
|
115
|
+
? number("aof_current_size")
|
|
116
|
+
: undefined,
|
|
117
|
+
keyspaces,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
class StatsCollector {
|
|
121
|
+
client;
|
|
122
|
+
constructor(client) {
|
|
123
|
+
this.client = client;
|
|
124
|
+
}
|
|
125
|
+
async getInfo() {
|
|
126
|
+
return parseRedisInfo(await this.client.info("all"));
|
|
127
|
+
}
|
|
128
|
+
async getSlowLog(count) {
|
|
129
|
+
const raw = (await this.client.slowlog("GET", count));
|
|
130
|
+
return parseSlowLogEntries(raw);
|
|
131
|
+
}
|
|
132
|
+
async getSlowLogLength() {
|
|
133
|
+
const raw = await this.client.slowlog("LEN");
|
|
134
|
+
return Number(raw);
|
|
135
|
+
}
|
|
136
|
+
async getConfigValues(keys) {
|
|
137
|
+
const config = {};
|
|
138
|
+
for (const key of keys) {
|
|
139
|
+
const raw = (await this.client.config("GET", key));
|
|
140
|
+
for (let index = 0; index < raw.length; index += 2) {
|
|
141
|
+
const configKey = raw[index];
|
|
142
|
+
const value = raw[index + 1];
|
|
143
|
+
if (configKey && value !== undefined) {
|
|
144
|
+
config[configKey] = value;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return config;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.StatsCollector = StatsCollector;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RedisConnection } from "../types";
|
|
2
|
+
export type ProfileConfig = Partial<RedisConnection>;
|
|
3
|
+
export interface AnalyzerConfig {
|
|
4
|
+
profiles?: Record<string, ProfileConfig>;
|
|
5
|
+
defaultProfile?: string;
|
|
6
|
+
slowCommandThreshold?: number;
|
|
7
|
+
maxSlowCommands?: number;
|
|
8
|
+
output?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function loadConfig(configPath?: string): AnalyzerConfig;
|
|
11
|
+
export declare function resolveProfile(config: AnalyzerConfig, profileName?: string): ProfileConfig;
|
|
12
|
+
export declare function listProfiles(config: AnalyzerConfig): string[];
|
|
13
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;AAErD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,cAAc,CAsC9D;AAED,wBAAgB,cAAc,CAC7B,MAAM,EAAE,cAAc,EACtB,WAAW,CAAC,EAAE,MAAM,GAClB,aAAa,CAsBf;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,EAAE,CAE7D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadConfig = loadConfig;
|
|
4
|
+
exports.resolveProfile = resolveProfile;
|
|
5
|
+
exports.listProfiles = listProfiles;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_os_1 = require("node:os");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
function parseConfig(candidate) {
|
|
10
|
+
return JSON.parse((0, node_fs_1.readFileSync)(candidate, "utf-8"));
|
|
11
|
+
}
|
|
12
|
+
function loadConfig(configPath) {
|
|
13
|
+
if (configPath) {
|
|
14
|
+
const explicitPath = (0, node_path_1.resolve)(configPath);
|
|
15
|
+
if (!(0, node_fs_1.existsSync)(explicitPath)) {
|
|
16
|
+
throw new Error(`Config file not found: ${explicitPath}`);
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return parseConfig(explicitPath);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
23
|
+
throw new Error(`Could not parse config file at ${explicitPath}: ${message}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const candidates = [
|
|
27
|
+
(0, node_path_1.join)(process.cwd(), ".analyzerrc.json"),
|
|
28
|
+
(0, node_path_1.join)((0, node_os_1.homedir)(), ".config", "db-analyzer", "config.json"),
|
|
29
|
+
];
|
|
30
|
+
for (const candidate of candidates) {
|
|
31
|
+
if (!(0, node_fs_1.existsSync)(candidate)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return parseConfig(candidate);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
39
|
+
console.warn(`Warning: could not parse config file at ${candidate}: ${message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
function resolveProfile(config, profileName) {
|
|
45
|
+
if (!config.profiles) {
|
|
46
|
+
if (profileName) {
|
|
47
|
+
throw new Error(`Profile "${profileName}" was requested, but no profiles were found in the config file.`);
|
|
48
|
+
}
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
const name = profileName ?? config.defaultProfile;
|
|
52
|
+
if (!name) {
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
const profile = config.profiles[name];
|
|
56
|
+
if (!profile) {
|
|
57
|
+
throw new Error(`Profile "${name}" not found in config file.`);
|
|
58
|
+
}
|
|
59
|
+
return profile;
|
|
60
|
+
}
|
|
61
|
+
function listProfiles(config) {
|
|
62
|
+
return Object.keys(config.profiles ?? {});
|
|
63
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare const COMMANDS: readonly ["full", "health", "server-info", "memory", "hit-rate", "slow-commands", "keys", "connections", "persistence", "replication", "config"];
|
|
2
|
+
export type Command = (typeof COMMANDS)[number];
|
|
3
|
+
export declare const WATCH_ALLOWED: Set<"full" | "health" | "server-info" | "memory" | "hit-rate" | "slow-commands" | "keys" | "connections" | "persistence" | "replication" | "config">;
|
|
4
|
+
export declare const WATCH_BLOCKED: Set<"full" | "health" | "server-info" | "memory" | "hit-rate" | "slow-commands" | "keys" | "connections" | "persistence" | "replication" | "config">;
|
|
5
|
+
export declare const FULL_ANALYSIS_COMMANDS: Command[];
|
|
6
|
+
export declare const THRESHOLDS: {
|
|
7
|
+
readonly memory: {
|
|
8
|
+
readonly usageWarning: 70;
|
|
9
|
+
readonly usageCritical: 90;
|
|
10
|
+
readonly fragWarning: 1.5;
|
|
11
|
+
readonly fragCritical: 2;
|
|
12
|
+
};
|
|
13
|
+
readonly hitRate: {
|
|
14
|
+
readonly warning: 90;
|
|
15
|
+
readonly critical: 80;
|
|
16
|
+
};
|
|
17
|
+
readonly replication: {
|
|
18
|
+
readonly lagWarning: 10;
|
|
19
|
+
readonly lagCritical: 60;
|
|
20
|
+
};
|
|
21
|
+
readonly persistence: {
|
|
22
|
+
readonly rdbStaleHours: 24;
|
|
23
|
+
};
|
|
24
|
+
readonly slowCommand: {
|
|
25
|
+
readonly defaultThresholdMicros: 10000;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export declare const SCORE_DEDUCTIONS: {
|
|
29
|
+
readonly memoryUsageCritical: 20;
|
|
30
|
+
readonly memoryUsageWarning: 10;
|
|
31
|
+
readonly highFragmentation: 15;
|
|
32
|
+
readonly lowHitRate: 20;
|
|
33
|
+
readonly veryLowHitRate: 10;
|
|
34
|
+
readonly linkDown: 25;
|
|
35
|
+
readonly highReplicationLag: 15;
|
|
36
|
+
readonly rdbFailed: 20;
|
|
37
|
+
readonly aofFailed: 20;
|
|
38
|
+
readonly stalePersistence: 10;
|
|
39
|
+
readonly highEviction: 10;
|
|
40
|
+
readonly rejectedConnections: 15;
|
|
41
|
+
};
|
|
42
|
+
export declare const DEFAULTS: {
|
|
43
|
+
readonly host: "localhost";
|
|
44
|
+
readonly port: 6379;
|
|
45
|
+
readonly db: 0;
|
|
46
|
+
readonly slowCommandThreshold: 10000;
|
|
47
|
+
readonly maxSlowCommands: 25;
|
|
48
|
+
readonly output: "./reports";
|
|
49
|
+
readonly watchInterval: 30;
|
|
50
|
+
};
|
|
51
|
+
export declare const IMPORTANT_CONFIG_KEYS: readonly ["maxmemory", "maxmemory-policy", "appendonly", "appendfsync", "save", "timeout", "tcp-keepalive", "slowlog-log-slower-than", "slowlog-max-len", "databases"];
|
|
52
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,kJAYX,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhD,eAAO,MAAM,aAAa,sJAOxB,CAAC;AAEH,eAAO,MAAM,aAAa,sJAAuB,CAAC;AAElD,eAAO,MAAM,sBAAsB,EAAE,OAAO,EAU3C,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CAqBb,CAAC;AAEX,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAanB,CAAC;AAEX,eAAO,MAAM,QAAQ;;;;;;;;CAQX,CAAC;AAEX,eAAO,MAAM,qBAAqB,wKAWxB,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IMPORTANT_CONFIG_KEYS = exports.DEFAULTS = exports.SCORE_DEDUCTIONS = exports.THRESHOLDS = exports.FULL_ANALYSIS_COMMANDS = exports.WATCH_BLOCKED = exports.WATCH_ALLOWED = exports.COMMANDS = void 0;
|
|
4
|
+
exports.COMMANDS = [
|
|
5
|
+
"full",
|
|
6
|
+
"health",
|
|
7
|
+
"server-info",
|
|
8
|
+
"memory",
|
|
9
|
+
"hit-rate",
|
|
10
|
+
"slow-commands",
|
|
11
|
+
"keys",
|
|
12
|
+
"connections",
|
|
13
|
+
"persistence",
|
|
14
|
+
"replication",
|
|
15
|
+
"config",
|
|
16
|
+
];
|
|
17
|
+
exports.WATCH_ALLOWED = new Set([
|
|
18
|
+
"health",
|
|
19
|
+
"connections",
|
|
20
|
+
"hit-rate",
|
|
21
|
+
"slow-commands",
|
|
22
|
+
"keys",
|
|
23
|
+
"replication",
|
|
24
|
+
]);
|
|
25
|
+
exports.WATCH_BLOCKED = new Set([]);
|
|
26
|
+
exports.FULL_ANALYSIS_COMMANDS = [
|
|
27
|
+
"health",
|
|
28
|
+
"memory",
|
|
29
|
+
"hit-rate",
|
|
30
|
+
"slow-commands",
|
|
31
|
+
"keys",
|
|
32
|
+
"connections",
|
|
33
|
+
"persistence",
|
|
34
|
+
"replication",
|
|
35
|
+
"config",
|
|
36
|
+
];
|
|
37
|
+
exports.THRESHOLDS = {
|
|
38
|
+
memory: {
|
|
39
|
+
usageWarning: 70,
|
|
40
|
+
usageCritical: 90,
|
|
41
|
+
fragWarning: 1.5,
|
|
42
|
+
fragCritical: 2.0,
|
|
43
|
+
},
|
|
44
|
+
hitRate: {
|
|
45
|
+
warning: 90,
|
|
46
|
+
critical: 80,
|
|
47
|
+
},
|
|
48
|
+
replication: {
|
|
49
|
+
lagWarning: 10,
|
|
50
|
+
lagCritical: 60,
|
|
51
|
+
},
|
|
52
|
+
persistence: {
|
|
53
|
+
rdbStaleHours: 24,
|
|
54
|
+
},
|
|
55
|
+
slowCommand: {
|
|
56
|
+
defaultThresholdMicros: 10_000,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
exports.SCORE_DEDUCTIONS = {
|
|
60
|
+
memoryUsageCritical: 20,
|
|
61
|
+
memoryUsageWarning: 10,
|
|
62
|
+
highFragmentation: 15,
|
|
63
|
+
lowHitRate: 20,
|
|
64
|
+
veryLowHitRate: 10,
|
|
65
|
+
linkDown: 25,
|
|
66
|
+
highReplicationLag: 15,
|
|
67
|
+
rdbFailed: 20,
|
|
68
|
+
aofFailed: 20,
|
|
69
|
+
stalePersistence: 10,
|
|
70
|
+
highEviction: 10,
|
|
71
|
+
rejectedConnections: 15,
|
|
72
|
+
};
|
|
73
|
+
exports.DEFAULTS = {
|
|
74
|
+
host: "localhost",
|
|
75
|
+
port: 6379,
|
|
76
|
+
db: 0,
|
|
77
|
+
slowCommandThreshold: 10_000,
|
|
78
|
+
maxSlowCommands: 25,
|
|
79
|
+
output: "./reports",
|
|
80
|
+
watchInterval: 30,
|
|
81
|
+
};
|
|
82
|
+
exports.IMPORTANT_CONFIG_KEYS = [
|
|
83
|
+
"maxmemory",
|
|
84
|
+
"maxmemory-policy",
|
|
85
|
+
"appendonly",
|
|
86
|
+
"appendfsync",
|
|
87
|
+
"save",
|
|
88
|
+
"timeout",
|
|
89
|
+
"tcp-keepalive",
|
|
90
|
+
"slowlog-log-slower-than",
|
|
91
|
+
"slowlog-max-len",
|
|
92
|
+
"databases",
|
|
93
|
+
];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FullRedisReport, HitRateAnalysis, MemoryAnalysis, PersistenceAnalysis, Recommendation, RedisMetrics, ReplicationAnalysis } from "./types";
|
|
2
|
+
export declare function computeHealthScore(report: Omit<FullRedisReport, "healthScore" | "recommendations">): number;
|
|
3
|
+
export declare function buildRecommendations(input: {
|
|
4
|
+
memory: MemoryAnalysis;
|
|
5
|
+
hitRate: HitRateAnalysis;
|
|
6
|
+
persistence: PersistenceAnalysis;
|
|
7
|
+
replication: ReplicationAnalysis;
|
|
8
|
+
metrics: RedisMetrics;
|
|
9
|
+
}): Recommendation[];
|
|
10
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/health.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,eAAe,EACf,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,MAAM,SAAS,CAAC;AASjB,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,GAAG,iBAAiB,CAAC,GAC9D,MAAM,CA+CR;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,mBAAmB,CAAC;IACjC,WAAW,EAAE,mBAAmB,CAAC;IACjC,OAAO,EAAE,YAAY,CAAC;CACtB,GAAG,cAAc,EAAE,CAiEnB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeHealthScore = computeHealthScore;
|
|
4
|
+
exports.buildRecommendations = buildRecommendations;
|
|
5
|
+
const constants_1 = require("./constants");
|
|
6
|
+
const PRIORITY_ORDER = {
|
|
7
|
+
critical: 0,
|
|
8
|
+
high: 1,
|
|
9
|
+
medium: 2,
|
|
10
|
+
low: 3,
|
|
11
|
+
};
|
|
12
|
+
function computeHealthScore(report) {
|
|
13
|
+
let score = 100;
|
|
14
|
+
const { memory, hitRate, persistence, replication } = report;
|
|
15
|
+
if (memory.maxMemory > 0) {
|
|
16
|
+
if (memory.usagePercent >= constants_1.THRESHOLDS.memory.usageCritical) {
|
|
17
|
+
score -= constants_1.SCORE_DEDUCTIONS.memoryUsageCritical;
|
|
18
|
+
}
|
|
19
|
+
else if (memory.usagePercent >= constants_1.THRESHOLDS.memory.usageWarning) {
|
|
20
|
+
score -= constants_1.SCORE_DEDUCTIONS.memoryUsageWarning;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (memory.fragSeverity === "critical") {
|
|
24
|
+
score -= constants_1.SCORE_DEDUCTIONS.highFragmentation;
|
|
25
|
+
}
|
|
26
|
+
if (hitRate.hitRate < constants_1.THRESHOLDS.hitRate.critical) {
|
|
27
|
+
score -= constants_1.SCORE_DEDUCTIONS.lowHitRate + constants_1.SCORE_DEDUCTIONS.veryLowHitRate;
|
|
28
|
+
}
|
|
29
|
+
else if (hitRate.hitRate < constants_1.THRESHOLDS.hitRate.warning) {
|
|
30
|
+
score -= constants_1.SCORE_DEDUCTIONS.lowHitRate;
|
|
31
|
+
}
|
|
32
|
+
if (hitRate.evictedKeys > 1000) {
|
|
33
|
+
score -= constants_1.SCORE_DEDUCTIONS.highEviction;
|
|
34
|
+
}
|
|
35
|
+
if (persistence.rdb.lastStatus === "err") {
|
|
36
|
+
score -= constants_1.SCORE_DEDUCTIONS.rdbFailed;
|
|
37
|
+
}
|
|
38
|
+
if (persistence.aof.enabled && persistence.aof.lastStatus === "err") {
|
|
39
|
+
score -= constants_1.SCORE_DEDUCTIONS.aofFailed;
|
|
40
|
+
}
|
|
41
|
+
if (persistence.severity === "warning") {
|
|
42
|
+
score -= constants_1.SCORE_DEDUCTIONS.stalePersistence;
|
|
43
|
+
}
|
|
44
|
+
if (replication.linkStatus === "down") {
|
|
45
|
+
score -= constants_1.SCORE_DEDUCTIONS.linkDown;
|
|
46
|
+
}
|
|
47
|
+
else if (replication.severity === "warning") {
|
|
48
|
+
score -= constants_1.SCORE_DEDUCTIONS.highReplicationLag;
|
|
49
|
+
}
|
|
50
|
+
if (report.metrics.rejectedConnections > 0) {
|
|
51
|
+
score -= constants_1.SCORE_DEDUCTIONS.rejectedConnections;
|
|
52
|
+
}
|
|
53
|
+
return Math.max(0, score);
|
|
54
|
+
}
|
|
55
|
+
function buildRecommendations(input) {
|
|
56
|
+
const recommendations = [];
|
|
57
|
+
recommendations.push(...toRecommendations("memory", input.memory.fragSeverity === "critical"
|
|
58
|
+
? "critical"
|
|
59
|
+
: input.memory.fragSeverity === "warning" ||
|
|
60
|
+
input.memory.usagePercent >= constants_1.THRESHOLDS.memory.usageWarning
|
|
61
|
+
? "high"
|
|
62
|
+
: "low", input.memory.recommendations));
|
|
63
|
+
recommendations.push(...toRecommendations("hit-rate", input.hitRate.hitRate < constants_1.THRESHOLDS.hitRate.critical
|
|
64
|
+
? "critical"
|
|
65
|
+
: input.hitRate.hitRate < constants_1.THRESHOLDS.hitRate.warning ||
|
|
66
|
+
input.hitRate.evictedKeys > 0
|
|
67
|
+
? "high"
|
|
68
|
+
: "low", input.hitRate.recommendations));
|
|
69
|
+
recommendations.push(...toRecommendations("persistence", mapSeverity(input.persistence.severity), input.persistence.recommendations));
|
|
70
|
+
recommendations.push(...toRecommendations("replication", mapSeverity(input.replication.severity), input.replication.recommendations));
|
|
71
|
+
if (input.metrics.rejectedConnections > 0) {
|
|
72
|
+
recommendations.push({
|
|
73
|
+
priority: "high",
|
|
74
|
+
category: "connections",
|
|
75
|
+
message: `${input.metrics.rejectedConnections.toLocaleString()} rejected connections detected.`,
|
|
76
|
+
action: "Raise maxclients, inspect client churn, or add connection pooling.",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (input.metrics.blockedClients > 0) {
|
|
80
|
+
recommendations.push({
|
|
81
|
+
priority: "medium",
|
|
82
|
+
category: "connections",
|
|
83
|
+
message: `${input.metrics.blockedClients.toLocaleString()} blocked clients detected.`,
|
|
84
|
+
action: "Inspect blocking Lua scripts, transactions, or slow commands.",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return recommendations.sort((left, right) => PRIORITY_ORDER[left.priority] - PRIORITY_ORDER[right.priority]);
|
|
88
|
+
}
|
|
89
|
+
function toRecommendations(category, priority, items) {
|
|
90
|
+
return items.map((message) => ({ priority, category, message }));
|
|
91
|
+
}
|
|
92
|
+
function mapSeverity(severity) {
|
|
93
|
+
if (severity === "critical") {
|
|
94
|
+
return "critical";
|
|
95
|
+
}
|
|
96
|
+
if (severity === "warning") {
|
|
97
|
+
return "high";
|
|
98
|
+
}
|
|
99
|
+
return "low";
|
|
100
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FullRedisReport, HitRateAnalysis, KeyspaceInfo, MemoryAnalysis, PersistenceAnalysis, RedisInfo, ReplicationAnalysis, SlowCommandAnalysis } from "../types";
|
|
2
|
+
export declare function showFullReport(report: FullRedisReport): void;
|
|
3
|
+
export declare function showHealth(report: FullRedisReport): void;
|
|
4
|
+
export declare function showServerInfo(info: RedisInfo): void;
|
|
5
|
+
export declare function showMemory(analysis: MemoryAnalysis): void;
|
|
6
|
+
export declare function showHitRate(analysis: HitRateAnalysis): void;
|
|
7
|
+
export declare function showSlowCommands(analysis: SlowCommandAnalysis): void;
|
|
8
|
+
export declare function showKeyspaces(keyspaces: KeyspaceInfo[]): void;
|
|
9
|
+
export declare function showConnections(info: RedisInfo): void;
|
|
10
|
+
export declare function showPersistence(analysis: PersistenceAnalysis): void;
|
|
11
|
+
export declare function showReplication(analysis: ReplicationAnalysis): void;
|
|
12
|
+
export declare function showConfig(config: Record<string, string>): void;
|
|
13
|
+
//# sourceMappingURL=display.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../../src/interactive/display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,eAAe,EACf,eAAe,EACf,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,MAAM,UAAU,CAAC;AAiBlB,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAY5D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAWxD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAQpD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAWzD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAW3D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAWpE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,CAa7D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAQrD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAanE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAUnE;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAK/D"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.showFullReport = showFullReport;
|
|
4
|
+
exports.showHealth = showHealth;
|
|
5
|
+
exports.showServerInfo = showServerInfo;
|
|
6
|
+
exports.showMemory = showMemory;
|
|
7
|
+
exports.showHitRate = showHitRate;
|
|
8
|
+
exports.showSlowCommands = showSlowCommands;
|
|
9
|
+
exports.showKeyspaces = showKeyspaces;
|
|
10
|
+
exports.showConnections = showConnections;
|
|
11
|
+
exports.showPersistence = showPersistence;
|
|
12
|
+
exports.showReplication = showReplication;
|
|
13
|
+
exports.showConfig = showConfig;
|
|
14
|
+
const format_1 = require("../utils/format");
|
|
15
|
+
const print_1 = require("../utils/print");
|
|
16
|
+
function showFullReport(report) {
|
|
17
|
+
showHealth(report);
|
|
18
|
+
(0, print_1.printSeparator)();
|
|
19
|
+
showMemory(report.memory);
|
|
20
|
+
(0, print_1.printSeparator)();
|
|
21
|
+
showHitRate(report.hitRate);
|
|
22
|
+
(0, print_1.printSeparator)();
|
|
23
|
+
showPersistence(report.persistence);
|
|
24
|
+
(0, print_1.printSeparator)();
|
|
25
|
+
showReplication(report.replication);
|
|
26
|
+
(0, print_1.printSeparator)();
|
|
27
|
+
showSlowCommands(report.slowCommands);
|
|
28
|
+
}
|
|
29
|
+
function showHealth(report) {
|
|
30
|
+
(0, print_1.printSection)("Health");
|
|
31
|
+
(0, print_1.printRow)("Health score", `${report.healthScore}/100 ${(0, print_1.healthEmoji)(report.healthScore)} ${(0, print_1.healthLabel)(report.healthScore)}`);
|
|
32
|
+
(0, print_1.printRow)("Redis version", report.metrics.version);
|
|
33
|
+
(0, print_1.printRow)("Mode", report.metrics.mode);
|
|
34
|
+
(0, print_1.printRow)("Used memory", report.memory.usedMemoryHuman);
|
|
35
|
+
(0, print_1.printRow)("Hit rate", (0, format_1.formatPercent)(report.hitRate.hitRate));
|
|
36
|
+
(0, print_1.printRow)("Ops / sec", (0, format_1.formatNumber)(report.metrics.opsPerSec));
|
|
37
|
+
}
|
|
38
|
+
function showServerInfo(info) {
|
|
39
|
+
(0, print_1.printSection)("Server Info");
|
|
40
|
+
(0, print_1.printRow)("Version", info.redisVersion);
|
|
41
|
+
(0, print_1.printRow)("Mode", info.redisMode);
|
|
42
|
+
(0, print_1.printRow)("OS", info.os);
|
|
43
|
+
(0, print_1.printRow)("Uptime", `${info.uptimeInDays} days`);
|
|
44
|
+
(0, print_1.printRow)("Port", info.tcpPort);
|
|
45
|
+
(0, print_1.printRow)("Config file", info.configFile || "n/a");
|
|
46
|
+
}
|
|
47
|
+
function showMemory(analysis) {
|
|
48
|
+
(0, print_1.printSection)("Memory");
|
|
49
|
+
(0, print_1.printRow)("Used", analysis.usedMemoryHuman);
|
|
50
|
+
(0, print_1.printRow)("Max", analysis.maxMemoryHuman || "unlimited");
|
|
51
|
+
(0, print_1.printRow)("Usage", (0, format_1.formatPercent)(analysis.usagePercent));
|
|
52
|
+
(0, print_1.printRow)("Fragmentation", analysis.fragRatio.toFixed(2));
|
|
53
|
+
(0, print_1.printRow)("Fragmentation waste", (0, format_1.formatBytes)(analysis.fragBytes));
|
|
54
|
+
(0, print_1.printRow)("RSS overhead", (0, format_1.formatBytes)(analysis.rssOverhead));
|
|
55
|
+
for (const recommendation of analysis.recommendations) {
|
|
56
|
+
(0, print_1.printBullet)(recommendation);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function showHitRate(analysis) {
|
|
60
|
+
(0, print_1.printSection)("Hit Rate");
|
|
61
|
+
(0, print_1.printRow)("Hits", (0, format_1.formatNumber)(analysis.hits));
|
|
62
|
+
(0, print_1.printRow)("Misses", (0, format_1.formatNumber)(analysis.misses));
|
|
63
|
+
(0, print_1.printRow)("Hit rate", (0, format_1.formatPercent)(analysis.hitRate));
|
|
64
|
+
(0, print_1.printRow)("Evicted keys", (0, format_1.formatNumber)(analysis.evictedKeys));
|
|
65
|
+
(0, print_1.printRow)("Expired keys", (0, format_1.formatNumber)(analysis.expiredKeys));
|
|
66
|
+
(0, print_1.printRow)("Policy", analysis.evictionPolicy);
|
|
67
|
+
for (const recommendation of analysis.recommendations) {
|
|
68
|
+
(0, print_1.printBullet)(recommendation);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function showSlowCommands(analysis) {
|
|
72
|
+
(0, print_1.printSection)("Slow Commands");
|
|
73
|
+
(0, print_1.printRow)("Logged entries", (0, format_1.formatNumber)(analysis.totalLogged));
|
|
74
|
+
(0, print_1.printRow)("Threshold", (0, format_1.formatDuration)(analysis.threshold / 1000));
|
|
75
|
+
for (const command of analysis.topCommandTypes) {
|
|
76
|
+
(0, print_1.printBullet)(`${command.command} — ${(0, format_1.formatNumber)(command.count)} entries`);
|
|
77
|
+
(0, print_1.printSubBullet)(`Average duration: ${(0, format_1.formatDuration)(command.avgMs)}`);
|
|
78
|
+
}
|
|
79
|
+
for (const recommendation of analysis.recommendations) {
|
|
80
|
+
(0, print_1.printBullet)(recommendation);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function showKeyspaces(keyspaces) {
|
|
84
|
+
(0, print_1.printSection)("Keyspaces");
|
|
85
|
+
if (keyspaces.length === 0) {
|
|
86
|
+
console.log(" No keys found.");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
for (const keyspace of keyspaces) {
|
|
90
|
+
(0, print_1.printBullet)(`db${keyspace.db} — ${(0, format_1.formatNumber)(keyspace.keys)} keys`);
|
|
91
|
+
(0, print_1.printSubBullet)(`Expiring: ${(0, format_1.formatNumber)(keyspace.expires)} | Avg TTL: ${(0, format_1.formatDuration)(keyspace.avgTtl)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function showConnections(info) {
|
|
95
|
+
(0, print_1.printSection)("Connections");
|
|
96
|
+
(0, print_1.printRow)("Connected clients", (0, format_1.formatNumber)(info.connectedClients));
|
|
97
|
+
(0, print_1.printRow)("Blocked clients", (0, format_1.formatNumber)(info.blockedClients));
|
|
98
|
+
(0, print_1.printRow)("Max clients", (0, format_1.formatNumber)(info.maxClients));
|
|
99
|
+
(0, print_1.printRow)("Rejected connections", (0, format_1.formatNumber)(info.rejectedConnections));
|
|
100
|
+
(0, print_1.printRow)("Max input buffer", (0, format_1.formatBytes)(info.clientRecentMaxInputBuffer));
|
|
101
|
+
(0, print_1.printRow)("Max output buffer", (0, format_1.formatBytes)(info.clientRecentMaxOutputBuffer));
|
|
102
|
+
}
|
|
103
|
+
function showPersistence(analysis) {
|
|
104
|
+
(0, print_1.printSection)("Persistence");
|
|
105
|
+
(0, print_1.printRow)("RDB enabled", analysis.rdb.enabled ? "yes" : "no");
|
|
106
|
+
(0, print_1.printRow)("RDB last status", analysis.rdb.lastStatus);
|
|
107
|
+
(0, print_1.printRow)("Seconds since save", (0, format_1.formatNumber)(analysis.rdb.secondsSinceLastSave));
|
|
108
|
+
(0, print_1.printRow)("AOF enabled", analysis.aof.enabled ? "yes" : "no");
|
|
109
|
+
(0, print_1.printRow)("AOF last status", analysis.aof.lastStatus);
|
|
110
|
+
for (const recommendation of analysis.recommendations) {
|
|
111
|
+
(0, print_1.printBullet)(recommendation);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function showReplication(analysis) {
|
|
115
|
+
(0, print_1.printSection)("Replication");
|
|
116
|
+
(0, print_1.printRow)("Role", analysis.role);
|
|
117
|
+
(0, print_1.printRow)("Connected replicas", (0, format_1.formatNumber)(analysis.connectedSlaves));
|
|
118
|
+
(0, print_1.printRow)("Link status", analysis.linkStatus ?? "n/a");
|
|
119
|
+
(0, print_1.printRow)("Lag seconds", analysis.lagSeconds ?? "n/a");
|
|
120
|
+
(0, print_1.printRow)("Sync in progress", analysis.syncInProgress ? "yes" : "no");
|
|
121
|
+
for (const recommendation of analysis.recommendations) {
|
|
122
|
+
(0, print_1.printBullet)(recommendation);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function showConfig(config) {
|
|
126
|
+
(0, print_1.printSection)("Configuration");
|
|
127
|
+
for (const [key, value] of Object.entries(config)) {
|
|
128
|
+
(0, print_1.printRow)(key, value);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Redis } from "ioredis";
|
|
2
|
+
import type { ParsedOptions } from "../cli/options";
|
|
3
|
+
import type { RedisConnection } from "../types";
|
|
4
|
+
export declare class InteractiveCLI {
|
|
5
|
+
private readonly client;
|
|
6
|
+
private readonly connection;
|
|
7
|
+
private readonly runtimeOptions;
|
|
8
|
+
private readonly collector;
|
|
9
|
+
private readonly memory;
|
|
10
|
+
private readonly performance;
|
|
11
|
+
private readonly persistence;
|
|
12
|
+
private readonly replication;
|
|
13
|
+
constructor(client: Redis, connection: RedisConnection, runtimeOptions: ParsedOptions);
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
private reporter;
|
|
16
|
+
private analysisMenu;
|
|
17
|
+
private singleModuleMenu;
|
|
18
|
+
private runModule;
|
|
19
|
+
private reportsMenu;
|
|
20
|
+
private watchMenu;
|
|
21
|
+
private settingsMenu;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|