Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5374cf5d3 | ||
|
|
352a357460 | ||
|
|
cc018f90bf | ||
|
|
9374fbeae6 | ||
|
|
9a44775b68 | ||
|
|
07c6356354 | ||
|
|
55b124a478 | ||
|
|
5249d1d2f0 | ||
|
|
59c0752143 | ||
|
|
39160df6a6 | ||
|
|
08d2aaaf53 | ||
|
|
715a38a6e5 | ||
|
|
7cc1ab4c63 | ||
|
|
3798dff0fc |
@@ -85,6 +85,15 @@ ask Mix to use Rebar 3 to compile it by passing the `manager: :rebar3` option.
|
||||
Once configured, Mix will prompt you to install Rebar 3 if it is not yet
|
||||
available.
|
||||
|
||||
## v1.2.5 (2016-04-30)
|
||||
|
||||
### 1. Bug fixes
|
||||
|
||||
* [Logger] Stringify truncated function data in Logger
|
||||
* [Logger] Ensure poorly formatted char data can also be logged by using the replacement character "�" (diamond question mark)
|
||||
* [Mix] Do not assume `@impl` is always a list
|
||||
* [String] Fix bugs in `String.replace_*` functions where it would not include the accumulated value for certain replacements
|
||||
|
||||
## v1.2.4 (2016-04-01)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -44,8 +44,9 @@ defmodule Access do
|
||||
nil
|
||||
|
||||
Since Access is a behaviour, it can be implemented to key-value
|
||||
data structures. Access requires the key comparison to be
|
||||
implemented using the `===` operator.
|
||||
data structures. The implementation should be added to the
|
||||
module that defines the struct being access. Access requires the
|
||||
key comparison to be implemented using the `===` operator.
|
||||
|
||||
## Field-based lookups
|
||||
|
||||
|
||||
@@ -537,7 +537,7 @@ defmodule Protocol do
|
||||
if Atom.to_string(protocol) =~ "Elixir.Access" do
|
||||
:elixir_errors.warn __ENV__.line, __ENV__.file,
|
||||
"implementation of the Access protocol is deprecated. For customization of " <>
|
||||
"the dict[key] syntax, please implement the Dict behaviour instead"
|
||||
"the data[key] syntax, please implement the Access behaviour in your struct"
|
||||
else
|
||||
Protocol.assert_protocol!(protocol)
|
||||
Protocol.__ensure_defimpl__(protocol, for, __ENV__)
|
||||
|
||||
@@ -628,12 +628,12 @@ defmodule String do
|
||||
replace_leading(string, match, replacement, prefix_size, suffix_size, "")
|
||||
end
|
||||
|
||||
defp replace_leading(string, match, replacement, prefix_size, suffix_size, acc) when suffix_size > 0 do
|
||||
defp replace_leading(string, match, replacement, prefix_size, suffix_size, acc) when suffix_size >= 0 do
|
||||
case string do
|
||||
<<prefix::size(prefix_size)-binary, suffix::size(suffix_size)-binary>> when prefix == match ->
|
||||
replace_leading(suffix, match, replacement, prefix_size, suffix_size - prefix_size, acc <> replacement)
|
||||
_ ->
|
||||
string
|
||||
acc <> string
|
||||
end
|
||||
end
|
||||
|
||||
@@ -671,7 +671,7 @@ defmodule String do
|
||||
<<prefix::size(prefix_size)-binary, suffix::size(suffix_size)-binary>> when suffix == match ->
|
||||
replace_trailing(prefix, match, replacement, prefix_size - suffix_size, suffix_size, acc <> replacement)
|
||||
_ ->
|
||||
string
|
||||
string <> acc
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -164,15 +164,34 @@ defmodule StringTest do
|
||||
assert String.capitalize("fin") == "Fin"
|
||||
end
|
||||
|
||||
test "replace_leading" do
|
||||
assert String.replace_leading("aa abc ", "a", "b") == "bb abc "
|
||||
assert String.replace_leading("__ abc ", "_", "b") == "bb abc "
|
||||
assert String.replace_leading("aaaaaaaa ", "a", "b") == "bbbbbbbb "
|
||||
assert String.replace_leading("aaaaaaaa ", "aaa", "b") == "bbaa "
|
||||
assert String.replace_leading("aaaaaaaaa", "a", "b") == "bbbbbbbbb"
|
||||
assert String.replace_leading("]]]]]]", "]", "[]") == "[][][][][][]"
|
||||
assert String.replace_leading("]]]]]]]]", "]", "") == ""
|
||||
assert String.replace_leading("]]]]]] ]", "]", "") == " ]"
|
||||
assert String.replace_leading("猫猫 cat ", "猫", "й") == "йй cat "
|
||||
assert String.replace_leading("test", "t", "T") == "Test"
|
||||
assert String.replace_leading("t", "t", "T") == "T"
|
||||
assert String.replace_leading("aaa", "b", "c") == "aaa"
|
||||
end
|
||||
|
||||
test "replace_trailing" do
|
||||
assert String.replace_trailing(" abc aa", "a", "") == " abc "
|
||||
assert String.replace_trailing(" abc __", "_", "") == " abc "
|
||||
assert String.replace_trailing(" aaaaaaaaa", "a", "") == " "
|
||||
assert String.replace_trailing("aaaaaaaaaa", "a", "") == ""
|
||||
assert String.replace_trailing("]]]]]]]]]]", "]", "") == ""
|
||||
assert String.replace_trailing(" cat 猫猫", "猫", "") == " cat "
|
||||
assert String.replace_trailing("test", "t", "") == "tes"
|
||||
assert String.replace_trailing("t", "t", "") == ""
|
||||
assert String.replace_trailing(" abc aa", "a", "b") == " abc bb"
|
||||
assert String.replace_trailing(" abc __", "_", "b") == " abc bb"
|
||||
assert String.replace_trailing(" aaaaaaaa", "a", "b") == " bbbbbbbb"
|
||||
assert String.replace_trailing(" aaaaaaaa", "aaa", "b") == " aabb"
|
||||
assert String.replace_trailing("aaaaaaaaa", "a", "b") == "bbbbbbbbb"
|
||||
assert String.replace_trailing("]]]]]]", "]", "[]") == "[][][][][][]"
|
||||
assert String.replace_trailing("]]]]]]]]", "]", "") == ""
|
||||
assert String.replace_trailing("] ]]]]]]", "]", "") == "] "
|
||||
assert String.replace_trailing(" cat 猫猫", "猫", "й") == " cat йй"
|
||||
assert String.replace_trailing("test", "t", "T") == "tesT"
|
||||
assert String.replace_trailing("t", "t", "T") == "T"
|
||||
assert String.replace_trailing("aaa", "b", "c") == "aaa"
|
||||
end
|
||||
|
||||
test "rstrip" do
|
||||
|
||||
@@ -562,7 +562,7 @@ defmodule Logger do
|
||||
end
|
||||
|
||||
defp truncate(data, n) when is_function(data, 0),
|
||||
do: Logger.Utils.truncate(data.(), n)
|
||||
do: truncate(data.(), n)
|
||||
defp truncate(data, n) when is_list(data) or is_binary(data),
|
||||
do: Logger.Utils.truncate(data, n)
|
||||
defp truncate(data, n),
|
||||
|
||||
@@ -74,11 +74,16 @@ defmodule Logger.Backends.Console do
|
||||
enabled: Keyword.get(colors, :enabled, IO.ANSI.enabled?)}
|
||||
end
|
||||
|
||||
defp log_event(level, msg, ts, md, %{colors: colors} = state) do
|
||||
defp log_event(level, msg, ts, md, %{colors: colors, device: device} = state) do
|
||||
output =
|
||||
format_event(level, msg, ts, md, state)
|
||||
|> color_event(level, colors)
|
||||
IO.write(state.device, output)
|
||||
try do
|
||||
IO.write(device, output)
|
||||
rescue
|
||||
ArgumentError ->
|
||||
IO.write(device, Logger.Formatter.prune(output))
|
||||
end
|
||||
end
|
||||
|
||||
defp format_event(level, msg, ts, md, %{format: format, metadata: keys}) do
|
||||
|
||||
@@ -44,6 +44,26 @@ defmodule Logger.Formatter do
|
||||
@type pattern :: :date | :level | :levelpad | :message | :metadata | :node | :time
|
||||
@valid_patterns [:time, :date, :message, :level, :node, :metadata, :levelpad]
|
||||
@default_pattern "\n$time $metadata[$level] $levelpad$message\n"
|
||||
@replacement "�"
|
||||
|
||||
@doc """
|
||||
Prune non-valid UTF-8 codepoints.
|
||||
|
||||
Typically called after formatting when the data cannot be printed.
|
||||
"""
|
||||
@spec prune(IO.chardata) :: IO.chardata
|
||||
def prune(binary) when is_binary(binary), do: prune_binary(binary, "")
|
||||
def prune([h|t]) when h in 0..1114111, do: [h|prune(t)]
|
||||
def prune([h|t]), do: [prune(h)|prune(t)]
|
||||
def prune([]), do: []
|
||||
def prune(_), do: @replacement
|
||||
|
||||
defp prune_binary(<<h::utf8, t::binary>>, acc),
|
||||
do: prune_binary(t, <<acc::binary, h::utf8>>)
|
||||
defp prune_binary(<<_, t::binary>>, acc),
|
||||
do: prune_binary(t, <<acc::binary, @replacement>>)
|
||||
defp prune_binary(<<>>, acc),
|
||||
do: acc
|
||||
|
||||
@doc ~S"""
|
||||
Compiles a format string into an array that the `format/5` can handle.
|
||||
|
||||
@@ -10,9 +10,9 @@ defmodule Logger.Watcher do
|
||||
"""
|
||||
def start_link(m, f, a) do
|
||||
import Supervisor.Spec
|
||||
child = worker(__MODULE__, [],
|
||||
[function: :watcher, restart: :transient])
|
||||
options = [strategy: :simple_one_for_one, name: @name]
|
||||
child = worker(__MODULE__, [], [function: :watcher, restart: :transient])
|
||||
options = [strategy: :simple_one_for_one, name: @name,
|
||||
max_restarts: 30, max_seconds: 3]
|
||||
case Supervisor.start_link([child], options) do
|
||||
{:ok, _} = ok ->
|
||||
_ = for {mod, handler, args} <- apply(m, f, a) do
|
||||
|
||||
@@ -4,6 +4,14 @@ defmodule Logger.FormatterTest do
|
||||
|
||||
import Logger.Formatter
|
||||
|
||||
test "prune/1" do
|
||||
assert prune(1) == "�"
|
||||
assert prune(<<"hí", 233>>) == "hí�"
|
||||
assert prune(["hi"|233]) == ["hi"|"�"]
|
||||
assert prune([233|"hi"]) == [233|"hi"]
|
||||
assert prune([[]|[]]) == [[]]
|
||||
end
|
||||
|
||||
defmodule CompileMod do
|
||||
def format(_level, _msg, _ts, _md) do
|
||||
true
|
||||
|
||||
@@ -80,16 +80,16 @@ defmodule Logger.UtilsTest do
|
||||
{'~ts~ts~ts', ["abcdeabcde", "", ""]}
|
||||
end
|
||||
|
||||
test "timestamp" do
|
||||
test "timestamp/1" do
|
||||
assert {{_, _, _}, {_, _, _, _}} = timestamp(true)
|
||||
end
|
||||
|
||||
test "format_date" do
|
||||
test "format_date/1" do
|
||||
date = {2015, 1, 30}
|
||||
assert format_date(date) == ["2015", ?-, [?0, "1"], ?-, "30"]
|
||||
end
|
||||
|
||||
test "format_time" do
|
||||
test "format_time/1" do
|
||||
time = {12, 30, 10, 1}
|
||||
assert format_time(time) == ["12", ?:, "30", ?:, "10", ?., [?0, ?0, "1"]]
|
||||
|
||||
|
||||
@@ -145,10 +145,12 @@ defmodule Mix.Compilers.Elixir do
|
||||
end
|
||||
|
||||
defp detect_kind(module) do
|
||||
impl = Module.get_attribute(module, :impl)
|
||||
|
||||
cond do
|
||||
impl = Module.get_attribute(module, :impl) ->
|
||||
is_list(impl) and impl[:protocol] ->
|
||||
{:impl, impl[:protocol]}
|
||||
Module.get_attribute(module, :protocol) ->
|
||||
is_list(Module.get_attribute(module, :protocol)) ->
|
||||
:protocol
|
||||
true ->
|
||||
:module
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{application, elixir,
|
||||
[{description, "elixir"},
|
||||
{vsn, "1.2.4"},
|
||||
{vsn, "1.2.5"},
|
||||
{modules, [
|
||||
elixir
|
||||
]},
|
||||
|
||||
Reference in New Issue
Block a user