WalleGriffkinder commited on
Commit
96d3197
·
verified ·
1 Parent(s): a7b2208

Update stats-reporter.js

Browse files
Files changed (1) hide show
  1. stats-reporter.js +157 -90
stats-reporter.js CHANGED
@@ -10,11 +10,9 @@ const config = {
10
  STATS_GIST_ID: process.env.STATS_GIST_ID || '',
11
  ENV_GIST_ID: process.env.ENV_GIST_ID || '',
12
  UPDATE_INTERVAL_MINUTES: parseInt(process.env.UPDATE_INTERVAL_MINUTES || '1440', 10),
13
- // Основной путь для данных Telegram Bot API
14
  TELEGRAM_DATA_DIR: process.env.TELEGRAM_DATA_DIR || '/var/lib/telegram-bot-api',
15
- // Дополнительные пути для сканирования, разделенные запятыми
16
- ADDITIONAL_SCAN_DIRS: (process.env.ADDITIONAL_SCAN_DIRS || '').split(',').filter(Boolean),
17
- FILES_TTL: parseInt(process.env.FILES_TTL || '-1', 10)
18
  };
19
 
20
  // Проверка обязательных переменных
@@ -26,63 +24,126 @@ for (const envVar of requiredEnvVars) {
26
  }
27
  }
28
 
29
- // Вначале сканируем систему, чтобы найти большие директории
30
- async function findLargeDirectories() {
31
  try {
32
- console.log(`[${new Date().toISOString()}] Scanning filesystem for large directories...`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- // Ищем директории с файлами размером больше 10MB
35
- const output = execSync(`find / -type d -path "/proc" -prune -o -path "/sys" -prune -o -path "/dev" -prune -o -type f -size +10M -exec dirname {} \\; 2>/dev/null | sort | uniq`).toString().trim();
36
 
37
- const largeDirs = output.split('\n').filter(Boolean);
38
- console.log(`Found large files in these directories: ${largeDirs.join(', ')}`);
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- return largeDirs;
41
  } catch (error) {
42
- console.error(`Error finding large directories: ${error.message}`);
43
- return [];
44
  }
45
  }
46
 
47
- // Функция для получения размера директории
48
- async function getDirSize(dirPath) {
49
  try {
50
- // Проверяем существование директории перед измерением
51
- await fs.access(dirPath);
 
52
 
53
- // Используем du для получения размера директории
54
- const output = execSync(`du -sb "${dirPath}" | cut -f1`).toString().trim();
55
- return parseInt(output, 10);
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  } catch (error) {
57
- console.error(`Error getting directory size for ${dirPath}: ${error.message}`);
58
- return 0;
59
  }
60
  }
61
 
62
- // Функция для подсчета файлов в директории (рекурсивно)
63
- async function countFiles(dirPath) {
 
 
 
 
 
 
 
 
64
  try {
65
- await fs.access(dirPath);
66
- let count = 0;
67
-
68
- async function traverse(dir) {
69
- const entries = await fs.readdir(dir, { withFileTypes: true });
70
-
71
- for (const entry of entries) {
72
- const fullPath = path.join(dir, entry.name);
73
-
74
- if (entry.isDirectory()) {
75
- await traverse(fullPath);
76
- } else {
77
- count++;
78
- }
79
- }
80
  }
81
-
82
- await traverse(dirPath);
83
- return count;
 
 
 
 
 
 
 
 
84
  } catch (error) {
85
- console.error(`Error counting files in ${dirPath}: ${error.message}`);
86
  return 0;
87
  }
88
  }
@@ -209,54 +270,30 @@ async function updateStats() {
209
  try {
210
  console.log(`[${new Date().toISOString()}] Updating statistics...`);
211
 
212
- // Сначала найдем все крупные директории в системе
213
- const largeDirs = await findLargeDirectories();
214
-
215
- // Запускаем очистку старых файлов, если настроено
216
- const cleanupResults = await cleanupOldFiles(config.TELEGRAM_DATA_DIR, config.FILES_TTL);
217
-
218
- // Основная директория
219
- let fileCount = await countFiles(config.TELEGRAM_DATA_DIR);
220
- let totalSize = await getDirSize(config.TELEGRAM_DATA_DIR);
221
 
222
- console.log(`Main directory ${config.TELEGRAM_DATA_DIR}: ${fileCount} files, ${formatBytes(totalSize)}`);
 
 
223
 
224
- // Добавляем все дополнительные директории
225
- const allDirs = [...config.ADDITIONAL_SCAN_DIRS, ...largeDirs];
 
226
 
227
- // Уникальные директории (исключаем дубликаты и вложенные)
228
- const uniqueDirs = Array.from(new Set(allDirs));
 
 
229
 
230
- // Информация о каждой директории
231
- const dirStats = {
232
- [config.TELEGRAM_DATA_DIR]: {
233
- files: fileCount,
234
- sizeBytes: totalSize,
235
- sizeHuman: formatBytes(totalSize)
236
- }
237
- };
238
 
239
- // Проверяем также все дополнительные директории
240
- for (const dir of uniqueDirs) {
241
- if (dir && dir !== config.TELEGRAM_DATA_DIR) {
242
- try {
243
- const dirFileCount = await countFiles(dir);
244
- const dirSize = await getDirSize(dir);
245
-
246
- console.log(`Additional directory ${dir}: ${dirFileCount} files, ${formatBytes(dirSize)}`);
247
-
248
- dirStats[dir] = {
249
- files: dirFileCount,
250
- sizeBytes: dirSize,
251
- sizeHuman: formatBytes(dirSize)
252
- };
253
-
254
- fileCount += dirFileCount;
255
- totalSize += dirSize;
256
- } catch (e) {
257
- console.error(`Error processing directory ${dir}: ${e.message}`);
258
- }
259
- }
260
  }
261
 
262
  const now = Date.now();
@@ -266,8 +303,6 @@ async function updateStats() {
266
  fileCount,
267
  totalSizeBytes: totalSize,
268
  totalSizeHuman: formatBytes(totalSize),
269
- directoryStats: dirStats,
270
- scannedDirectories: [config.TELEGRAM_DATA_DIR, ...uniqueDirs].filter(Boolean),
271
  cleanupResults: config.FILES_TTL > 0 ? {
272
  ttlHours: config.FILES_TTL,
273
  processedItems: cleanupResults.processed,
@@ -275,6 +310,36 @@ async function updateStats() {
275
  } : { enabled: false }
276
  };
277
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  // Обновляем статистику в Gist
279
  const statsJson = JSON.stringify(stats, null, 2);
280
  await updateGist(config.STATS_GIST_ID, 'telegram-bot-api-stats.json', statsJson);
@@ -304,6 +369,7 @@ async function updateEnvInfo(statsLink) {
304
  SPACE_ID: spaceId,
305
  FILES_TTL: config.FILES_TTL,
306
  UPDATE_INTERVAL_MINUTES: config.UPDATE_INTERVAL_MINUTES,
 
307
  statsLink: statsLink || ''
308
  };
309
 
@@ -390,4 +456,5 @@ const intervalMs = config.UPDATE_INTERVAL_MINUTES * 60 * 1000;
390
  setInterval(runUpdate, intervalMs);
391
 
392
  console.log(`[${new Date().toISOString()}] Stats reporter started, updating every ${config.UPDATE_INTERVAL_MINUTES} minutes`);
393
- console.log(`[${new Date().toISOString()}] File TTL set to ${config.FILES_TTL} hours ${config.FILES_TTL <= 0 ? '(cleanup disabled)' : ''}`);
 
 
10
  STATS_GIST_ID: process.env.STATS_GIST_ID || '',
11
  ENV_GIST_ID: process.env.ENV_GIST_ID || '',
12
  UPDATE_INTERVAL_MINUTES: parseInt(process.env.UPDATE_INTERVAL_MINUTES || '1440', 10),
 
13
  TELEGRAM_DATA_DIR: process.env.TELEGRAM_DATA_DIR || '/var/lib/telegram-bot-api',
14
+ FILES_TTL: parseInt(process.env.FILES_TTL || '-1', 10),
15
+ DEBUG_MODE: process.env.DEBUG_MODE === 'true' // Для включения подробного логирования
 
16
  };
17
 
18
  // Проверка обязательных переменных
 
24
  }
25
  }
26
 
27
+ // Функция для подсчета файлов и логирования всех путей
28
+ async function countFilesWithLogging(dirPath) {
29
  try {
30
+ let count = 0;
31
+ let filesList = [];
32
+ let totalSize = 0;
33
+
34
+ async function traverse(dir) {
35
+ try {
36
+ const entries = await fs.readdir(dir, { withFileTypes: true });
37
+
38
+ for (const entry of entries) {
39
+ const fullPath = path.join(dir, entry.name);
40
+
41
+ try {
42
+ if (entry.isDirectory()) {
43
+ await traverse(fullPath);
44
+ } else {
45
+ count++;
46
+ // Получаем размер файла
47
+ const stats = await fs.stat(fullPath);
48
+ totalSize += stats.size;
49
+
50
+ // Собираем пути всех файлов
51
+ if (config.DEBUG_MODE) {
52
+ filesList.push(`${fullPath} (${formatBytes(stats.size)})`);
53
+ }
54
+ }
55
+ } catch (e) {
56
+ console.error(`Error processing ${fullPath}: ${e.message}`);
57
+ }
58
+ }
59
+ } catch (e) {
60
+ console.error(`Error reading directory ${dir}: ${e.message}`);
61
+ }
62
+ }
63
 
64
+ await traverse(dirPath);
 
65
 
66
+ // Записываем список файлов для отладки
67
+ if (config.DEBUG_MODE) {
68
+ console.log(`=== DEBUG: Found ${count} files in ${dirPath} with total size ${formatBytes(totalSize)} ===`);
69
+ const debugFilename = `/tmp/telegram-api-files-${Date.now()}.txt`;
70
+ await fs.writeFile(debugFilename, filesList.join('\n'));
71
+ console.log(`DEBUG: Full file list saved to ${debugFilename}`);
72
+
73
+ // Записываем размеры 10 самых больших файлов
74
+ console.log(`=== DEBUG: Top 10 largest files in ${dirPath} ===`);
75
+ const largestFiles = await findLargestFiles(dirPath, 10);
76
+ for (const file of largestFiles) {
77
+ console.log(`${file.path}: ${formatBytes(file.size)}`);
78
+ }
79
+ }
80
 
81
+ return { count, filesList, sizeFromFiles: totalSize };
82
  } catch (error) {
83
+ console.error(`Error counting files in ${dirPath}: ${error.message}`);
84
+ return { count: 0, filesList: [], sizeFromFiles: 0 };
85
  }
86
  }
87
 
88
+ // Находим самые большие файлы
89
+ async function findLargestFiles(dirPath, limit = 10) {
90
  try {
91
+ // Используем find и sort для поиска самых больших файлов
92
+ const cmd = `find "${dirPath}" -type f -exec du -sh {} \\; | sort -rh | head -n ${limit}`;
93
+ const output = execSync(cmd).toString().trim();
94
 
95
+ return output.split('\n')
96
+ .filter(Boolean)
97
+ .map(line => {
98
+ const parts = line.trim().split(/\s+/);
99
+ const size = parts[0];
100
+ const path = parts.slice(1).join(' ');
101
+
102
+ // Преобразуем размер в байты для сортировки
103
+ const sizeInBytes = humanReadableToBytes(size);
104
+
105
+ return {
106
+ size: sizeInBytes,
107
+ sizeHuman: size,
108
+ path: path
109
+ };
110
+ });
111
  } catch (error) {
112
+ console.error(`Error finding largest files: ${error.message}`);
113
+ return [];
114
  }
115
  }
116
 
117
+ // Преобразование человекочитаемого размера в байты
118
+ function humanReadableToBytes(sizeStr) {
119
+ const units = {
120
+ 'B': 1,
121
+ 'K': 1024,
122
+ 'M': 1024 * 1024,
123
+ 'G': 1024 * 1024 * 1024,
124
+ 'T': 1024 * 1024 * 1024 * 1024
125
+ };
126
+
127
  try {
128
+ const matches = sizeStr.match(/^(\d+(?:\.\d+)?)([KMGT]?)$/i);
129
+ if (matches) {
130
+ const size = parseFloat(matches[1]);
131
+ const unit = matches[2].toUpperCase() || 'B';
132
+ return size * (units[unit] || 1);
 
 
 
 
 
 
 
 
 
 
133
  }
134
+ return 0;
135
+ } catch (e) {
136
+ return 0;
137
+ }
138
+ }
139
+
140
+ // Функция для получения размера директории
141
+ async function getDirSize(dirPath) {
142
+ try {
143
+ const output = execSync(`du -sb "${dirPath}" | cut -f1`).toString().trim();
144
+ return parseInt(output, 10);
145
  } catch (error) {
146
+ console.error(`Error getting directory size: ${error.message}`);
147
  return 0;
148
  }
149
  }
 
270
  try {
271
  console.log(`[${new Date().toISOString()}] Updating statistics...`);
272
 
273
+ // Запуск очистки, если настроено
274
+ const cleanupResults = config.FILES_TTL > 0
275
+ ? await cleanupOldFiles(config.TELEGRAM_DATA_DIR, config.FILES_TTL)
276
+ : { processed: 0, deleted: 0 };
 
 
 
 
 
277
 
278
+ // Получаем статистику с подробным логированием
279
+ const { count: fileCount, sizeFromFiles } = await countFilesWithLogging(config.TELEGRAM_DATA_DIR);
280
+ const totalSize = await getDirSize(config.TELEGRAM_DATA_DIR);
281
 
282
+ console.log(`Directory ${config.TELEGRAM_DATA_DIR}: ${fileCount} files`);
283
+ console.log(`Size from du command: ${formatBytes(totalSize)}`);
284
+ console.log(`Size from summing files: ${formatBytes(sizeFromFiles)}`);
285
 
286
+ // Проверяем, если есть значительное расхождение
287
+ if (Math.abs(totalSize - sizeFromFiles) > 1024 * 1024) { // Больше 1 МБ разницы
288
+ console.log(`WARNING: Significant difference between directory size and sum of file sizes: ${formatBytes(Math.abs(totalSize - sizeFromFiles))}`);
289
+ }
290
 
291
+ // Проверяем наличие скрытых файлов
292
+ const hiddenFilesCommand = `find "${config.TELEGRAM_DATA_DIR}" -name ".*" -not -name "." -not -name ".." -type f | wc -l`;
293
+ const hiddenFilesCount = parseInt(execSync(hiddenFilesCommand).toString().trim());
 
 
 
 
 
294
 
295
+ if (hiddenFilesCount > 0) {
296
+ console.log(`Found ${hiddenFilesCount} hidden files`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  }
298
 
299
  const now = Date.now();
 
303
  fileCount,
304
  totalSizeBytes: totalSize,
305
  totalSizeHuman: formatBytes(totalSize),
 
 
306
  cleanupResults: config.FILES_TTL > 0 ? {
307
  ttlHours: config.FILES_TTL,
308
  processedItems: cleanupResults.processed,
 
310
  } : { enabled: false }
311
  };
312
 
313
+ // Если включен режим отладки, добавляем информацию о самых больших файлах
314
+ if (config.DEBUG_MODE) {
315
+ try {
316
+ // Список всех файлов в директории (только имена без размеров)
317
+ const allFilesCommand = `find "${config.TELEGRAM_DATA_DIR}" -type f | sort`;
318
+ const allFiles = execSync(allFilesCommand).toString().trim().split('\n');
319
+
320
+ // Поиск самых больших файлов
321
+ const largestFiles = await findLargestFiles(config.TELEGRAM_DATA_DIR, 20);
322
+
323
+ stats.debug = {
324
+ totalFiles: fileCount,
325
+ hiddenFiles: hiddenFilesCount,
326
+ sizeFromDu: totalSize,
327
+ sizeFromFiles: sizeFromFiles,
328
+ fileListSample: allFiles.slice(0, 100), // Первые 100 файлов
329
+ largestFiles: largestFiles.map(file => ({
330
+ path: file.path,
331
+ size: file.size,
332
+ sizeHuman: file.sizeHuman
333
+ }))
334
+ };
335
+ } catch (e) {
336
+ console.error(`Error collecting debug info: ${e.message}`);
337
+ stats.debug = {
338
+ error: e.message
339
+ };
340
+ }
341
+ }
342
+
343
  // Обновляем статистику в Gist
344
  const statsJson = JSON.stringify(stats, null, 2);
345
  await updateGist(config.STATS_GIST_ID, 'telegram-bot-api-stats.json', statsJson);
 
369
  SPACE_ID: spaceId,
370
  FILES_TTL: config.FILES_TTL,
371
  UPDATE_INTERVAL_MINUTES: config.UPDATE_INTERVAL_MINUTES,
372
+ DEBUG_MODE: config.DEBUG_MODE,
373
  statsLink: statsLink || ''
374
  };
375
 
 
456
  setInterval(runUpdate, intervalMs);
457
 
458
  console.log(`[${new Date().toISOString()}] Stats reporter started, updating every ${config.UPDATE_INTERVAL_MINUTES} minutes`);
459
+ console.log(`[${new Date().toISOString()}] File TTL set to ${config.FILES_TTL} hours ${config.FILES_TTL <= 0 ? '(cleanup disabled)' : ''}`);
460
+ console.log(`[${new Date().toISOString()}] Debug mode is ${config.DEBUG_MODE ? 'enabled' : 'disabled'}`);