## Write a line

Add the namespace and log. There is nothing to place in the scene and nothing to wire up.

```csharp
using Udonite.Logging;

public class Door : UdoniteBehaviour
{
    public override void Interact()
    {
        Log.Info("opened");
    }
}
```

```text
[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:

```csharp
Log.Info("hit for " + damage, "combat");
```

```text
[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:

```csharp
Log.Assert(owner != null);
Log.Assert(players.Length > 0);
```

```text
[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:

```csharp
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:

```csharp
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.
