@andrey4emk/npm-app-back-b24 3.0.2 → 3.2.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/logs/logs.ts +102 -2
- package/package.json +1 -1
- package/utils/fetchRetry.ts +1 -1
package/logs/logs.ts
CHANGED
|
@@ -19,6 +19,17 @@ interface LogLevelConfig {
|
|
|
19
19
|
/** Полная конфигурация логирования */
|
|
20
20
|
type LogConfig = Record<LogLevel, LogLevelConfig>;
|
|
21
21
|
|
|
22
|
+
// ==================== Константы B24 Chat ====================
|
|
23
|
+
|
|
24
|
+
/** ID бота в B24 для отправки error-логов */
|
|
25
|
+
const B24_BOT_ID = 66600;
|
|
26
|
+
|
|
27
|
+
/** CLIENT_ID бота в B24 */
|
|
28
|
+
const B24_CLIENT_ID = "6rf74zyu842h6op1z186b08k7aavqq7z";
|
|
29
|
+
|
|
30
|
+
/** Лимит длины сообщения для B24 чата (безопасный, с запасом на BB-обёртку) */
|
|
31
|
+
const B24_TEXT_LIMIT = 4000;
|
|
32
|
+
|
|
22
33
|
// ==================== Настройки ====================
|
|
23
34
|
|
|
24
35
|
const configDir: string = process.env.CONFIG_DIR || "../config";
|
|
@@ -62,8 +73,20 @@ class LogsAPI {
|
|
|
62
73
|
|
|
63
74
|
private readonly resetColor = "\x1b[0m";
|
|
64
75
|
|
|
76
|
+
/** Webhook URL для отправки error-логов в B24 чат */
|
|
77
|
+
private readonly b24WebhookUrl: string | undefined;
|
|
78
|
+
|
|
79
|
+
/** ID чата B24 для отправки error-логов (формат: chatXXXXXX) */
|
|
80
|
+
private readonly b24ChatId: string | undefined;
|
|
81
|
+
|
|
82
|
+
/** Имя приложения для заголовка сообщения */
|
|
83
|
+
private readonly appName: string;
|
|
84
|
+
|
|
65
85
|
constructor() {
|
|
66
86
|
this.initConfig();
|
|
87
|
+
this.b24WebhookUrl = process.env.LOG_B24_WEBHOOK_URL;
|
|
88
|
+
this.b24ChatId = process.env.LOG_B24_CHAT_ID;
|
|
89
|
+
this.appName = process.env.APP_NAME || "Unknown App";
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
/** Проверяем и заполняем конфиг дефолтными значениями если данных нет */
|
|
@@ -77,12 +100,24 @@ class LogsAPI {
|
|
|
77
100
|
|
|
78
101
|
/**
|
|
79
102
|
* Добавляет сообщение в лог
|
|
103
|
+
*
|
|
104
|
+
* Важно: при уровне `error` сообщение отправляется в B24 чат (через webhook)
|
|
105
|
+
* независимо от настройки `error.enabled` в `log.json`. Настройка `enabled`
|
|
106
|
+
* управляет только выводом в консоль. Это сделано намеренно, чтобы критические
|
|
107
|
+
* ошибки всегда доходили до команды даже при отключённом консольном логировании.
|
|
108
|
+
*
|
|
80
109
|
* @param message - Текст сообщения или объект для вывода
|
|
81
110
|
* @param level - Уровень логирования (trace, debug, info, warn, error)
|
|
82
111
|
* @param jsonData - Дополнительные данные для вывода (опционально)
|
|
83
112
|
*/
|
|
84
113
|
add(message: string | object, level?: LogLevel, jsonData?: unknown): void {
|
|
85
114
|
const levelStr: LogLevel = level || "info";
|
|
115
|
+
const messageText = typeof message === "string" ? message : JSON.stringify(message);
|
|
116
|
+
|
|
117
|
+
// Отправляем error-логи в B24 чат независимо от настроек консольного вывода
|
|
118
|
+
if (levelStr === "error") {
|
|
119
|
+
this.sendToB24Chat(messageText, jsonData);
|
|
120
|
+
}
|
|
86
121
|
|
|
87
122
|
// Проверяем конфиг, и если логирование отключено, то выходим
|
|
88
123
|
const isLoggingEnabled = confLog.get(`${levelStr}.enabled`) as boolean;
|
|
@@ -90,8 +125,6 @@ class LogsAPI {
|
|
|
90
125
|
return;
|
|
91
126
|
}
|
|
92
127
|
|
|
93
|
-
const messageText = typeof message === "string" ? message : JSON.stringify(message);
|
|
94
|
-
|
|
95
128
|
// Получаем цвет для уровня
|
|
96
129
|
const color = (confLog.get(`${levelStr}.color`) as string) || "\x1b[37m";
|
|
97
130
|
|
|
@@ -106,6 +139,73 @@ class LogsAPI {
|
|
|
106
139
|
console.dir(jsonData, { depth: null, colors: true });
|
|
107
140
|
}
|
|
108
141
|
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Убирает BB-теги для plain text отправки (при обрезке текста)
|
|
145
|
+
*/
|
|
146
|
+
private stripBbCodes(text: string): string {
|
|
147
|
+
return text.replace(/\[\/?(b|code)\]/g, "");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Отправляет error-сообщение в чат B24 через webhook (fire-and-forget)
|
|
152
|
+
* Использует нативный fetch, а не fetchRetry — во избежание циклической зависимости
|
|
153
|
+
* Ошибки не пробрасываются, только console.error
|
|
154
|
+
*/
|
|
155
|
+
private sendToB24Chat(message: string, jsonData?: unknown): void {
|
|
156
|
+
if (!this.b24WebhookUrl || !this.b24ChatId) return;
|
|
157
|
+
|
|
158
|
+
// Нормализуем URL — гарантируем trailing slash
|
|
159
|
+
const baseUrl = this.b24WebhookUrl.endsWith("/") ? this.b24WebhookUrl : `${this.b24WebhookUrl}/`;
|
|
160
|
+
const url = `${baseUrl}imbot.message.add.json`;
|
|
161
|
+
|
|
162
|
+
let text = `[b]ERROR[/b] | ${this.appName}\n${message}`;
|
|
163
|
+
|
|
164
|
+
// Добавляем jsonData если есть
|
|
165
|
+
if (jsonData !== undefined) {
|
|
166
|
+
// Безопасная сериализация — логгер не должен бросать исключения
|
|
167
|
+
let jsonStr: string;
|
|
168
|
+
try {
|
|
169
|
+
jsonStr = JSON.stringify(jsonData, null, 2);
|
|
170
|
+
} catch {
|
|
171
|
+
jsonStr = "[Не удалось сериализовать jsonData]";
|
|
172
|
+
}
|
|
173
|
+
text += `\n[code]${jsonStr}[/code]`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Обрезаем до лимита B24
|
|
177
|
+
let isTruncated = false;
|
|
178
|
+
if (text.length > B24_TEXT_LIMIT) {
|
|
179
|
+
const truncatedSuffix = "\n...(обрезано)";
|
|
180
|
+
text = text.slice(0, B24_TEXT_LIMIT - truncatedSuffix.length) + truncatedSuffix;
|
|
181
|
+
isTruncated = true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Если текст обрезан — отправляем без BB-тегов, чтобы не разорвать [code]...[/code]
|
|
185
|
+
if (isTruncated) {
|
|
186
|
+
text = this.stripBbCodes(text);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
fetch(url, {
|
|
190
|
+
method: "POST",
|
|
191
|
+
headers: { "Content-Type": "application/json" },
|
|
192
|
+
body: JSON.stringify({
|
|
193
|
+
BOT_ID: B24_BOT_ID,
|
|
194
|
+
CLIENT_ID: B24_CLIENT_ID,
|
|
195
|
+
DIALOG_ID: this.b24ChatId,
|
|
196
|
+
MESSAGE: text,
|
|
197
|
+
}),
|
|
198
|
+
})
|
|
199
|
+
.then((response) => {
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
console.error(`Logs B24 Chat: HTTP ${response.status}`);
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
.catch((error: unknown) => {
|
|
205
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
206
|
+
console.error(`Logs B24 Chat: ошибка отправки — ${errMsg}`);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
109
209
|
}
|
|
110
210
|
|
|
111
211
|
export const logs = new LogsAPI();
|
package/package.json
CHANGED
package/utils/fetchRetry.ts
CHANGED
|
@@ -64,7 +64,7 @@ export async function fetchRetry(
|
|
|
64
64
|
|
|
65
65
|
logs.add(
|
|
66
66
|
`fetchRetry: попытка ${attempt}/${retries} не удалась (${lastError.message}), повтор через ${delay}мс — ${String(url)}`,
|
|
67
|
-
"
|
|
67
|
+
"warn"
|
|
68
68
|
);
|
|
69
69
|
|
|
70
70
|
await new Promise((resolve) => setTimeout(resolve, delay));
|