Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions misc/custom_logging/README.md
Original file line number Diff line number Diff line change
@@ -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

![Screenshot](screenshots/custom_logging.webp)
72 changes: 72 additions & 0 deletions misc/custom_logging/custom_logger_ui.gd
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions misc/custom_logging/custom_logger_ui.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://cgdbfnmbujg61
38 changes: 38 additions & 0 deletions misc/custom_logging/custom_logger_ui.tscn
Original file line number Diff line number Diff line change
@@ -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")
Binary file added misc/custom_logging/jetbrains_mono_bold.woff2
Binary file not shown.
36 changes: 36 additions & 0 deletions misc/custom_logging/jetbrains_mono_bold.woff2.import
Original file line number Diff line number Diff line change
@@ -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={}
Binary file not shown.
36 changes: 36 additions & 0 deletions misc/custom_logging/jetbrains_mono_regular.woff2.import
Original file line number Diff line number Diff line change
@@ -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 changes: 58 additions & 0 deletions misc/custom_logging/main.gd
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions misc/custom_logging/main.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://715k1racyrfh
120 changes: 120 additions & 0 deletions misc/custom_logging/main.tscn
Original file line number Diff line number Diff line change
@@ -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"]
Loading