diff --git a/Test.gd b/Test.gd index c9da6e4..37fb9a2 100644 --- a/Test.gd +++ b/Test.gd @@ -37,7 +37,7 @@ func _ready() -> void: add_child(core) await get_tree().process_frame # Print information about CORE - core.logger.info(await core.get_formatted_string("""Version information: + core.logger.info("Test.gd", await core.get_formatted_string("""Version information: Release (semantic) = %release_semantic% Release = %release% Typerelease = %release_type% @@ -47,7 +47,7 @@ Development mode = %devmode% Headless mode = %headless% Custom module support = %custommodules%""")) # Print hi - core.logger.info("Hi there!") + core.logger.info("Test.gd", "Hi there!") # Update CORE configuration func configure_core() -> void: diff --git a/docs/docs/getting-started/initializing-core.md b/docs/docs/getting-started/initializing-core.md index 358def6..670ab56 100644 --- a/docs/docs/getting-started/initializing-core.md +++ b/docs/docs/getting-started/initializing-core.md @@ -36,10 +36,10 @@ func _ready() -> void: # Print "Hello World!" to console with all possible 'LoggerLevel''s for type in CoreTypes.LoggerLevel: - if type == "NONE": continue # Exclude "NONE" logger level - type = StringName(type.to_lower()) # Convert to StringName - logger.call(type, "Hello World!") # Call it + if type == "NONE": continue # Exclude "NONE" logger level + type = StringName(type.to_lower()) # Convert to StringName + logger.call(type, "/path/to/script.gd", "Hello World!") # Call it # Test crash - logger.crash("This is a test crash.") + logger.crash("/path/to/script.gd", "This is a test crash.") ``` diff --git a/docs/docs/reference/logger.md b/docs/docs/reference/logger.md index 497aa07..48fe97a 100644 --- a/docs/docs/reference/logger.md +++ b/docs/docs/reference/logger.md @@ -16,17 +16,17 @@ Emitted on any log call, permitted or not. \ ## Functions ### *bool* is_level_allowed(*CoreTypes.LoggerLevel* level) Checks if the specified log level is permitted by the current configuration. -### *void* diag(*String* message) +### *void* diag(*String* origin, *String* message) Prints a diagnostic message -### *void* verb(*String* message) +### *void* verb(*String* origin, *String* message) Prints a verbose message -### *void* info(*String* message) -Prints a informational message -### *void* warn(*String* message) +### *void* info(*String* origin, *String* message) +Prints an informational message +### *void* warn(*String* origin, *String* message) Prints a warning message -### *void* error(*String* message) +### *void* error(*String* origin, *String* message) Prints an error message -### *void* crash(*String* message, *bool* framework_crash = *false*) +### *void* crash(*String* origin, *String* message, *bool* framework_crash = *false*) :::note[Awaiting required] Using the `await` keyword is required for this function. ::: diff --git a/src/classes/config.gd b/src/classes/config.gd index 770e94b..b69f180 100644 --- a/src/classes/config.gd +++ b/src/classes/config.gd @@ -56,7 +56,7 @@ func _init() -> void: # Logger logger_level = CoreTypes.LoggerLevel.INFO logger_colored = true - logger_format = "%color%[%time%] [%level% %source%:%line%] %message%" + logger_format = "%color%[%time%] [%level% %origin%] %message%" logger_newlines_override = true logger_newlines_sizelimit = 40 # LogUI diff --git a/src/core.gd b/src/core.gd index 5742a95..ddfd76a 100644 --- a/src/core.gd +++ b/src/core.gd @@ -69,7 +69,7 @@ func _ready() -> void: inject_modules() custom_modules_node.name = "Custom Modules" add_child(custom_modules_node) - logger.info("Initialized CORE successfully") + logger.infof("core.gd", "Initialized CORE successfully") # Initialize modules ## Initializes all modules during the first initialization phase.[br] @@ -121,30 +121,30 @@ func inject_modules() -> void: # Registers a custom module ## Registers a new custom module. func register_custom_module(module_name: String, module_class: CoreBaseModule) -> bool: - logger.verb("Registering new custom module \"" + module_name + "\"") + logger.verbf("core.gd", "Registering new custom module \"" + module_name + "\"") if !config.custom_modules: - logger.error("Registering module failed: Custom module support is disabled.") + logger.errorf("core.gd", "Registering module failed: Custom module support is disabled.") return false if custom_modules.has(module_name): - logger.error("Registering module failed: A custom module with the name \"" + module_name + "\" already exists.") + logger.errorf("core.gd", "Registering module failed: A custom module with the name \"" + module_name + "\" already exists.") return false module_class.name = module_name - logger.diag("Adding module to SceneTree") + logger.diagf("core.gd", "Adding module to SceneTree") custom_modules_node.add_child(module_class) - logger.diag("Merging module with custom_modules") + logger.diagf("core.gd", "Merging module with custom_modules") custom_modules.merge({ module_name: module_class }) - logger.diag("Initializing custom module") + logger.diagf("core.gd", "Initializing custom module") module_class._initialize() - logger.diag("Updating custom module configuration") + logger.diagf("core.gd", "Updating custom module configuration") module_class._pull_config() return true # Unregisters a custom module ## Unregisters a custom module, making it no longer function. func unregister_custom_module(module_name: String) -> void: - logger.verb("Unregistering custom module \"" + module_name + "\"") + logger.verbf("core.gd", "Unregistering custom module \"" + module_name + "\"") if !custom_modules.has(module_name): - logger.error("Unregistering module failed: A custom module with the name \"" + module_name + "\" does not exist.") + logger.errorf("core.gd", "Unregistering module failed: A custom module with the name \"" + module_name + "\" does not exist.") return custom_modules_node.remove_child(get_custom_module(module_name)) custom_modules.erase(module_name) @@ -152,9 +152,9 @@ func unregister_custom_module(module_name: String) -> void: # Returns a custom module ## Returns a loaded custom module for access. func get_custom_module(module_name: String) -> CoreBaseModule: - logger.diag("Getting custom module \"" + module_name + "\"") + logger.diagf("core.gd", "Getting custom module \"" + module_name + "\"") if !custom_modules.has(module_name): - logger.error("Getting module failed: A custom module with the name \"" + module_name + "\" does not exist.") + logger.errorf("core.gd", "Getting module failed: A custom module with the name \"" + module_name + "\" does not exist.") return return custom_modules[module_name] @@ -162,11 +162,11 @@ func get_custom_module(module_name: String) -> CoreBaseModule: ## Loads a (new) configuration file and applies it to all modules. func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new()) -> void: var initialized = config != null - if initialized: logger.verb("Reloading CORE's configuration") + if initialized: logger.verbf("core.gd", "Reloading CORE's configuration") config = new_config if is_devmode(): # Override configuration in development mode config.logger_level = CoreTypes.LoggerLevel.VERB - if initialized: logger.verb("Overrode configuration (development mode)") + if initialized: logger.verbf("core.gd", "Overrode configuration (development mode)") if initialized: apply_configuration() # Call _pull_config() functions @@ -174,12 +174,12 @@ func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new( ## [br] ## [b]NEVER call this yourself unless you know what you are doing![/b] func apply_configuration() -> void: - logger.verb("Applying configuration") - if is_devmode(): logger.warn("The CORE Framework is in development mode. Here be dragons!") - if config.headless: logger.warn("CORE is in headless mode. Certain modules will not work as expected.") + logger.verbf("core.gd", "Applying configuration") + if is_devmode(): logger.warnf("core.gd", "The CORE Framework is in development mode. Here be dragons!") + if config.headless: logger.warnf("core.gd", "CORE is in headless mode. Certain modules will not work as expected.") edl._pull_config() if !config.custom_modules: - logger.verb("Removing all custom modules (custom modules support is disabled)") + logger.verbf("core.gd", "Removing all custom modules (custom modules support is disabled)") for module in custom_modules: unregister_custom_module(module) logger._pull_config() misc._pull_config() @@ -187,7 +187,7 @@ func apply_configuration() -> void: logui._pull_config() if config.custom_modules: for module in custom_modules: - logger.diag("Updating configuration for custom module \"" + module.name + "\"") + logger.diagf("core.gd", "Updating configuration for custom module \"" + module.name + "\"") module._pull_config() # Return development mode status @@ -223,7 +223,7 @@ func get_formatted_string(string: String) -> String: CoreTypes.VersionType.ALPHA: string = string.replace("%type%", "Alpha") string = string.replace("%type_technical%", "a") - _: await logger.crash("Invalid version type " + str(version_type), true) + _: await logger.crashf("core.gd", "Invalid version type " + str(version_type), true) # Development mode if is_devmode(): string = string.replace("%devmode%", "Enabled") else: string = string.replace("%devmode%", "Disabled") diff --git a/src/edl.gd b/src/edl.gd index 7317242..64fb7a7 100644 --- a/src/edl.gd +++ b/src/edl.gd @@ -27,48 +27,48 @@ var list_complete: Dictionary = {} func generate_id() -> int: var id = randi() if list_queue.has(id) or list_active.has(id): return generate_id() - logger.diag("Generated new download id " + str(id)) + logger.diagf("edl.gd", "Generated new download id " + str(id)) return id func awaited_request(url: String, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Dictionary: - logger.verb("Creating awaited request") + logger.verbf("edl.gd", "Creating awaited request") var id: int = create_download(url, method, headers, data) start_download(id) - logger.diag("Waiting for request " + str(id) + " to finish") + logger.diagf("edl.gd", "Waiting for request " + str(id) + " to finish") while !is_download_complete(id): await get_tree().create_timer(0.1, true).timeout var dldata: Dictionary = list_complete[id] list_complete.erase(id) return dldata func batch_awaited_request(urls: PackedStringArray, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Array[Dictionary]: - logger.verb("Creating " + str(urls.size()) + " awaited request(s)") + logger.verbf("edl.gd", "Creating " + str(urls.size()) + " awaited request(s)") var dldata: Array[Dictionary]= [] for url in urls: var id: int = create_download(url, method, headers, data) start_download(id) - logger.diag("Waiting for request " + str(id) + " to finish") + logger.diagf("edl.gd", "Waiting for request " + str(id) + " to finish") while !is_download_complete(id): await get_tree().create_timer(0.1, true).timeout dldata.append(list_complete[id]) list_complete.erase(id) return dldata func create_download(url: String, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), body: String = "") -> int: - logger.verb("Creating new request\n-> URL: " + url + "\n-> Method: " + str(method) + "\nHeaders:\n" + str(headers) + "\nBody:\n" + body) + logger.verbf("edl.gd", "Creating new request\n-> URL: " + url + "\n-> Method: " + str(method) + "\nHeaders:\n" + str(headers) + "\nBody:\n" + body) var id = generate_id() list_queue.merge({ id: { "url": url, "method": method, "headers": headers, "body": body } }) return id func start_download(id) -> void: - logger.verb("Starting request " + str(id)) + logger.verbf("edl.gd", "Starting request " + str(id)) list_active.merge({ id: list_queue[id] }) list_queue.erase(id) - logger.diag("Creating new HTTPRequest \"Request #" + str(id) + "\"") + logger.diagf("edl.gd", "Creating new HTTPRequest \"Request #" + str(id) + "\"") var download: HTTPRequest = HTTPRequest.new() download.name = "Request #" + str(id) download.accept_gzip = true download.use_threads = true var lambda: Callable = func(result: int, http_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: - logger.verb("Request " + str(id) + " completed\nResult: " + str(result) + "\nHTTP response code: " + str(http_code) + "\nHeaders:\n" + str(headers) + "\nBody size: " + str(body.size()) + " Bytes // " + str(core.misc.byte2mib(body.size(), true)) + " MiB") + logger.verbf("edl.gd", "Request " + str(id) + " completed\nResult: " + str(result) + "\nHTTP response code: " + str(http_code) + "\nHeaders:\n" + str(headers) + "\nBody size: " + str(body.size()) + " Bytes // " + str(core.misc.byte2mib(body.size(), true)) + " MiB") list_complete.merge({ id: { "result": result, "http_code": http_code, "headers": headers, "body": body, "body_utf8": body.get_string_from_utf8() } }) list_active.erase(id) download.connect("request_completed", lambda) @@ -78,9 +78,9 @@ func start_download(id) -> void: func is_download_complete(id: int) -> bool: return list_complete.has(id) func clean_queue() -> void: - logger.verb("Cleaning request queue") + logger.verbf("edl.gd", "Cleaning request queue") list_queue.clear() func clean_completed() -> void: - logger.verb("Cleaning completed requests") + logger.verbf("edl.gd", "Cleaning completed requests") list_complete.clear() diff --git a/src/logger.gd b/src/logger.gd index cfda987..148e04d 100644 --- a/src/logger.gd +++ b/src/logger.gd @@ -40,18 +40,14 @@ func _pull_config() -> void: config_newlines_sizelimit = core.config.logger_newlines_sizelimit # Creates log messages -func _log(level: CoreTypes.LoggerLevel, message: String) -> void: - var origin: Dictionary = get_origin() +func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void: if !is_level_allowed(level): emit_signal("log_event", false, level, origin, message, "") return var format: String = config_format format = format.replace("%time_ms%", str(Time.get_ticks_msec())) format = format.replace("%time%", Time.get_time_string_from_system(true)) - format = format.replace("%source%", origin["source_clean"]) - format = format.replace("%source_raw%", origin["source"]) - format = format.replace("%function%", origin["function"]) - format = format.replace("%line%", str(origin["line"])) + format = format.replace("%origin%", origin) var format_newline: String = format.replace("%color%", "").replace("%message%", "") if !config_colored: format = format.replace("%color%", "") match(level): @@ -86,35 +82,29 @@ func _log(level: CoreTypes.LoggerLevel, message: String) -> void: if config_colored: print_rich(format) else: print(format) -# Get function caller -func get_origin(n: int = 1) -> Dictionary: - var stack: Dictionary = get_stack()[2+n] - return { "source": stack["source"], "source_clean": stack["source"].replace("res://", "").replace("user://", ""), "function": stack["function"], "line": stack["line"] } - # Check if level is allowed func is_level_allowed(level: CoreTypes.LoggerLevel) -> bool: if level <= config_level: return true else: return false # Self explanitory -func diag(message: String) -> void: _log(CoreTypes.LoggerLevel.DIAG, message) -func verb(message: String) -> void: _log(CoreTypes.LoggerLevel.VERB, message) -func info(message: String) -> void: _log(CoreTypes.LoggerLevel.INFO, message) -func warn(message: String) -> void: _log(CoreTypes.LoggerLevel.WARN, message) -func error(message: String) -> void: _log(CoreTypes.LoggerLevel.ERROR, message) +func diag(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.DIAG, origin, message) +func verb(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.VERB, origin, message) +func info(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.INFO, origin, message) +func warn(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.WARN, origin, message) +func error(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.ERROR, origin, message) # Built-in crash handler for CORE and applications using it -func crash(_message: String, framework_crash: bool = false) -> void: +func crash(origin: String, message: String, framework_crash: bool = false) -> void: # Collect information var stack: Array[Dictionary] = get_stack() - var origin: Dictionary = get_origin(0) var mem_info: Dictionary = OS.get_memory_info() var crash_message: String = """Generating crash report... ###################################### ### CORE CRASH HANDLER ### ###################################### %causer% inflicted a crash! -%script% (func %function%, line %line%) issues: +%origin% says: %message% +++ CORE INFORMATION +++ @@ -162,10 +152,8 @@ STACKTRACE # Replace placeholders if framework_crash: crash_message = crash_message.replace("%causer%", "The CORE Framework") else: crash_message = crash_message.replace("%causer%", "The running application") - crash_message = crash_message.replace("%script%", origin["source_clean"]) - crash_message = crash_message.replace("%function%", origin["function"]) - crash_message = crash_message.replace("%line%", str(origin["line"])) - crash_message = crash_message.replace("%message%", _message) + crash_message = crash_message.replace("%origin%", origin) + crash_message = crash_message.replace("%message%", message) crash_message = crash_message.replace("%version_release%", str(core.version_release)) crash_message = crash_message.replace("%version_type%", await core.get_formatted_string("%type%")) crash_message = crash_message.replace("%version_typerelease%", str(core.version_typerelease)) @@ -194,6 +182,14 @@ STACKTRACE config_newlines_override = true config_newlines_sizelimit = -1 # Print crash message - _log(CoreTypes.LoggerLevel.NONE, crash_message) + _log(CoreTypes.LoggerLevel.NONE, origin, crash_message) # Shutdown await core.misc.quit_safely(69) + +# Makes CORE development easier +func diagf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.DIAG, core.basepath.replace("res://", "") + "src/" + origin, message) +func verbf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.VERB, core.basepath.replace("res://", "") + "src/" + origin, message) +func infof(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.INFO, core.basepath.replace("res://", "") + "src/" + origin, message) +func warnf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.WARN, core.basepath.replace("res://", "") + "src/" + origin, message) +func errorf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.ERROR, core.basepath.replace("res://", "") + "src/" + origin, message) +func crashf(origin: String, message: String) -> void: crash(core.basepath.replace("res://", "") + "src/" + origin, message) diff --git a/src/logui.gd b/src/logui.gd index 683e856..a01f66d 100644 --- a/src/logui.gd +++ b/src/logui.gd @@ -77,7 +77,7 @@ func _ready() -> void: vsbar.add_theme_stylebox_override("grabber_highlight", StyleBoxEmpty.new()) vsbar.add_theme_stylebox_override("grabber_pressed", StyleBoxEmpty.new()) # Connect log_event - logger.connect("log_event", func(allowed: bool, _level: CoreTypes.LoggerLevel, _origin: Dictionary, _message: String, format: String) -> void: if allowed: logrtl.text = logrtl.text + format + "\n") + logger.connect("log_event", func(allowed: bool, _level: CoreTypes.LoggerLevel, _origin: String, _message: String, format: String) -> void: if allowed: logrtl.text = logrtl.text + format + "\n") func _process(_delta: float) -> void: if !core.config.headless: diff --git a/src/misc.gd b/src/misc.gd index 13cd215..7e6b572 100644 --- a/src/misc.gd +++ b/src/misc.gd @@ -22,8 +22,8 @@ extends CoreBaseModule func quit_safely(exitcode: int = 0) -> void: - logger.info("Shutting down (code " + str(exitcode) + ")") - logger.diag("Waiting for log messages to be flushed") + logger.infof("misc.gd", "Shutting down (code " + str(exitcode) + ")") + logger.diagf("misc.gd", "Waiting for log messages to be flushed") await get_tree().create_timer(0.25).timeout get_tree().quit(exitcode) diff --git a/src/sms.gd b/src/sms.gd index 849c735..a8e6bde 100644 --- a/src/sms.gd +++ b/src/sms.gd @@ -45,15 +45,15 @@ func _initialize() -> void: func _pull_config() -> void: if core.config.headless: # Remove all scenes - logger.verb("Removing all scenes (triggered by headless mode)") + logger.verbf("sms.gd", "Removing all scenes (triggered by headless mode)") for scene in scenes: remove_scene(scene, true) # Add a scene to some scene collection func add_scene(sname: String, type: CoreTypes.SceneType, sclass: Node) -> bool: if core.config.headless: return false - logger.verb("Adding scene \"" + sname + "\" of type " + str(type)) + logger.verbf("sms.gd", "Adding scene \"" + sname + "\" of type " + str(type)) if exists(sname) != CoreTypes.SceneType.NONE: - logger.error("Scene with name \"" + sname + "\" already exists") + logger.errorf("sms.gd", "Scene with name \"" + sname + "\" already exists") return true sclass.name = sname match(type): @@ -63,17 +63,17 @@ func add_scene(sname: String, type: CoreTypes.SceneType, sclass: Node) -> bool: CoreTypes.SceneType.MAIN: scenes_main.add_child(sclass) CoreTypes.SceneType.BACKGROUND: scenes_background.add_child(sclass) CoreTypes.SceneType.NONE: - logger.error("CoreTypes.SceneType.NONE is not a valid scene type") + logger.errorf("sms.gd", "CoreTypes.SceneType.NONE is not a valid scene type") return false - _: await logger.crash("Invalid SceneType " + str(type), true) + _: await logger.crashf("sms.gd", "Invalid SceneType " + str(type), true) scenes.merge({ sname: { "type": type, "class": sclass } }) return true # Remove a scene from some scene collection func remove_scene(sname: String, force_remove: bool = false) -> bool: if core.config.headless and !force_remove: return false - if force_remove: await logger.crash("force_remove = true is not allowed", true) - logger.verb("Removing scene \"" + sname + "\"") + if force_remove: await logger.crashf("sms.gd", "force_remove = true is not allowed", true) + logger.verbf("sms.gd", "Removing scene \"" + sname + "\"") match(exists(sname)): CoreTypes.SceneType.DEBUG: scenes_debug.remove_child(scenes[sname]["class"]) CoreTypes.SceneType.CUTSCENE: scenes_cutscene.remove_child(scenes[sname]["class"]) @@ -81,9 +81,9 @@ func remove_scene(sname: String, force_remove: bool = false) -> bool: CoreTypes.SceneType.MAIN: scenes_main.remove_child(scenes[sname]["class"]) CoreTypes.SceneType.BACKGROUND: scenes_background.remove_child(scenes[sname]["class"]) CoreTypes.SceneType.NONE: - logger.error("Scene \"" + sname + "\" does not exist") + logger.errorf("sms.gd", "Scene \"" + sname + "\" does not exist") return false - _: await logger.crash("Invalid SceneType " + str(exists(sname)), true) + _: await logger.crashf("sms.gd", "Invalid SceneType " + str(exists(sname)), true) scenes.erase(sname) return true @@ -96,8 +96,8 @@ func get_scene(sname: String) -> Node: CoreTypes.SceneType.MENU: return scenes[sname]["class"] CoreTypes.SceneType.MAIN: return scenes[sname]["class"] CoreTypes.SceneType.BACKGROUND: return scenes[sname]["class"] - CoreTypes.SceneType.NONE: logger.error("Scene \"" + sname + "\" does not exist") - _: await logger.crash("Invalid SceneType " + str(exists(sname)), true) + CoreTypes.SceneType.NONE: logger.errorf("sms.gd", "Scene \"" + sname + "\" does not exist") + _: await logger.crashf("sms.gd", "Invalid SceneType " + str(exists(sname)), true) return null # Return a scene collection for scene manipulation @@ -109,8 +109,8 @@ func get_scene_collection(type: CoreTypes.SceneType) -> Node: CoreTypes.SceneType.MENU: return scenes_menu CoreTypes.SceneType.MAIN: return scenes_main CoreTypes.SceneType.BACKGROUND: return scenes_background - CoreTypes.SceneType.NONE: logger.error("No scene collection was found for CoreTypes.SceneType.NONE") - _: await logger.crash("Invalid SceneType " + str(type), true) + CoreTypes.SceneType.NONE: logger.errorf("sms.gd", "No scene collection was found for CoreTypes.SceneType.NONE") + _: await logger.crashf("sms.gd", "Invalid SceneType " + str(type), true) return null # Return scenes in some scene collection