# Log: When to use emit vs. context

**URL:** <https://forum.crystal-lang.org/t/log-when-to-use-emit-vs-context/9022>\
**Category:** Help & Support\
**Created:** [June 21, 2026, 8:58pm UTC](https://forum.crystal-lang.org/t/log-when-to-use-emit-vs-context/9022 "2026-06-21T20:58:19Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![phil294](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/phil294/32/2836_2.png) [@phil294](https://forum.crystal-lang.org/u/phil294)\
**Post date:** [June 21, 2026, 8:58pm UTC](https://forum.crystal-lang.org/t/log-when-to-use-emit-vs-context/9022/1 "2026-06-21T20:58:19Z")

</div>

Hello,

when do you use one over the other? I can’t really find docs about this. The following just prints both data structures, making me wonder why there are two different ways of doing it. The only difference I can see is that you can set context on a per-Fiber basis while emit sends volatile data.

```auto
require "log"
Log.with_context(x: { y: 1 }) do
  Log.error do |emitter|
    emitter.emit("...", a: { b: 2 })
  end
end

```

While Crystal’s docs are usually fantastic, I have found the logging module hard to understand. Personally I would have loved more elaborate infos on the various building blocks. They are scattered among the different submodules and it’s rarely clear to me when to use what.

As a use case, I’m trying to build a class where the logging calls of all instance methods will be prefixed with the value of a certain instance property. It doesn’t seem like the Log module supports that, so I guess I have to build a custom log method for my class which I then call. But I wonder which of the two syntaxes I should use.

As an aside, I also wonder: If I do

```auto
Log.trace { my_large_var.to_json }

```

this appears to create a heap var, as the log backend abstraction is indifferent to the consumer, aka you cannot access the IO here. Logging _in particular_ is a use case of perhaps wanting to write to a file or in memory WAL thousands of times per second. This could be ugly wrt performance, it seems to me. Even the official [performance guide](https://crystal-lang.org/reference/1.18/guides/performance.html) recommends to work on IO instead of string operations. Am I missing something? Or should we perhaps just always instead do

```auto
Log.trace &.emit(my_large_var.to_json)

```

?

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [June 21, 2026, 11:52pm UTC](https://forum.crystal-lang.org/t/log-when-to-use-emit-vs-context/9022/2 "2026-06-21T23:52:56Z")

</div>

> [@phil294](#):
>
> when do you use one over the other?

> [@phil294](#):
>
> The only difference I can see is that you can set context on a per-Fiber basis while emit sends volatile data.

Pretty much yea. The way the docs name these are **context** and **metadata**. The main difference being **context** applies to all emitted logs within that block (or fiber depending the API used), while **metadata** is scoped to a single log. The main use case being is you can use context for common high level info like `user_id`, whereas metadata can be used to capture log/message specific info.

> [@phil294](#):
>
> As an aside, I also wonder: If I do

I’m _pretty_ sure this’ll create a closure with you `my_large_var`, BUT `#to_json` will only be called if the log severity level is \>= `trace`. E.g. the block of a log method doesn’t get executed if not used, thus saving you the actual allocation of your var’s JSON representation.

> [@phil294](#):
>
> Or should we perhaps just always instead do

It doesn’t really matter. `Log.trace &.emit(my_large_var.to_json)` is the same as `Log.trace { my_large_var.to_json }`.

> [@phil294](#):
>
> Logging _in particular_ is a use case of perhaps wanting to write to a file or in memory WAL thousands of times per second.

There is def going to be an overhead in logging, but ultimately depends on how you implement it. Like it would be a bit unexpected if you’re logging a bunch of `trace` level logs in production. But as you mentioned log entries _have_ to store the message a string instead just writing to an `IO` directly because there isn’t a guarantee that the backend it’ll write to _IS_ an `IO` at all. You could have a backend that writes things to Elasticsearch for example.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [June 22, 2026, 7:33am UTC](https://forum.crystal-lang.org/t/log-when-to-use-emit-vs-context/9022/3 "2026-06-22T07:33:37Z")

</div>

> [@phil294](#):
>
> Logging _in particular_ is a use case of perhaps wanting to write to a file or in memory WAL thousands of times per second. This could be ugly wrt performance, it seems to me.

`Log` is meant for leaving a trace of program execution to enable debugging or statistics and the like.  
It’s not intended to ensure durability of application data, as a write-ahead log would do.  
You might be looking at the wrong tool.

---

<div class="post-metadata">

**Author:** ![phil294](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/phil294/32/2836_2.png) [@phil294](https://forum.crystal-lang.org/u/phil294)\
**Post date:** [August 9, 2026, 6:07am UTC](https://forum.crystal-lang.org/t/log-when-to-use-emit-vs-context/9022/4 "2026-08-09T06:07:24Z")

</div>

Right, thanks to both of you for the helpful answers. I made some performance tests and using `Log.debug()` appears to be about twice as slow than manually writing the data + timestamp into an open file handle. The actual performance penalty seems to come from the timestamp / json serialization though, so I have migrated my mass message stream log into a more bare-bones implementation as you suggested.
