Skip to content

Commit 07c6356

Browse files
author
José Valim
committed
Ensure poorly formatted chardata is pruned in Logger watcher
Signed-off-by: José Valim <[email protected]>
1 parent 55b124a commit 07c6356

File tree

4 files changed

+40
-8
lines changed

4 files changed

+40
-8
lines changed

lib/logger/lib/logger/backends/console.ex

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,16 @@ defmodule Logger.Backends.Console do
7474
enabled: Keyword.get(colors, :enabled, IO.ANSI.enabled?)}
7575
end
7676

77-
defp log_event(level, msg, ts, md, %{colors: colors} = state) do
77+
defp log_event(level, msg, ts, md, %{colors: colors, device: device} = state) do
7878
output =
7979
format_event(level, msg, ts, md, state)
8080
|> color_event(level, colors)
81-
IO.write(state.device, output)
81+
try do
82+
IO.write(device, output)
83+
rescue
84+
ArgumentError ->
85+
IO.write(device, Logger.Utils.prune(output))
86+
end
8287
end
8388

8489
defp format_event(level, msg, ts, md, %{format: format, metadata: keys}) do

lib/logger/lib/logger/utils.ex

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11
defmodule Logger.Utils do
22
@moduledoc false
33

4+
@replacement "�"
5+
6+
@doc """
7+
Prune non-valid UTF-8 codepoints.
8+
"""
9+
@spec prune(IO.chardata) :: IO.chardata
10+
def prune(binary) when is_binary(binary), do: prune_binary(binary, "")
11+
def prune([h|t]) when h in 0..1114111, do: [h|prune(t)]
12+
def prune([h|t]), do: [prune(h)|prune(t)]
13+
def prune([]), do: []
14+
def prune(_), do: @replacement
15+
16+
defp prune_binary(<<h::utf8, t::binary>>, acc),
17+
do: prune_binary(t, <<acc::binary, h::utf8>>)
18+
defp prune_binary(<<_, t::binary>>, acc),
19+
do: prune_binary(t, <<acc::binary, @replacement>>)
20+
defp prune_binary(<<>>, acc),
21+
do: acc
22+
423
@doc """
524
Truncates a char data into n bytes.
625

lib/logger/lib/logger/watcher.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ defmodule Logger.Watcher do
1010
"""
1111
def start_link(m, f, a) do
1212
import Supervisor.Spec
13-
child = worker(__MODULE__, [],
14-
[function: :watcher, restart: :transient])
15-
options = [strategy: :simple_one_for_one, name: @name]
13+
child = worker(__MODULE__, [], [function: :watcher, restart: :transient])
14+
options = [strategy: :simple_one_for_one, name: @name,
15+
max_restarts: 30, max_seconds: 3]
1616
case Supervisor.start_link([child], options) do
1717
{:ok, _} = ok ->
1818
_ = for {mod, handler, args} <- apply(m, f, a) do

lib/logger/test/logger/utils_test.exs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ defmodule Logger.UtilsTest do
66
import Kernel, except: [inspect: 2]
77
defp inspect(format, args), do: Logger.Utils.inspect(format, args, 10)
88

9+
test "prune/1" do
10+
assert prune(1) == "�"
11+
assert prune(<<"hí", 233>>) == "hí�"
12+
assert prune(["hi"|233]) == ["hi"|"�"]
13+
assert prune([233|"hi"]) == [233|"hi"]
14+
assert prune([[]|[]]) == [[]]
15+
end
16+
917
test "truncate/2" do
1018
# ASCII binaries
1119
assert truncate("foo", 4) == "foo"
@@ -80,16 +88,16 @@ defmodule Logger.UtilsTest do
8088
{'~ts~ts~ts', ["abcdeabcde", "", ""]}
8189
end
8290

83-
test "timestamp" do
91+
test "timestamp/1" do
8492
assert {{_, _, _}, {_, _, _, _}} = timestamp(true)
8593
end
8694

87-
test "format_date" do
95+
test "format_date/1" do
8896
date = {2015, 1, 30}
8997
assert format_date(date) == ["2015", ?-, [?0, "1"], ?-, "30"]
9098
end
9199

92-
test "format_time" do
100+
test "format_time/1" do
93101
time = {12, 30, 10, 1}
94102
assert format_time(time) == ["12", ?:, "30", ?:, "10", ?., [?0, ?0, "1"]]
95103

0 commit comments

Comments
 (0)