## Base class of all logger types. class ESCLoggerBase: ## Signal sent when Escoria requires performing an emergency savegame.[br] ## [br] ## #### Parameters[br] ## [br] ## None. ## [br] signal perform_emergency_savegame ## Signal sent when an error or warning happened.[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |message|`Variant`|Error or warning message emitted through the logger.|yes|[br] ## [br] signal error_message_signal(message) ## Log filename format const LOG_FILE_FORMAT: String = "log_%s_%s.log" # Configured log level var _log_level: int ## If true, assert() functions will not be called, thus the program won't ## exit or error. Resets to false after an assert() call was ignored once. ## Useful for console calls. var dont_assert: bool = false # Constructor func _init(): _log_level = ESCLogLevel.determine_escoria_log_level() ## Formats a message depending on context, message and letter, then returns it. The formatted string[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |context|`String`|usually, the escoria file that sent the message.|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## |letter|`String`|letter to add to the formatted log (I for Info, W for Warning...)|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns a `String` value. (`String`) func formatted_message(context: String, msg: String, letter: String) -> String: return "ESC ({0}) {1} {2}: {3}".format([_formatted_date(), letter, context, msg]) ## Trace log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func trace(owner: Object, msg: String): var context: String = owner.get_script().resource_path.get_file() _trace_message(context, msg) # Direct message trace log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _trace_message(context: String, msg: String): print(formatted_message(context, msg, "T")) ## Debug log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func debug(owner: Object, msg: String): var context: String = owner.get_script().resource_path.get_file() _debug_message(context, msg) # Static debug log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _debug_message(context: String, msg: String): print(formatted_message(context, msg, "D")) ## Info log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func info(owner: Object, msg: String): var context: String = owner.get_script().resource_path.get_file() _info_message(context, msg) # Static info log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _info_message(context: String, msg: String): print(formatted_message(context, msg, "I")) ## Warning log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func warn(owner: Object, msg: String): var context: String = owner.get_script().resource_path.get_file() _warn_message(context, msg) # Static warning log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _warn_message(context: String, msg: String): print(formatted_message(context, msg, "W")) push_warning(formatted_message(context, msg, "W")) if ESCProjectSettingsManager.get_setting( ESCProjectSettingsManager.TERMINATE_ON_WARNINGS ): if not dont_assert: assert(false) escoria.get_tree().quit() dont_assert = false error_message_signal.emit(msg) ## Error log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func error(owner: Object, msg: String): var context = owner.get_script().resource_path.get_file() _error_message(context, msg) # Static error log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _error_message(context: String, msg: String): printerr(formatted_message(context, msg, "E")) push_error(formatted_message(context, msg, "E")) if ESCProjectSettingsManager.get_setting( ESCProjectSettingsManager.TERMINATE_ON_ERRORS ): if not dont_assert: assert(false) escoria.get_tree().quit() dont_assert = false error_message_signal.emit(msg) # Formats the current system's datetime as 'YYYY-mm-ddTHH:MM:SS'. func _formatted_date() -> String: var info = Time.get_datetime_dict_from_system() info["year"] = "%04d" % info["year"] info["month"] = "%02d" % info["month"] info["day"] = "%02d" % info["day"] info["hour"] = "%02d" % info["hour"] info["minute"] = "%02d" % info["minute"] info["second"] = "%02d" % info["second"] return "{year}-{month}-{day}T{hour}:{minute}:{second}".format(info) ## A logger that logs to the terminal and to a log file. class ESCLoggerFile extends ESCLoggerBase: ## Log file handler var log_file: FileAccess # Constructor func _init(): super() # This is left alone as this constructor is called from escoria.gd's own # constructor var log_file_path = ProjectSettings.get_setting( ESCProjectSettingsManager.LOG_FILE_PATH ) var date = Time.get_datetime_dict_from_system() log_file_path = log_file_path.path_join(LOG_FILE_FORMAT % [ str(date["year"]) + str(date["month"]) + str(date["day"]), str(date["hour"]) + str(date["minute"]) + str(date["second"]) ]) log_file = FileAccess.open( log_file_path, FileAccess.WRITE ) ## Trace log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func trace(owner: Object, msg: String): if _log_level >= ESCLogLevel.LOG_TRACE: _log_to_file(owner, msg, "T") super.trace(owner, msg) # Direct message trace log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _trace_message(context: String, msg: String): if _log_level >= ESCLogLevel.LOG_TRACE: _log_to_file_message(context, msg, "T") super._trace_message(context, msg) ## Debug log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func debug(owner: Object, msg: String): if _log_level >= ESCLogLevel.LOG_DEBUG: _log_to_file(owner, msg, "D") super.debug(owner, msg) # Static debug log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _debug_message(context: String, msg: String): if _log_level >= ESCLogLevel.LOG_DEBUG: _log_to_file_message(context, msg, "D") super._debug_message(context, msg) ## Info log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func info(owner: Object, msg: String): if _log_level >= ESCLogLevel.LOG_INFO: _log_to_file(owner, msg, "I") super.info(owner, msg) # Static info log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _info_message(context: String, msg: String): if _log_level >= ESCLogLevel.LOG_INFO: _log_to_file_message(context, msg, "I") super._info_message(context, msg) ## Warning log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func warn(owner: Object, msg: String): if _log_level >= ESCLogLevel.LOG_WARNING: _log_to_file(owner, msg, "W") if ESCProjectSettingsManager.get_setting( ESCProjectSettingsManager.TERMINATE_ON_WARNINGS ): _log_stack_trace_to_file() print_stack() close_logs() super.warn(owner, msg) # Static warning log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _warn_message(context: String, msg: String): if _log_level >= ESCLogLevel.LOG_WARNING: _log_to_file_message(context, msg, "W") if ESCProjectSettingsManager.get_setting( ESCProjectSettingsManager.TERMINATE_ON_WARNINGS ): _log_stack_trace_to_file() print_stack() close_logs() super._warn_message(context, msg) ## Error log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func error(owner: Object, msg: String): if _log_level >= ESCLogLevel.LOG_ERROR: _log_to_file(owner, msg, "E") if ESCProjectSettingsManager.get_setting( ESCProjectSettingsManager.TERMINATE_ON_ERRORS ): _log_stack_trace_to_file() print_stack() close_logs() super.error(owner, msg) # Static error log (requiring a string for the context) # # #### PARAMETERS # # - owner: caller as a string value # - msg: logged message. func _error_message(context: String, msg: String): if _log_level >= ESCLogLevel.LOG_ERROR: _log_to_file_message(context, msg, "E") if ESCProjectSettingsManager.get_setting( ESCProjectSettingsManager.TERMINATE_ON_ERRORS ): _log_stack_trace_to_file() print_stack() close_logs() super._error_message(context, msg) ## Close the log file cleanly[br] ## [br] ## #### Parameters[br] ## [br] ## None. ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func close_logs(): print("Closing logs peacefully.") _log_line_to_file("Closing logs peacefully.") log_file.close() # Log the log message and context to file func _log_to_file(owner: Object, msg: String, letter: String): var context: String if owner != null: context = owner.get_script().resource_path.get_file() _log_to_file_message(context, msg, letter) # Log the log message and context as string to file func _log_to_file_message(context: String, msg: String, letter: String): if log_file.is_open(): log_file.store_string(formatted_message(context, msg, letter) + "\n") # Log the message line to file func _log_line_to_file(msg: String): if log_file.is_open(): log_file.store_string(msg + "\n") # Log the stack trace to file func _log_stack_trace_to_file(): var frame_number = 0 for stack in get_stack().slice(2, get_stack().size()): _log_line_to_file( "Frame %s - %s:%s in function '%s'" % [ str(frame_number), stack["source"], stack["line"], stack["function"], ] ) frame_number += 1 ## A simple logger that logs to terminal using debug() function class ESCLoggerVerbose extends ESCLoggerBase: # Constructor func _init(): pass ## Debug log[br] ## [br] ## #### Parameters[br] ## [br] ## | Name | Type | Description | Required? |[br] ## |:-----|:-----|:------------|:----------|[br] ## |owner|`Object`|caller object (usually, `self`)|yes|[br] ## |msg|`String`|logged message.|yes|[br] ## [br] ## #### Returns[br] ## [br] ## Returns nothing. func debug(owner: Object, msg: String): var context = owner.get_script().resource_path.get_file() print(context, ": ", msg)