├── Logging.png ├── plugin.cfg ├── Logger.gd ├── .gitignore ├── example ├── Example Logging.tscn └── Example Logging.gd ├── Logging.png.import ├── LICENSE ├── README.md └── log_base.gd /Logging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Beanzilla/Logger/HEAD/Logging.png -------------------------------------------------------------------------------- /plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="Logger" 4 | description="A filebased logging plugin." 5 | author="ApolloX" 6 | version="1.2" 7 | script="Logger.gd" 8 | -------------------------------------------------------------------------------- /Logger.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends EditorPlugin 3 | 4 | func _enter_tree(): 5 | add_custom_type("Logger", "Node", preload("log_base.gd"), preload("Logging.png")) 6 | 7 | func _exit_tree(): 8 | remove_custom_type("Logger") 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot/ 3 | 4 | # Godot-specific ignores 5 | .import/ 6 | export.cfg 7 | export_presets.cfg 8 | 9 | # Imported translations (automatically generated from CSV files) 10 | *.translation 11 | 12 | # Mono-specific ignores 13 | .mono/ 14 | data_*/ 15 | mono_crash.*.json 16 | 17 | # Exclude .log files 18 | *.log -------------------------------------------------------------------------------- /example/Example Logging.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://addons/Logger/log_base.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/Logger/example/Example Logging.gd" type="Script" id=2] 5 | 6 | [node name="Example Logging" type="Node2D"] 7 | position = Vector2( 250, 250 ) 8 | script = ExtResource( 2 ) 9 | 10 | [node name="Logger" type="Node" parent="."] 11 | script = ExtResource( 1 ) 12 | __meta__ = { 13 | "_editor_description_": "Logger V1.0 ApolloX" 14 | } 15 | persist_debug = false 16 | file_dir = "res://addons/Logger/example/" 17 | -------------------------------------------------------------------------------- /Logging.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/Logging.png-4515a13ab4998ab99f08b72db994dc6b.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/Logger/Logging.png" 13 | dest_files=[ "res://.import/Logging.png-4515a13ab4998ab99f08b72db994dc6b.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Beanzilla 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/Example Logging.gd: -------------------------------------------------------------------------------- 1 | extends Node2D 2 | 3 | # Obtain access to my plugin 4 | onready var Log = $Logger 5 | 6 | # Some example calls 7 | func _ready(): 8 | # Standard calls with no secondary parameter 9 | Log.debug("This is a debug statement") 10 | Log.info("Information is ready") 11 | Log.warn("Warning thrown") # Note: I could have also used Log.warning("Warning msg is same") 12 | # More advanced calls with a second parameter (Decides to exit/end the progam 13 | # This is calling error and setting it's auto_exit to false (it's default for errors) 14 | Log.error("Failed obtaining acorns from squirrel army", false) 15 | # This is calling critical (or crit) with it's default auto_exit setting (critical/crit will automatically exit) 16 | Log.critical("This will auto exit after called", true) # Change to false to continue the program 17 | printerr("This only goes to the console") 18 | 19 | # Logger also includes some assistant functions 20 | print("Current datetime stamp: ", Log.timestamp("{month}/{day}/{year} {12hour}:{min}:{sec} {ampm}")) # I.E. '01/01/2000 01:53:22 AM' 21 | print("Position of Example Logging node: ", Log.pos2str(self.position)) # This is so you can print positions 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Logger 2 | 3 | A filebased logging plugin, for [Godot](https://godotengine.org/) game engine. 4 | 5 | ## Setup 6 | 7 | Assuming you have this plugin installed into Godot. 8 | 9 | > Need help installing a plugin? Try [HERE](https://docs.godotengine.org/en/stable/tutorials/plugins/editor/installing_plugins.html) 10 | 11 | From there simply active the plugin, then add a Logger node to your scene. 12 | 13 | ## Configuration 14 | 15 | If you've used the Godot editor to create the Logger node then you can simply use the inspector. 16 | 17 | | Value | Type | Description | 18 | |------------|------------|-----------| 19 | | Persist Log | Bool | Does the log file get cleared on start of the scene/instance/use of logging? | 20 | | File Dir | String | The path to store the log file. | 21 | | File Name | String | The name of the log file. (See Format Template section for help on what {dt} means) | 22 | | File Name Time Format | String | Defines {dt} in File Name. (See Format Template section for help on what {dt} means) | 23 | | Formatting | String | The format of all logging lines (I.E. `09-01-2020 01:00:00 PM DEBUG A Debug Statement.`) | 24 | | Time Format | String | The format of {dt} for in Formatting. | 25 | | Debug | Bool | Do we log debug statements/calls. | 26 | | Info | Bool | Do we log info statements/calls. | 27 | | Warn | Bool | Do we log warn/warning statements/calls. | 28 | | error | Bool | Do we log error statements/calls. | 29 | | Crit | Bool | Do we log crit/critical statements/calls. | 30 | 31 | ## Format Template 32 | 33 | This allows fully customised log files. 34 | 35 | | Value | Description | 36 | |-------|-------------| 37 | | dt | Typically used to indicate date time stamp. (Once defined) 38 | | level | The logging level (DEBUG, INFO, WARN, ERROR, CRITICAL) 39 | | msg | The message passed to one of the logging statements/calls. 40 | | month | The current month as 2 digits. (I.E. January is `01`) 41 | | day | The current day as 2 digits. (I.E. First day of the month is `01`) 42 | | year | The current year as 4 digits. (I.E. 2000 is `2000`) 43 | | 24hour | The current hour as 24 hour (Millitary time), as 2 digits. (I.E. 1 PM is `13`) 44 | | 12hour | The current hour as 12 hour (Use `ampm` to add the AM/PM), as 2 digits. (I.E. 1 PM is `01`) 45 | | min | The current minute as 2 digits. (I.E. 5 minutes is `05`) 46 | | sec | The current second as 2 digits. (I.E. 2 seconds is `02`) 47 | | ampm | A string describing if it's AM or PM. (Only use with `12hour`, it will be invisible if no `12hour` in format) 48 | 49 | > dt is used to abreviate date time in File Name, and Formatting. 50 | 51 | ## Contact me 52 | 53 | Please leave an issue/bug report if anything goes wrong or you come up with some other suggestions/feature requests. 54 | 55 | ## Credits 56 | 57 | * `Logging.png` was based off of [Node](https://github.com/godotengine/godot/blob/master/editor/icons/Node.svg) from the Godot game engine. 58 | -------------------------------------------------------------------------------- /log_base.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Node 3 | 4 | var log_file = null 5 | export var persist_log = true # If false the log file gets cleared automatically every startup 6 | var logy = null 7 | 8 | export var file_dir = "res://" 9 | export var file_name = "{dt}.log" 10 | export var file_name_time_format = "{month}-{year}" 11 | export var formatting = "{dt} {level} {msg}" 12 | export var time_format = "{month}/{day}/{year} {24hour}:{min}:{sec}" 13 | 14 | # Allow toggling what you want 15 | export var DEBUG = true 16 | export var INFO = true 17 | export var WARN = true 18 | export var ERROR = true 19 | export var CRIT = true 20 | 21 | func _enter_tree(): 22 | logy = self 23 | editor_description = "Logger V1.3 ApolloX" 24 | logy.editor_description = "Logger V1.3 ApolloX" 25 | logy.setup() 26 | return logy 27 | 28 | func setup(): 29 | log_file = File.new() 30 | var dtnow = timestamp(file_name_time_format) 31 | if !log_file.file_exists(file_dir + file_name.format({"dt": dtnow})) or !persist_log: 32 | log_file.open(file_dir + file_name.format({"dt": dtnow}), File.WRITE) 33 | log_file.store_string("") # Fix issue where non-persistent would not reset properly 34 | log_file.close() 35 | log_file.open(file_dir + file_name.format({"dt": dtnow}), File.READ_WRITE) 36 | log_file.seek_end() 37 | else: 38 | log_file.open(file_dir + file_name.format({"dt": dtnow}), File.READ_WRITE) 39 | log_file.seek_end() 40 | 41 | # Assistant Functions 42 | func pos2str(pos: Vector2 = Vector2(0, 0)) -> String: 43 | return "(" + str(pos.x) + ", " + str(pos.y) + ")" 44 | 45 | func timestamp(fmat : String ="{month}/{day}/{year} {24hour}:{min}:{sec}", in_utc: bool = false): 46 | var t = OS.get_datetime(in_utc) 47 | var hour12 = t.hour 48 | var ampm = "" # Fill it in only if 12hour is requested 49 | if "12hour" in fmat: # Only use if 12hour is visible in formating 50 | ampm = "AM" 51 | if hour12 > 12: 52 | hour12 -= 12 53 | ampm = "PM" 54 | var result = fmat.format({"month": str(t.month).pad_zeros(2), "day": str(t.day).pad_zeros(2), "year": str(t.year).pad_zeros(4), "24hour": str(t.hour).pad_zeros(2), "12hour": str(hour12).pad_zeros(2), "min": str(t.minute).pad_zeros(2), "sec": str(t.second).pad_zeros(2), "ampm": str(ampm)}) 55 | return result 56 | 57 | func debug(msg : String): 58 | if DEBUG: 59 | var dt = timestamp(time_format) 60 | var line = formatting.format({"dt": dt, "level": "DEBUG ", "msg": msg}) 61 | if log_file != null: 62 | log_file.seek_end() 63 | log_file.store_string(line + "\n") 64 | log_file.flush() 65 | 66 | func info(msg : String): 67 | if INFO: 68 | var dt = timestamp(time_format) 69 | var line = formatting.format({"dt": dt, "level": "INFO ", "msg": msg}) 70 | if log_file != null: 71 | log_file.seek_end() 72 | log_file.store_string(line + "\n") 73 | log_file.flush() 74 | 75 | func warn(msg : String): 76 | if WARN: 77 | var dt = timestamp(time_format) 78 | var line = formatting.format({"dt": dt, "level": "WARN ", "msg": msg}) 79 | if log_file != null: 80 | log_file.seek_end() 81 | log_file.store_string(line + "\n") 82 | log_file.flush() 83 | 84 | func warning(msg : String): 85 | if WARN: 86 | warn(msg) 87 | 88 | func error(msg : String, and_exit: bool = false): 89 | if ERROR: 90 | var dt = timestamp(time_format) 91 | var line = formatting.format({"dt": dt, "level": "ERROR ", "msg": msg}) 92 | if log_file != null: 93 | log_file.seek_end() 94 | log_file.store_string(line + "\n") 95 | log_file.flush() 96 | if and_exit: 97 | var my_pid = OS.get_process_id() 98 | var _ec = OS.kill(my_pid) 99 | 100 | func crit(msg : String, and_exit: bool = true): 101 | if CRIT: 102 | var dt = timestamp(time_format) 103 | var line = formatting.format({"dt": dt, "level": "CRITICAL", "msg": msg}) 104 | if log_file != null: 105 | log_file.seek_end() 106 | log_file.store_string(line + "\n") 107 | log_file.flush() 108 | if and_exit: 109 | var my_pid = OS.get_process_id() 110 | var _ec = OS.kill(my_pid) 111 | 112 | func critical(msg : String, and_exit: bool = true): 113 | if CRIT: 114 | crit(msg, and_exit) 115 | --------------------------------------------------------------------------------