Config of backend logger in runtime.exs ignored

I’m using LoggerFileBackend in order to write logs to a file and trying to config the path based on the hostname. I have the following code in runtime.exs:

IO.inspect(Application.get_all_env(:logger), label: :pre_splunk_path)

config :logger, :splunk_log,
  path: "/var/log/apps/my_app.#{host}.log"

IO.inspect(Application.get_all_env(:logger), label: :post_splunk_path)

For both pre_splunk_path and post_splunk_path, the path is not set:

pre_splunk_path: [
  backends: [:console, {LoggerFileBackend, :splunk_log}],
  ...
  splunk_log: [
    level: :info
  ],
  ...
]
post_splunk_path: [ same ]

Afterwards when LoggerFileBackend.init is called, it isn’t set:

Calling init with name=splunk_log
config: %{
  inode: nil,
  io_device: nil,
  level: :info,
  name: :splunk_log,
  path: nil,
  rotate: nil
}

But if I check from the console after startup, it is set:

1> Application.get_all_env(:logger)
[
  backends: [:console, {LoggerFileBackend, :splunk_log}],
  ...
  splunk_log: [
    level: :info,
    path: "/var/log/apps/myapp.console-1631022785-3082.log"
  ],
  ...
]

And at this point I can force reconfigure from the console and it works:

2> :gen_event.call(Logger, {LoggerFileBackend, :splunk_log}, 
{:configure, path: "/var/log/apps/myapp.console-1631025756-20171.log"})

So any idea how I can have the runtime config take affect properly?

1 Like

BTW, I should mention that I think a normal console works fine. This problem occurs when running a release.

Logger has 3 levels of configuration, read more about them here: Logger — Logger v1.12.3
You’re trying to use Application configuration during runtime, but Logger.add_backend/2 and Logger.remove_backend/2 should be used.

Typically, I have these lines in my runtime.exs:

current_backends = Application.get_env(:logger, :backends)

new_backends =
  case config_env() do
    :prod -> [MyAwesomeJSONLogger, Sentry.LoggerBackend]
    :dev -> [:console]
    :test -> [:console]
  end

config :logger, backends: new_backends

current_backends
|> List.myers_difference(new_backends)
|> Enum.each(fn
  {:del, backends} -> Enum.each(backends, &Logger.remove_backend/1)
  {:ins, backends} -> Enum.each(backends, &Logger.add_backend/1)
  _ -> :noop
end)
3 Likes

Thanks! I’ll modify to use add_backend instead

I modified to use Logger.add_backend but it was a little more complicated than that when doing a release. In case anyone else has this issue, here is what I included in runtime.exs to get it working:

      {:ok, host} = :inet.gethostname()
      splunk_log = {LoggerFileBackend, :splunk_log}

      # Configuring splunk_log even though the initial init of it won't use these attributes,
      # but if the Logger has to restart it will use these (I think!).
      config :logger, backends: [:console, splunk_log]

      splunk_config = [
        path: "/var/log/my_apps/myapp.#{host}.log",
        ...
      ]

      config :logger, :splunk_log, splunk_config

      # Start logger otherwise add_backend will fail under release
      Application.ensure_all_started(:logger)
      Logger.add_backend(splunk_log)
      # Explicitly configure splunk_log since runtime config isn't picked up during initial start
      Logger.configure_backend(splunk_log, splunk_config)

1 Like