192 lines
6.6 KiB
GDScript
192 lines
6.6 KiB
GDScript
class_name LogsRich
|
||
extends RichTextLabel
|
||
|
||
var _log_text: String = "":
|
||
set(value):
|
||
_log_text = value
|
||
text = _log_text
|
||
scroll_to_line(get_line_count())
|
||
get:
|
||
return _log_text
|
||
|
||
enum LogLevel {
|
||
INFO,
|
||
WARNING,
|
||
ERROR,
|
||
DEBUG
|
||
}
|
||
|
||
var _level_colors: Dictionary = {
|
||
LogLevel.INFO: Color.WHITE,
|
||
LogLevel.WARNING: Color.YELLOW,
|
||
LogLevel.ERROR: Color.RED,
|
||
LogLevel.DEBUG: Color.CYAN
|
||
}
|
||
|
||
var _level_prefixes: Dictionary = {
|
||
LogLevel.INFO: "[INFO]",
|
||
LogLevel.WARNING: "[WARNING]",
|
||
LogLevel.ERROR: "[ERROR]",
|
||
LogLevel.DEBUG: "[DEBUG]"
|
||
}
|
||
|
||
var max_lines: int = 1000
|
||
|
||
func _ready():
|
||
scroll_active = true
|
||
scroll_following = true
|
||
bbcode_enabled = true
|
||
|
||
# Добавляем моноширинный шрифт для лучшего отображения логов
|
||
var font = get_theme_font("normal_font")
|
||
if font:
|
||
add_theme_font_override("normal_font", font.duplicate())
|
||
|
||
clear_logs()
|
||
|
||
func add_log(message: String, level: LogLevel = LogLevel.INFO) -> void:
|
||
var timestamp = Time.get_time_string_from_system()
|
||
var prefix = _level_prefixes.get(level, "[INFO]")
|
||
var color = _level_colors.get(level, Color.WHITE)
|
||
|
||
var formatted_message = "[%s] %s %s" % [timestamp, prefix, message]
|
||
|
||
# Используем BBcode для цветного текста
|
||
# Важно: to_html() возвращает цвет без #, нужно добавить
|
||
var color_hex = color.to_html()
|
||
append_text("[color=#%s]%s[/color]\n" % [color_hex, formatted_message])
|
||
|
||
# Обновляем приватную переменную
|
||
_log_text = text
|
||
|
||
# Ограничиваем количество строк
|
||
limit_line_count()
|
||
|
||
# Прокручиваем к последней строке
|
||
scroll_to_line(get_line_count())
|
||
|
||
func info(message: String) -> void:
|
||
add_log(message, LogLevel.INFO)
|
||
|
||
func warning(message: String) -> void:
|
||
add_log(message, LogLevel.WARNING)
|
||
|
||
func error(message: String) -> void:
|
||
add_log(message, LogLevel.ERROR)
|
||
|
||
func debug(message: String) -> void:
|
||
add_log(message, LogLevel.DEBUG)
|
||
|
||
func clear_logs() -> void:
|
||
clear()
|
||
text = ""
|
||
_log_text = ""
|
||
|
||
func limit_line_count() -> void:
|
||
var lines = get_parsed_text().split("\n")
|
||
if lines.size() > max_lines:
|
||
# Удаляем старые строки
|
||
var _new_lines = lines.slice(lines.size() - max_lines)
|
||
|
||
# Очищаем и перестраиваем текст с сохранением форматирования
|
||
clear()
|
||
text = ""
|
||
|
||
# Нужно переформатировать все строки снова
|
||
# Это сложно сделать правильно без хранения дополнительной информации о цветах
|
||
# Поэтому лучше использовать альтернативный подход:
|
||
|
||
# Просто обрезаем raw текст
|
||
var current_text = get_parsed_text()
|
||
var all_lines = current_text.split("\n")
|
||
if all_lines.size() > max_lines:
|
||
var trimmed_lines = all_lines.slice(all_lines.size() - max_lines)
|
||
clear()
|
||
text = "\n".join(trimmed_lines)
|
||
_log_text = text
|
||
|
||
# Альтернативная, более простая реализация limit_line_count
|
||
func limit_line_count_simple() -> void:
|
||
# Получаем сырой текст без BBcode тегов
|
||
var raw_text = get_parsed_text()
|
||
var lines = raw_text.split("\n")
|
||
|
||
if lines.size() > max_lines:
|
||
# Удаляем первые строки сверх лимита
|
||
clear()
|
||
text = ""
|
||
|
||
# Начинаем с индекса, где превышен лимит
|
||
var start_index = lines.size() - max_lines
|
||
for i in range(start_index, lines.size()):
|
||
# Здесь нужно определить уровень логирования для каждой строки
|
||
# Это сложно без хранения дополнительной информации
|
||
# Поэтому просто добавляем как INFO
|
||
var line = lines[i].strip_edges()
|
||
if line.length() > 0:
|
||
append_text("[color=#ffffff]%s[/color]\n" % line)
|
||
|
||
_log_text = text
|
||
|
||
# Лучший подход: хранить логи в массиве и перерисовывать при необходимости
|
||
var _log_entries: Array = [] # Каждая запись: {message: String, level: LogLevel, timestamp: String}
|
||
|
||
func add_log_advanced(message: String, level: LogLevel = LogLevel.INFO) -> void:
|
||
var timestamp = Time.get_time_string_from_system()
|
||
var entry = {
|
||
"message": message,
|
||
"level": level,
|
||
"timestamp": timestamp
|
||
}
|
||
|
||
_log_entries.append(entry)
|
||
|
||
# Ограничиваем количество записей
|
||
if _log_entries.size() > max_lines:
|
||
_log_entries.pop_front()
|
||
|
||
# Перерисовываем все логи
|
||
redraw_logs()
|
||
|
||
func redraw_logs() -> void:
|
||
clear()
|
||
text = ""
|
||
|
||
for entry in _log_entries:
|
||
var prefix = _level_prefixes.get(entry.level, "[INFO]")
|
||
var color = _level_colors.get(entry.level, Color.WHITE)
|
||
var formatted_message = "[%s] %s %s" % [entry.timestamp, prefix, entry.message]
|
||
var color_hex = color.to_html()
|
||
append_text("[color=#%s]%s[/color]\n" % [color_hex, formatted_message])
|
||
|
||
_log_text = text
|
||
scroll_to_line(get_line_count())
|
||
|
||
# Метод для сохранения логов в файл
|
||
func save_logs_to_file(path: String = "user://logs.txt") -> void:
|
||
var file = FileAccess.open(path, FileAccess.WRITE)
|
||
if file:
|
||
file.store_string(get_parsed_text())
|
||
file.close()
|
||
info("Logs saved to: %s" % path)
|
||
else:
|
||
error("Failed to save logs to: %s" % path)
|
||
|
||
# Метод для фильтрации логов по уровню
|
||
func filter_logs_by_level(min_level: LogLevel) -> void:
|
||
if _log_entries.is_empty():
|
||
return
|
||
|
||
clear()
|
||
text = ""
|
||
|
||
for entry in _log_entries:
|
||
if entry.level >= min_level:
|
||
var prefix = _level_prefixes.get(entry.level, "[INFO]")
|
||
var color = _level_colors.get(entry.level, Color.WHITE)
|
||
var formatted_message = "[%s] %s %s" % [entry.timestamp, prefix, entry.message]
|
||
var color_hex = color.to_html()
|
||
append_text("[color=#%s]%s[/color]\n" % [color_hex, formatted_message])
|
||
|
||
_log_text = text
|