Рефактор

This commit is contained in:
sasha80
2023-07-25 08:46:38 +03:00
parent c1d135eaed
commit f6baa951fc
11 changed files with 446 additions and 6 deletions

7
addons/godot-logger/.gitattributes vendored Normal file
View File

@@ -0,0 +1,7 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf
/.gitattributes export-ignore
/.gitignore export-ignore
/README.md export-ignore
/LICENSE.md export-ignore

3
addons/godot-logger/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Godot auto generated files
*.import
/.idea/

View File

@@ -0,0 +1,21 @@
# MIT License
Copyright (c) 2020-2023 Mansur Isaev and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,60 @@
# Godot-Log
Simple in-game logger for Godot 4.0.
![](https://user-images.githubusercontent.com/8208165/144706770-e4fda4c0-249b-4851-b7a8-8d0bc3d278bc.png)
# Features
- Installed as plugin.
- Singleton Log.
- Write to log file.
- Disable log levels.
- Custom log levels.
# Installation:
1. Clone or download this repository to `addons` folder.
2. Enable `Godot Log` in Plugins.
3. Add `LogOutput` node to the scene.
4. Profit.
# Usage:
## Calling default levels:
```gdscript
Log.info(text)
Log.debug(text)
Log.warning(text)
Log.error(text)
Log.fatal(text)
```
## Create a custom log level:
```gdscript
# main.gd
const CUSTOM = Log.MAX << 1 # Bitwise left shift the MAX value for a custom level.
func _ready() -> void:
Log.add_level(CUSTOM, "Level Name")
```
## Calling the custom level:
```gdscript
Log.message(CUSTOM, "Something happened")
```
## Disable log level:
```gdscript
Log.set_level(Log.INFO, false) # Disable built-in level.
Log.set_level(CUSTOM, false) # Disable custom level.
```
## Enable log level:
```gdscript
Log.set_level(Log.DEBUG, true) # Enable built-in level.
Log.set_level(CUSTOM, true) # Enable custom level.
```
# License
Copyright (c) 2020-2023 Mansur Isaev and contributors
Unless otherwise specified, files in this repository are licensed under the
MIT license. See [LICENSE.md](LICENSE.md) for more information.

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="m3 1c-1.1046 0-2 0.8954-2 2v10c0 1.1046 0.89543 2 2 2h10c1.1046 0 2-0.8954 2-2v-10c0-1.1046-0.89543-2-2-2h-10zm4.3125 4.7793c0.39127 0 0.74441 0.085556 1.0625 0.25586 0.31809 0.1689 0.57062 0.41729 0.75781 0.74805 0.18719 0.32935 0.28125 0.73544 0.28125 1.2168s-0.094058 0.888-0.28125 1.2188c-0.18719 0.32935-0.43973 0.57774-0.75781 0.74805-0.31809 0.1689-0.67123 0.25391-1.0625 0.25391-0.39409 0-0.75027-0.085556-1.0684-0.25586-0.31668-0.17171-0.56867-0.42065-0.75586-0.75-0.18578-0.33075-0.2793-0.73631-0.2793-1.2148 0-0.48135 0.093512-0.88745 0.2793-1.2168 0.18719-0.33075 0.43918-0.57915 0.75586-0.74805 0.31809-0.1703 0.67427-0.25586 1.0684-0.25586zm4.7363 0c0.34061 0 0.64992 0.063327 0.92578 0.19141 0.27586 0.12667 0.49821 0.3016 0.66992 0.52539 0.17312 0.22238 0.27513 0.47959 0.30469 0.76953h-1.1855c-0.035187-0.14778-0.11279-0.26157-0.23242-0.3418-0.11963-0.081633-0.27265-0.12305-0.45703-0.12305-0.29557 1e-7 -0.52369 0.10474-0.68555 0.31445-0.16186 0.20971-0.24219 0.50257-0.24219 0.87695 0 0.38001 0.075648 0.67615 0.23047 0.88867s0.38544 0.31836 0.68945 0.31836c0.2632 0 0.46145-0.054826 0.59375-0.16602 0.13371-0.11119 0.20336-0.26257 0.20898-0.45117h-0.78516v-0.83594h1.916v0.59961c0 0.39409-0.084465 0.73163-0.25195 1.0117-0.16608 0.27868-0.39475 0.49339-0.6875 0.64258-0.29134 0.14778-0.62475 0.2207-1.002 0.2207-0.42083 0-0.79129-0.08883-1.1094-0.26758-0.31809-0.17875-0.56735-0.43292-0.74609-0.76367-0.17734-0.33075-0.26562-0.72562-0.26562-1.1816 0-0.47572 0.095149-0.87878 0.28516-1.2109 0.19001-0.33216 0.44613-0.58469 0.76562-0.75781s0.67209-0.25977 1.0605-0.25977zm-10.049 0.058594h1.1738v3.3789h1.748v0.94531h-2.9219v-4.3242zm5.3125 0.96289c-0.29134 1e-7 -0.51456 0.1031-0.66797 0.30859-0.15201 0.20549-0.22852 0.50217-0.22852 0.89062s0.07651 0.68514 0.22852 0.89062c0.15341 0.20549 0.37662 0.30859 0.66797 0.30859 0.29134 0 0.51206-0.1031 0.66406-0.30859 0.15341-0.20549 0.23047-0.50217 0.23047-0.89062s-0.077055-0.68514-0.23047-0.89062c-0.15201-0.20549-0.37272-0.30859-0.66406-0.30859z" fill="#a5efac"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,7 @@
[plugin]
name="Godot Log"
description="Simple in-game Logger"
author="Mansur Isaev"
version="0.7"
script="plugin.gd"

View File

@@ -0,0 +1,49 @@
# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends EditorPlugin
const AUTOLOAD_NAME = "Log"
const AUTOLOAD_PATH = "res://addons/godot-logger/scripts/logger.gd"
const LOGGER_OUTPUT = "LoggerOutput"
const LOGGER_OUTPUT_SCRIPT = "res://addons/godot-logger/scripts/logger_output.gd"
const LOGGER_OUTPUT_ICON = "res://addons/godot-logger/icons/logger.svg"
func _def_settings(name: String, default: Variant) -> void:
if not ProjectSettings.has_setting(name):
ProjectSettings.set_setting(name, default)
ProjectSettings.set_initial_value(name, default)
func _enter_tree() -> void:
_def_settings("plugins/logger/log_enabled", true)
_def_settings("plugins/logger/default_output", false)
_def_settings("plugins/logger/level", 31) # The magic number is - INFO | DEBUG | WARNING | ERROR | FATAL
ProjectSettings.add_property_info(
{
"name": "plugins/logger/level",
"type": TYPE_INT,
"hint": PROPERTY_HINT_FLAGS,
"hint_string": "Info,Debug,Warning,Error,Fatal",
}
)
_def_settings("plugins/logger/file/file_path", "user://uarep-ctl.log")
_def_settings("plugins/logger/file/log_file_write", true)
_def_settings("plugins/logger/default_output_format", "[{hour}:{minute}:{second}][{level}]{text}")
_def_settings("plugins/logger/file_format", "[{hour}:{minute}:{second}][{level}]{text}")
add_autoload_singleton(AUTOLOAD_NAME, AUTOLOAD_PATH)
add_custom_type(LOGGER_OUTPUT, "RichTextLabel", load(LOGGER_OUTPUT_SCRIPT), load(LOGGER_OUTPUT_ICON))
func _exit_tree() -> void:
remove_custom_type(LOGGER_OUTPUT)
remove_autoload_singleton(AUTOLOAD_NAME)

View File

@@ -0,0 +1,218 @@
# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License
# See `LICENSE.md` included in the source distribution for details.
## Logger class.
class_name Logger
extends Node
## Emitted when the logger create a message.
signal logged(message: Dictionary)
enum {
INFO = 1, ## Info level.
DEBUG = 1<<1, ## Warning level.
WARNING = 1<<2, ## Debug level.
ERROR = 1<<3, ## Error level.
FATAL = 1<<4, ## Fatal level.
MAX = FATAL, ## Bitwise left shift for custom levels.
}
var _level : int
var _log_enabled : bool
var _default_output_enabled : bool
var _file_write_enabled : bool
var _file : FileAccess
var _file_path : String
var _format_default_output : String
var _format_file : String
var _names = {
INFO: "INFO",
DEBUG: "DEBUG",
WARNING: "WARNING",
ERROR: "ERROR",
FATAL: "FATAL"
}
# Can be overridden to define custom default values.
func _enter_tree() -> void:
set_log_enabled(ProjectSettings.get_setting("plugins/logger/log_enabled", true))
set_default_output_enabled(ProjectSettings.get_setting("plugins/logger/default_output", false))
_level = ProjectSettings.get_setting("plugins/logger/level", INFO | DEBUG | WARNING | ERROR | FATAL)
set_file_path(ProjectSettings.get_setting("plugins/logger/file/file_path", "user://uarep-ctl.log"))
set_file_write_enabled(ProjectSettings.get_setting("plugins/logger/file/log_file_write", true))
_format_default_output = ProjectSettings.get_setting("plugins/logger/default_output_format", "[{hour}:{minute}:{second}][{level}]{text}")
_format_file = ProjectSettings.get_setting("plugins/logger/file_format", "[{hour}:{minute}:{second}][{level}]{text}")
func _exit_tree() -> void:
_close_file()
## Return [param true] if logger has level.
func has_level(level: int) -> bool:
return _names.has(level)
## Set the level enabled.
func set_level(level: int, enabled: bool) -> void:
assert(has_level(level), "Invalid level.")
if not has_level(level):
return
if enabled:
_level |= level
else:
_level &= ~level
## Add a custom log level. The level value must be unique and be greater than [member MAX].
## To call the custom level use [method message] method.
func add_level(level: int, nm: String) -> void:
assert(not has_level(level), "Has level.")
assert(level > MAX and not level % 2, "Invalid level.")
assert(name, "Invalid name.")
if not has_level(level) and level > MAX and not level % MAX and not name.is_empty():
_names[level] = name
set_level(level, true)
## Return the level name.
func get_level_name(level: int) -> String:
return _names[level]
## Set Log enabled. Disable ALL messages.
func set_log_enabled(enabled: bool) -> void:
_log_enabled = enabled
## Return [param true] if Log enabled.
func is_log_enabled() -> bool:
return _log_enabled
## Set default output enabled.
func set_default_output_enabled(enabled: bool) -> void:
_default_output_enabled = enabled
## Returns [param true] if default output is enabled.
func is_default_output_enabled() -> bool:
return _default_output_enabled
## Set file write enabled.
func set_file_write_enabled(enabled: bool) -> void:
if _file_write_enabled == enabled:
return
_file_write_enabled = enabled
if enabled:
_open_file()
else:
_close_file()
## Returns [param true] if write to a file is enabled.
func is_file_write_enabled() -> bool:
return _file_write_enabled
## Set the path to the log file.
func set_file_path(path: String) -> void:
assert(path.is_absolute_path(), "Invalid path.")
if not path.is_absolute_path() or _file_path == path:
return
_file_path = path
if is_file_write_enabled():
_open_file()
## Return path to log file.
func get_file_path() -> String:
return _file_path
## Create an info message.
func info(text: String) -> void:
message(INFO, text)
## Create a debug message. Debug build only.
func debug(text: String) -> void:
if OS.is_debug_build():
message(DEBUG, text)
## Create a warning message.
func warning(text: String) -> void:
message(WARNING, text)
## Create an error message.
func error(text: String) -> void:
message(ERROR, text)
## Create a fatal error message.
func fatal(text: String) -> void:
message(FATAL, text)
## Format string for log file.
func format_file(msg: Dictionary) -> String:
return _format_file.format(
{
"hour": "%02d" % msg["hour"],
"minute":"%02d" % msg["minute"],
"second":"%02d" % msg["second"],
"level": _names[msg["level"]],
"text": msg["text"],
}
)
## Format string for editor output.
func format_stdout(msg: Dictionary) -> String:
return _format_default_output.format(
{
"hour": "%02d" % msg["hour"],
"minute":"%02d" % msg["minute"],
"second":"%02d" % msg["second"],
"level": _names[msg["level"]],
"text": msg["text"],
}
)
## Create a message with a custom level.
func message(level: int, text: String) -> void:
assert(has_level(level), "Has not level.")
assert(text, "Invalid message text.")
if _log_enabled and _level & level:
var msg : Dictionary = Time.get_time_dict_from_system()
msg["level"] = level
msg["level_name"] = _names[level]
msg["text"] = text
logged.emit(msg)
if _file_write_enabled:
_file.store_line(format_file(msg))
if _default_output_enabled:
print(format_stdout(msg))
func _open_file() -> void:
if is_instance_valid(_file) and _file.is_open():
_file.close()
_file = FileAccess.open(get_file_path(), FileAccess.WRITE)
var err := FileAccess.get_open_error()
if err:
return print_debug(error_string(err))
err = _file.get_error()
if err:
return print_debug(error_string(err))
func _close_file() -> void:
if is_instance_valid(_file) and _file.is_open():
_file = null

View File

@@ -0,0 +1,76 @@
# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
## LoggerOutput class.
class_name LoggerOutput
extends RichTextLabel
## Emited when handle [signal Logger.logged] signal.
signal handled()
@export var format_text : String = "[{hour}:{minute}:{second}][{level}]{text}"
@export var colors : Dictionary = {
Logger.INFO: Color.WHITE,
Logger.DEBUG: Color.GRAY,
Logger.WARNING: Color.YELLOW,
Logger.ERROR: Color.RED,
Logger.FATAL: Color.RED,
}
var _logger : Logger
func _enter_tree() -> void:
var logger := get_node_or_null("/root/Log") as Logger
if is_instance_valid(logger):
set_logger(logger)
func _exit_tree() -> void:
if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message):
_logger.logged.disconnect(handle_message)
## Return the level color or [member Color.WHITE].
func get_color(level: int) -> Color:
return colors.get(level, Color.WHITE)
## Set the logger.
func set_logger(logger: Logger) -> void:
assert(is_instance_valid(logger), "Invalid Logger.")
if not is_instance_valid(logger) or is_same(_logger, logger):
return
if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message):
_logger.logged.disconnect(handle_message)
if not logger.logged.is_connected(handle_message):
logger.logged.connect(handle_message)
_logger = logger
## Return the logger.
func get_logger() -> Logger:
return _logger
## Return formatted string from message.
func format(message: Dictionary) -> String:
return format_text.format(
{
"hour": "%02d" % message["hour"],
"minute": "%02d" % message["minute"],
"second": "%02d" % message["second"],
"level": message["level_name"],
"text": message["text"],
}
)
## Handle the message.
func handle_message(message: Dictionary) -> void:
push_color(get_color(message["level"]))
append_text(format(message) + "\n")
pop()
handled.emit()