mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2025-12-15 13:00:07 +01:00
Add a custom logging demo (#1242)
This demo showcases a custom logger implementation, which runs in parallel to the built-in logging facilities (including file logging). The custom logger displays all messages printed by the engine in an in-game console.
This commit is contained in:
17
misc/custom_logging/README.md
Normal file
17
misc/custom_logging/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Custom Logging
|
||||
|
||||
This demo showcases a custom logger implementation, which runs in parallel
|
||||
with the built-in logging facilities (including file logging). The custom logger
|
||||
displays all messages printed by the engine in an in-game console.
|
||||
|
||||
See [Logging](https://docs.godotengine.org/en/latest/tutorials/scripting/logging.html)
|
||||
in the documentation for more information about configuring the engine's logging
|
||||
and writing custom loggers.
|
||||
|
||||
Language: GDScript
|
||||
|
||||
Renderer: Compatibility
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
72
misc/custom_logging/custom_logger_ui.gd
Normal file
72
misc/custom_logging/custom_logger_ui.gd
Normal file
@@ -0,0 +1,72 @@
|
||||
extends RichTextLabel
|
||||
|
||||
var logger := CustomLogger.new()
|
||||
|
||||
|
||||
# Custom loggers must be thread-safe, as they may be called from non-main threads.
|
||||
# We use `call_deferred()` to call methods on nodes to ensure they are modified
|
||||
# from the main thread, as thread guards could prevent the methods from being
|
||||
# called successfully otherwise.
|
||||
class CustomLogger extends Logger:
|
||||
func _log_message(message: String, _error: bool) -> void:
|
||||
CustomLoggerUI.get_node("Panel/RichTextLabel").call_deferred(&"append_text", message)
|
||||
|
||||
|
||||
func _log_error(
|
||||
function: String,
|
||||
file: String,
|
||||
line: int,
|
||||
code: String,
|
||||
rationale: String,
|
||||
_editor_notify: bool,
|
||||
error_type: int,
|
||||
script_backtraces: Array[ScriptBacktrace]
|
||||
) -> void:
|
||||
var prefix := ""
|
||||
# The column at which to print the trace. Should match the length of the
|
||||
# unformatted text above it.
|
||||
var trace_indent := 0
|
||||
|
||||
match error_type:
|
||||
ERROR_TYPE_ERROR:
|
||||
prefix = "[color=#f54][b]ERROR:[/b]"
|
||||
trace_indent = 6
|
||||
ERROR_TYPE_WARNING:
|
||||
prefix = "[color=#fd4][b]WARNING:[/b]"
|
||||
trace_indent = 8
|
||||
ERROR_TYPE_SCRIPT:
|
||||
prefix = "[color=#f4f][b]SCRIPT ERROR:[/b]"
|
||||
trace_indent = 13
|
||||
ERROR_TYPE_SHADER:
|
||||
prefix = "[color=#4bf][b]SHADER ERROR:[/b]"
|
||||
trace_indent = 13
|
||||
|
||||
var trace := "%*s %s (%s:%s)" % [trace_indent, "at:", function, file, line]
|
||||
var script_backtraces_text := ""
|
||||
for backtrace in script_backtraces:
|
||||
script_backtraces_text += backtrace.format(trace_indent - 3) + "\n"
|
||||
|
||||
CustomLoggerUI.get_node("Panel/RichTextLabel").call_deferred(
|
||||
&"append_text",
|
||||
"%s %s %s[/color]\n[color=#999]%s[/color]\n[color=#999]%s[/color]" % [
|
||||
prefix,
|
||||
code,
|
||||
rationale,
|
||||
trace,
|
||||
script_backtraces_text,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Use `_init()` to register the logger as early as possible, which ensures that messages
|
||||
# printed early are taken into account. However, even when using `_init()`, the engine's own
|
||||
# initialization messages are not accessible.
|
||||
func _init() -> void:
|
||||
OS.add_logger(logger)
|
||||
|
||||
|
||||
# Removing the logger happens automatically when the project exits by default.
|
||||
# In case you need to remove a custom logger earlier, you can use `OS.remove_logger()`.
|
||||
# Doing so can also avoid object leak warnings that may be printed on exit.
|
||||
func _exit_tree() -> void:
|
||||
OS.remove_logger(logger)
|
||||
1
misc/custom_logging/custom_logger_ui.gd.uid
Normal file
1
misc/custom_logging/custom_logger_ui.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cgdbfnmbujg61
|
||||
38
misc/custom_logging/custom_logger_ui.tscn
Normal file
38
misc/custom_logging/custom_logger_ui.tscn
Normal file
@@ -0,0 +1,38 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://cpdcq55mdqx5o"]
|
||||
|
||||
[ext_resource type="FontFile" uid="uid://jrduhl6723o1" path="res://jetbrains_mono_regular.woff2" id="1_c73ru"]
|
||||
[ext_resource type="FontFile" uid="uid://g800tr1mba1m" path="res://jetbrains_mono_bold.woff2" id="2_nsaj1"]
|
||||
[ext_resource type="Script" uid="uid://cgdbfnmbujg61" path="res://custom_logger_ui.gd" id="3_5eal2"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_c73ru"]
|
||||
content_margin_left = 20.0
|
||||
content_margin_top = 0.0
|
||||
content_margin_right = 0.0
|
||||
content_margin_bottom = 10.0
|
||||
bg_color = Color(0.1, 0.1, 0.1, 0.6)
|
||||
corner_radius_top_left = 3
|
||||
corner_radius_top_right = 3
|
||||
corner_radius_bottom_right = 3
|
||||
corner_radius_bottom_left = 3
|
||||
corner_detail = 5
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer"]
|
||||
layer = 1024
|
||||
|
||||
[node name="Panel" type="PanelContainer" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_bottom = -194.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_c73ru")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="Panel"]
|
||||
layout_mode = 2
|
||||
theme_override_fonts/normal_font = ExtResource("1_c73ru")
|
||||
theme_override_fonts/bold_font = ExtResource("2_nsaj1")
|
||||
theme_override_fonts/mono_font = ExtResource("1_c73ru")
|
||||
bbcode_enabled = true
|
||||
scroll_following = true
|
||||
script = ExtResource("3_5eal2")
|
||||
BIN
misc/custom_logging/jetbrains_mono_bold.woff2
Normal file
BIN
misc/custom_logging/jetbrains_mono_bold.woff2
Normal file
Binary file not shown.
36
misc/custom_logging/jetbrains_mono_bold.woff2.import
Normal file
36
misc/custom_logging/jetbrains_mono_bold.woff2.import
Normal file
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://g800tr1mba1m"
|
||||
path="res://.godot/imported/jetbrains_mono_bold.woff2-81dbd630c21ec1c82f93481b15f2ad52.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://jetbrains_mono_bold.woff2"
|
||||
dest_files=["res://.godot/imported/jetbrains_mono_bold.woff2-81dbd630c21ec1c82f93481b15f2ad52.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
BIN
misc/custom_logging/jetbrains_mono_regular.woff2
Normal file
BIN
misc/custom_logging/jetbrains_mono_regular.woff2
Normal file
Binary file not shown.
36
misc/custom_logging/jetbrains_mono_regular.woff2.import
Normal file
36
misc/custom_logging/jetbrains_mono_regular.woff2.import
Normal file
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://jrduhl6723o1"
|
||||
path="res://.godot/imported/jetbrains_mono_regular.woff2-a5a5f65e14a39c1ed0a365506c5126e5.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://jetbrains_mono_regular.woff2"
|
||||
dest_files=["res://.godot/imported/jetbrains_mono_regular.woff2-a5a5f65e14a39c1ed0a365506c5126e5.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
58
misc/custom_logging/main.gd
Normal file
58
misc/custom_logging/main.gd
Normal file
@@ -0,0 +1,58 @@
|
||||
extends Control
|
||||
|
||||
var message_counter := 0
|
||||
var message_raw_counter := 0
|
||||
var message_stderr_counter := 0
|
||||
var warning_counter := 0
|
||||
var error_counter := 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
print("Normal message 1.")
|
||||
push_error("Error 1.")
|
||||
push_warning("Warning 1.")
|
||||
push_error("Error 2.")
|
||||
push_warning("Warning 2.")
|
||||
print("Normal message 2.")
|
||||
printerr("Normal message 1 (stderr).")
|
||||
printerr("Normal message 2 (stderr).")
|
||||
printraw("Normal message 1 (raw). ")
|
||||
printraw("Normal message 2 (raw).\n--------\n")
|
||||
|
||||
if bool(ProjectSettings.get_setting_with_override("application/run/flush_stdout_on_print")):
|
||||
$FlushStdoutOnPrint.text = "Flush stdout on print: Yes (?)"
|
||||
else:
|
||||
$FlushStdoutOnPrint.text = "Flush stdout on print: No (?)"
|
||||
|
||||
|
||||
func _on_print_message_pressed() -> void:
|
||||
message_counter += 1
|
||||
print("Printing message #%d." % message_counter)
|
||||
|
||||
|
||||
func _on_print_message_raw_pressed() -> void:
|
||||
message_raw_counter += 1
|
||||
printraw("Printing message #%d (raw). " % message_raw_counter)
|
||||
|
||||
|
||||
func _on_print_message_stderr_pressed() -> void:
|
||||
message_stderr_counter += 1
|
||||
printerr("Printing message #%d (stderr)." % message_stderr_counter)
|
||||
|
||||
|
||||
func _on_print_warning_pressed() -> void:
|
||||
warning_counter += 1
|
||||
push_warning("Printing warning #%d." % warning_counter)
|
||||
|
||||
|
||||
func _on_print_error_pressed() -> void:
|
||||
error_counter += 1
|
||||
push_error("Printing error #%d." % error_counter)
|
||||
|
||||
|
||||
func _on_open_logs_folder_pressed() -> void:
|
||||
OS.shell_open(ProjectSettings.globalize_path(String(ProjectSettings.get_setting_with_override("debug/file_logging/log_path")).get_base_dir()))
|
||||
|
||||
|
||||
func _on_crash_engine_pressed() -> void:
|
||||
OS.crash("Crashing the engine on user request (the Crash Engine button was pressed). Do not report this as a bug.")
|
||||
1
misc/custom_logging/main.gd.uid
Normal file
1
misc/custom_logging/main.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://715k1racyrfh
|
||||
120
misc/custom_logging/main.tscn
Normal file
120
misc/custom_logging/main.tscn
Normal file
@@ -0,0 +1,120 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://bukh5v13yl2og"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://715k1racyrfh" path="res://main.gd" id="1_ig7tw"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ig7tw"]
|
||||
content_margin_left = 8.0
|
||||
content_margin_top = 8.0
|
||||
content_margin_right = 8.0
|
||||
content_margin_bottom = 8.0
|
||||
bg_color = Color(0.12591082, 0.12591085, 0.12591076, 1)
|
||||
corner_radius_top_left = 3
|
||||
corner_radius_top_right = 3
|
||||
corner_radius_bottom_right = 3
|
||||
corner_radius_bottom_left = 3
|
||||
corner_detail = 3
|
||||
|
||||
[sub_resource type="Theme" id="Theme_0xm2m"]
|
||||
TooltipPanel/styles/panel = SubResource("StyleBoxFlat_ig7tw")
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = SubResource("Theme_0xm2m")
|
||||
script = ExtResource("1_ig7tw")
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = -103.0
|
||||
offset_right = 413.0
|
||||
offset_bottom = -80.0
|
||||
grow_vertical = 0
|
||||
theme_override_colors/font_color = Color(1, 1, 1, 0.7529412)
|
||||
text = "This project has an autoload with a custom logger that displays messages above.
|
||||
The custom logger replicates the output seen in the terminal, which may differ
|
||||
from the one displayed in the editor Output panel.
|
||||
Try running Godot from a terminal to see the difference."
|
||||
|
||||
[node name="FlushStdoutOnPrint" type="Label" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 784.0
|
||||
offset_top = -103.0
|
||||
offset_right = 981.0
|
||||
offset_bottom = -80.0
|
||||
grow_vertical = 0
|
||||
tooltip_text = "Flushing standard output on print allows prints to be visible immediately
|
||||
in log files, even if the engine crashes or is killed by the user.
|
||||
This has a performance impact when printing frequently.
|
||||
|
||||
This can be configured in the Project Settings (Application > Run > Flush stdout on Print).
|
||||
By default, this is enabled in debug builds (+ editor) and disabled in release builds."
|
||||
mouse_filter = 1
|
||||
theme_override_colors/font_color = Color(1, 1, 1, 0.7529412)
|
||||
text = "Flush stdout on print: Yes (?)"
|
||||
|
||||
[node name="Actions" type="HBoxContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = -63.0
|
||||
offset_right = 1014.0
|
||||
offset_bottom = -28.0
|
||||
grow_vertical = 0
|
||||
theme_override_constants/separation = 8
|
||||
|
||||
[node name="PrintMessage" type="Button" parent="Actions"]
|
||||
layout_mode = 2
|
||||
text = "Print Message"
|
||||
|
||||
[node name="PrintMessageRaw" type="Button" parent="Actions"]
|
||||
layout_mode = 2
|
||||
text = "Print Message (raw)"
|
||||
|
||||
[node name="PrintMessageStderr" type="Button" parent="Actions"]
|
||||
layout_mode = 2
|
||||
text = "Print Message (stderr)"
|
||||
|
||||
[node name="PrintWarning" type="Button" parent="Actions"]
|
||||
layout_mode = 2
|
||||
text = "Print Warning"
|
||||
|
||||
[node name="PrintError" type="Button" parent="Actions"]
|
||||
layout_mode = 2
|
||||
text = "Print Error"
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="Actions"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="OpenLogsFolder" type="Button" parent="Actions"]
|
||||
layout_mode = 2
|
||||
text = "Open Logs Folder"
|
||||
|
||||
[node name="CrashEngine" type="Button" parent="Actions"]
|
||||
layout_mode = 2
|
||||
tooltip_text = "Crashing the engine produces a stack trace written in the log file,
|
||||
as well as terminal output. The crash backtrace is not available from scripting
|
||||
in the current session, but when the next session starts, you could read existing
|
||||
log files in the logs folder and check for the presence of crash backtraces there."
|
||||
text = "Crash Engine"
|
||||
|
||||
[connection signal="pressed" from="Actions/PrintMessage" to="." method="_on_print_message_pressed"]
|
||||
[connection signal="pressed" from="Actions/PrintMessageRaw" to="." method="_on_print_message_raw_pressed"]
|
||||
[connection signal="pressed" from="Actions/PrintMessageStderr" to="." method="_on_print_message_stderr_pressed"]
|
||||
[connection signal="pressed" from="Actions/PrintWarning" to="." method="_on_print_warning_pressed"]
|
||||
[connection signal="pressed" from="Actions/PrintError" to="." method="_on_print_error_pressed"]
|
||||
[connection signal="pressed" from="Actions/OpenLogsFolder" to="." method="_on_open_logs_folder_pressed"]
|
||||
[connection signal="pressed" from="Actions/CrashEngine" to="." method="_on_crash_engine_pressed"]
|
||||
38
misc/custom_logging/project.godot
Normal file
38
misc/custom_logging/project.godot
Normal file
@@ -0,0 +1,38 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Custom Logging"
|
||||
config/description="This demo showcases a custom logger implementation, which runs in parallel
|
||||
to the built-in logging facilities (including file logging). The custom logger
|
||||
displays all messages printed by the engine in an in-game console."
|
||||
config/tags=PackedStringArray("demo", "official")
|
||||
run/main_scene="uid://bukh5v13yl2og"
|
||||
config/features=PackedStringArray("4.5")
|
||||
run/low_processor_mode=true
|
||||
|
||||
[autoload]
|
||||
|
||||
CustomLoggerUI="*res://custom_logger_ui.tscn"
|
||||
|
||||
[debug]
|
||||
|
||||
gdscript/warnings/untyped_declaration=1
|
||||
|
||||
[display]
|
||||
|
||||
window/stretch/mode="canvas_items"
|
||||
window/stretch/aspect="expand"
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
0
misc/custom_logging/screenshots/.gdignore
Normal file
0
misc/custom_logging/screenshots/.gdignore
Normal file
BIN
misc/custom_logging/screenshots/custom_logging.webp
Normal file
BIN
misc/custom_logging/screenshots/custom_logging.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
Reference in New Issue
Block a user