logger

 

logger

extends Node

# 项目设置>全局>自动加载 Logger.gd添加为单例,名称为log,其他地方直接用log.info即可打印
# user:// = cat\AppData\Roaming\Godot\app_userdata\rogue_zombie_dongzhou
enum LogLevel { DEBUG, INFO, WARN, ERROR }

var PROJECT_HOME = "user://"
var LOG_DIR = "logs"  # 日志存放目录
var LOG_DATE : String
var LOG_OB : FileAccess
var LOG_LEVEL = LogLevel.INFO

func _ready():
	_init_log_dir()
	_switch_log_date()
		
func _init_log_dir():
	# 确保日志目录存在
	var home_ob = DirAccess.open(PROJECT_HOME)
	if home_ob and not home_ob.dir_exists(LOG_DIR) and home_ob.make_dir(LOG_DIR) != OK:
		print("res://core/base/Logger.gd _init_dir: Failed to create logs directory: %s" % LOG_DIR)	
		
func _switch_log_date():
	var current_date = Time.get_date_string_from_system()  # 只包含日期
	if LOG_DATE == current_date:
		return
	LOG_DATE = current_date 
	var log_file_name = "RZD_%s.log" % LOG_DATE
	var log_path = "%s%s/%s" % [PROJECT_HOME, LOG_DIR, log_file_name]
	var log_ob: FileAccess
	if FileAccess.file_exists(log_path):
		log_ob = FileAccess.open(log_path, FileAccess.ModeFlags.READ_WRITE)  # 追加,不创建
	else:
		log_ob = FileAccess.open(log_path, FileAccess.ModeFlags.WRITE)  # 覆盖,自动创建
	if not log_ob:
		if LOG_OB:
			warn("FileAccess.open log Failed: %s"% LOG_OB.get_path_absolute())  # 创建日志失败,则记录到昨日文件
		else:
			print("res://core/base/Logger.gd _switch_date: Failed to open log: %s" % LOG_OB.get_path_absolute())
	else:
		LOG_OB = log_ob  # 切换日志文件
		info("FileAccess.open log Success: %s"% LOG_OB.get_path_absolute())

func _log(level: LogLevel, message: String):
	if level < LOG_LEVEL:
		return
	
	# 初始化默认值
	var file_path = "UnknownPath"
	var file_name = "UnknownFile"
	var func_name = "UnknownFunction"

	# 获取调用栈并解析
	var stacks:Array = get_stack()
	if stacks:
		var caller: Dictionary = stacks[2]  # 获取调用者信息行
		if caller:
			file_path = caller['source']
			file_name = file_path.split("/")[-1]
			func_name = "%s(%s)"%[caller['function'], caller['line']]

	var level_str
	match level:
		LogLevel.DEBUG:
			level_str = "DEBUG"
		LogLevel.INFO:
			level_str = "INFO"
		LogLevel.WARN:
			level_str = "WARN"
		LogLevel.ERROR:
			level_str = "ERROR"
		_:
			level_str = "UNKNOWN"

	var timestamp = Time.get_datetime_string_from_system(false)  # 服务器实际时间
	var log_entry = "%s %s %s %s: %s" % [timestamp, level_str, file_name, func_name, message]

	# 控制台
	print(log_entry)

	# 日志文件
	_switch_log_date()
	if LOG_OB:
		LOG_OB.seek_end()
		LOG_OB.store_line(log_entry)

func debug(arg1, arg2="", arg3="", arg4=""):
	_log(LogLevel.DEBUG, _combine_args([arg1, arg2, arg3, arg4]))

func info(arg1, arg2="", arg3="", arg4=""):
	_log(LogLevel.INFO, _combine_args([arg1, arg2, arg3, arg4]))

func warning(arg1, arg2="", arg3="", arg4=""): warn(arg1, arg2, arg3, arg4)
func warn(arg1, arg2="", arg3="", arg4=""):
	_log(LogLevel.WARN, _combine_args([arg1, arg2, arg3, arg4]))

func error(arg1, arg2="", arg3="", arg4=""):
	_log(LogLevel.ERROR, _combine_args([arg1, arg2, arg3, arg4]))

# 私有方法:将可变参数组合为字符串
func _combine_args(args: Array) -> String:
	return " ".join(args)

func set_level(level: LogLevel): 
	# 从枚举里获得名称
	info("%s --> %s" % [LogLevel.find_key(LOG_LEVEL), LogLevel.find_key(level)])
	LOG_LEVEL = level

func _exit_tree():
	if LOG_OB:
		LOG_OB.close()