venkatd

venkatd

I wanted to ask is there a way to log specific messages without truncation?

When I run migrations that replaces data, as an extra safety measure (in addition to backups) I like to log out diffs and before/after messages. For those logs specifically I want to set truncate to infinity.

0
Post #11
harrisi

harrisi

Could this be due to an interaction between the now-deprecated :console backend interacting with your use of :default_formatter? Maybe try changing any config :logger, :console ... to use :default_formatter. I couldn’t recreate the issue of not getting colors working, but mismatched logger config keys can cause non-obvious behavior.

For what it’s worth, some upcoming version of Phoenix will set the minimum Elixir version to 1.15 and use :default_formatter instead of :console.

You can update the formatter config, log a message, and update it again. There’s an example of that here: Logger — Logger v1.20.2. It would be similar with a custom formatter as well.

That sounds like it may be a good option for your situation, but you could also add another handler with a formatter with no truncating, and filter for specific messages. If it’s infrequent, it’s probably better to go with the update, log, update strategy instead, though.

1
Post #12
venkatd

venkatd

Thanks for the tip!

Yes it’s infrequent.

I only need this when we are running certain kinds of migrations. We do backup our database but for the extra confidence I like have full logs of what exactly happened during the migration. The before/after/diff of each row updated helps me confirm that everything went through correctly.

1
Post #13
harrisi

harrisi

Yeah, in that case I think just doing something like

def migrate do
  formatter = Logger.default_formatter(truncate: :infinity)
  :logger.update_handler_config(:default, :formatter, formatter)

  # do migrations

  :logger.update_handler_config(:default, :formatter, Logger.default_formatter())
end

would suffice. You’d maybe want to take care to ensure that if the migrations fail or something you still properly update the handler, but that may not matter in this case.

Just for posterity, here’s the other option I mentioned:

# config/config.exs

config :logs, :logger, [
  {
    :handler,
    :custom_logger,
    :logger_std_h,
    %{
      filters: [
        remote_gl: {&:logger_filters.remote_gl/2, :stop},
        custom_filter: {&Logs.custom_filter/2, []}
      ],
      filter_default: :log,
      formatter: Logger.default_formatter(truncate: :infinity),
      level: :all,
      module: :logger_std_h
    }
  }
]

# lib/logs.ex
defmodule Logs do
  def custom_filter(%{meta: %{no_truncate: true}} = event, _extra) do
    event
  end
  def custom_filter(_event, _extra), do: :stop
end

# lib/logs/application.ex

defmodule Logs.Application do
  use Application

  def start(_type, _args) do
    Logger.add_handlers(:logs)

    # ...
  end

# ...
end

Then when you need to log something without truncation, you would just do something like:

Logger.info("this won't be truncated", no_truncate: true)

One issue with that is that the default handler will still log it, truncated, but you’ll also get the non-truncated form. If you want to avoid that you would need to add an inverse filter to the default handler, like:

# config/config.exs
config :logger, :default_handler,
  filters: [
    inverse_custom_filter: {&Logs.inverse_custom_filter/2, []}
  ]

# lib/logs.ex
defmodule Logs do
  # ...

  def inverse_custom_filter(event, extra) do
    if custom_filter(event, extra) == :stop do
      event
    else
      :stop
    end
  end

  # ...
end

Maybe I should’ve written a blog post instead. :slight_smile:

0
Post #14
— All posts loaded —