|
| 1 | +defmodule Logger.ErlangHandler do |
| 2 | + @moduledoc false |
| 3 | + |
| 4 | + @doc """ |
| 5 | + Hook required by `:logger`. |
| 6 | + """ |
| 7 | + def log(%{meta: %{domain: [:otp, :sasl | _]}}, %{sasl_reports?: false}) do |
| 8 | + :ok |
| 9 | + end |
| 10 | + |
| 11 | + def log(%{meta: %{domain: [:supervisor_report]}}, %{sasl_reports?: false}) do |
| 12 | + :ok |
| 13 | + end |
| 14 | + |
| 15 | + def log(%{level: level, msg: msg, meta: erl_meta}, _config) do |
| 16 | + level = erlang_level_to_elixir_level(level) |
| 17 | + |
| 18 | + Logger.bare_log(level, fn -> |
| 19 | + try do |
| 20 | + meta = extract_metadata(erl_meta) |
| 21 | + |
| 22 | + case msg do |
| 23 | + {:string, string} -> |
| 24 | + {string, meta} |
| 25 | + |
| 26 | + {:report, %{label: label, report: report} = complete} when map_size(complete) == 2 -> |
| 27 | + translate(level, :report, {label, report}, meta, erl_meta) |
| 28 | + |
| 29 | + {:report, %{label: {:error_logger, _}, format: format, args: args}} -> |
| 30 | + translate(level, :format, {format, args}, meta, erl_meta) |
| 31 | + |
| 32 | + {:report, report} -> |
| 33 | + translate(level, :report, {:logger, report}, meta, erl_meta) |
| 34 | + |
| 35 | + {format, args} -> |
| 36 | + translate(level, :format, {format, args}, meta, erl_meta) |
| 37 | + end |
| 38 | + rescue |
| 39 | + e -> |
| 40 | + [ |
| 41 | + "Failure while translating Erlang's logger event\n", |
| 42 | + Exception.format(:error, e, System.stacktrace()) |
| 43 | + ] |
| 44 | + end |
| 45 | + end) |
| 46 | + end |
| 47 | + |
| 48 | + defp erlang_level_to_elixir_level(:emergency), do: :error |
| 49 | + defp erlang_level_to_elixir_level(:alert), do: :error |
| 50 | + defp erlang_level_to_elixir_level(:critical), do: :error |
| 51 | + defp erlang_level_to_elixir_level(:error), do: :error |
| 52 | + defp erlang_level_to_elixir_level(:warning), do: :warn |
| 53 | + defp erlang_level_to_elixir_level(:notice), do: :info |
| 54 | + defp erlang_level_to_elixir_level(:info), do: :info |
| 55 | + defp erlang_level_to_elixir_level(:debug), do: :debug |
| 56 | + |
| 57 | + defp extract_metadata(map) do |
| 58 | + metadata = [] |
| 59 | + |
| 60 | + metadata = |
| 61 | + case map do |
| 62 | + %{mfa: {mod, fun, arity}} -> [module: mod, function: form_fa(fun, arity)] ++ metadata |
| 63 | + _ -> metadata |
| 64 | + end |
| 65 | + |
| 66 | + metadata = |
| 67 | + case map do |
| 68 | + %{file: file, line: line} -> [file: List.to_string(file), line: line] ++ metadata |
| 69 | + _ -> metadata |
| 70 | + end |
| 71 | + |
| 72 | + metadata = |
| 73 | + case map do |
| 74 | + %{pid: pid} -> [pid: pid] ++ metadata |
| 75 | + _ -> metadata |
| 76 | + end |
| 77 | + |
| 78 | + metadata |
| 79 | + rescue |
| 80 | + _ -> [] |
| 81 | + end |
| 82 | + |
| 83 | + defp form_fa(fun, arity) do |
| 84 | + Atom.to_string(fun) <> "/" <> Integer.to_string(arity) |
| 85 | + end |
| 86 | + |
| 87 | + @doc """ |
| 88 | + Shared translation convenience. |
| 89 | + """ |
| 90 | + def translate(level, kind, data, meta, erl_meta) do |
| 91 | + %{ |
| 92 | + level: min_level, |
| 93 | + truncate: truncate, |
| 94 | + translators: translators |
| 95 | + } = Logger.Config.__data__() |
| 96 | + |
| 97 | + case translate(translators, min_level, level, kind, data, meta) do |
| 98 | + :none -> {translate_fallback(kind, data, erl_meta, truncate), meta} |
| 99 | + other -> other |
| 100 | + end |
| 101 | + end |
| 102 | + |
| 103 | + defp translate([{mod, fun} | t], min_level, level, kind, data, meta) do |
| 104 | + case apply(mod, fun, [min_level, level, kind, data]) do |
| 105 | + {:ok, chardata, transdata} -> {chardata, Keyword.merge(meta, transdata)} |
| 106 | + {:ok, chardata} -> {chardata, meta} |
| 107 | + :skip -> :skip |
| 108 | + :none -> translate(t, min_level, level, kind, data, meta) |
| 109 | + end |
| 110 | + end |
| 111 | + |
| 112 | + defp translate([], _min_level, _level, _kind, _data, _meta) do |
| 113 | + :none |
| 114 | + end |
| 115 | + |
| 116 | + defp translate_fallback(:report, {:logger, data}, %{report_cb: callback} = meta, truncate) do |
| 117 | + translate_fallback(:format, callback.(data), meta, truncate) |
| 118 | + end |
| 119 | + |
| 120 | + defp translate_fallback(:format, {format, args}, _meta, truncate) do |
| 121 | + format |
| 122 | + |> Logger.Utils.scan_inspect(args, truncate) |
| 123 | + |> :io_lib.build_text() |
| 124 | + end |
| 125 | + |
| 126 | + defp translate_fallback(:report, {_type, %{} = data}, _meta, _truncate) do |
| 127 | + Kernel.inspect(Map.to_list(data)) |
| 128 | + end |
| 129 | + |
| 130 | + defp translate_fallback(:report, {_type, data}, _meta, _truncate) do |
| 131 | + Kernel.inspect(data) |
| 132 | + end |
| 133 | +end |
0 commit comments