summaryrefslogtreecommitdiff
path: root/addons/escoria-core/tools/logging/esc_logger.gd
diff options
context:
space:
mode:
Diffstat (limited to 'addons/escoria-core/tools/logging/esc_logger.gd')
-rw-r--r--addons/escoria-core/tools/logging/esc_logger.gd462
1 files changed, 462 insertions, 0 deletions
diff --git a/addons/escoria-core/tools/logging/esc_logger.gd b/addons/escoria-core/tools/logging/esc_logger.gd
new file mode 100644
index 0000000..26d8d86
--- /dev/null
+++ b/addons/escoria-core/tools/logging/esc_logger.gd
@@ -0,0 +1,462 @@
+## 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)