Logger metadata only relates to the current process; how to set this in a Mix task?

I’ve used Logger.metadata before (along the lines of this post), but I’m having some trouble making it work from within a Mix task.

Assuming the following in my config:

config :logger, :console,
  level: :debug,
  format: "[$level] $message [metadata] $metadata\n",
   metadata: [:foo]

and a run/1 function in a custom mix task like so:

  def run(opts) do
    {:ok, _} = Application.ensure_all_started(:my_app)
    Logger.metadata(foo: "XZ")
    Logger.info("wtf?")
  end

I would expect the log output to be something like this:

08:42:30.012 [info] wtf? [metadata] state=XZ

That’s what I get when I try this inside iex, but instead, it only outputs the message:

08:42:30.012 [info]  wtf?

Can someone explain this? Does have something to do with the metadata only applying to the current process?

Thanks, as always!

Mix tasks don’t load config.exs by default, I believe, for performance purposes. You have to load those configurations explicitly if you want them.

Would you recommend doing it via

Mix.Task.run("loadconfig")

?

You can set the flag like this too…

Logger.info("wtf?", foo: "XZ")

I still can’t get metadata showing for things I launch via a Mix task…

Thanks! Usually I use the simple form like this, but the beauty of calling Logger.metadata() is that you can establish a context for upcoming log messages before execution is routed deep into functions. It’s especially valuable when you can send log messages with that metadata from functions that don’t have that data in scope. It was a mind-blowing experience for me to discover that Elixir did this – I remember so many code refactors done just to pass variables around for the sake of logging! So it’s frustrating that this isn’t working (yet) in my Mix tasks…

Did you try the load config task?

Yes, I tried including the Mix.Task.run("loadconfig") in my Mix task’s run/1 function, but the formatting and the metadata config is still ignored.

mix loadconfig will not affect running Logger. Unfortunately @fireproofsocks need to do it “manually” as IIRC there is no option to “reload” application environment.

Dumb question: how to load config files “manually”? https://hexdocs.pm/elixir/Code.html#require_file/2 ?

No. I mean that changes in application environment will not be reflected in logger configuration unless explicitly done so. You need to use Logger.configure/1 to apply configuration.

Maybe an alias could be helpful?

"mytask": ["loadconfig", "mytask"]

There’s gotta be a way to tell mix to do the config loading including logger config prior to your mix task. How does something like phx.server work?