Getting started
Write a line, tag it, assert on something, and hand a line to code that has somewhere else to put it.
Write a line
Add the namespace and log. There is nothing to place in the scene and nothing to wire up.
using Udonite.Logging;
public class Door : UdoniteBehaviour
{
public override void Interact()
{
Log.Info("opened");
}
}
[Door.Interact:8] opened
Log.Warning and Log.Error write the same line to the other two Console channels.
The type comes from the file name. There is no way to ask Udon for the enclosing type at runtime, and Unity only recognises a behaviour whose type name matches its file name, so for the behaviours doing the logging the two are the same. A call from a differently named class reports the file's name, not its own.
Tag related lines
A tag groups lines that belong together, and reads before the call site:
Log.Info("hit for " + damage, "combat");
[combat] [Weapon.Fire:22] hit for 3
Tags are ordinary text in the line, so the Console's own search box filters on them.
Assert on something
Log.Assert reports only when the condition is false, and quotes the condition's own source:
Log.Assert(owner != null);
Log.Assert(players.Length > 0);
[assertion failed] [Room.Join:31] owner != null
[assertion failed] [Room.Join:32] players.Length > 0
That quoting is the reason to prefer it over an if and an Error: the line names what was untrue rather than only that something was, and it stays correct when the condition is later edited.
A message replaces the quoted condition where the condition alone would not explain much:
Log.Assert(state == Ready, "the join handler ran before the room finished loading");
It reports and returns; it never throws. An exception in Udon halts the behaviour for the rest of the session, which would turn a diagnostic into an outage for everyone in the world.
Hand a line somewhere else
For a line with somewhere else to go — an in-world panel, a ring buffer, something bound off the client — Log.Entry hands back the pieces instead of writing them:
LogEntry entry = Log.Entry("hit for " + damage, LogLevel.Warning, "combat");
panel.Show(entry.Message, entry.Tag, entry.Time);
Log.Write(entry);
Message, Text, Tag, Type, Member, Line, Level and Time are separate fields, because a panel two metres away wants different parts of a line than a console does.
This is a separate call so the ordinary one stays free. Every Entry allocates an object, and a world logging from an Update should not pay for one nobody reads. Log.Info and its siblings return nothing.
What it costs
A log call builds a string, and a world runs under a ten-second VM budget. That is nothing at human rates and real money in a hot loop, so keep them out of code that runs every frame for every player.
There is no way to switch logging off short of deleting the calls. [Conditional] is the mechanism that should do it, by removing the call and its arguments outright, and Udonite does not honour it yet.