Metrix global context conflicts when setting local context with a keyword list
jknipp opened this issue · comments
When trying to set the context locally for metrics on count with a keyword list, Metrix throws an error when merging the values with the global context. If the global context is removed, a keyword list is allowed and works as expected.
Global source configuration via config.exs
config :metrix,
context: %{"source" => "my_source"}
Example Call
Metrics.count(source: "value", name)
Stack Trace
stacktrace:
(elixir) lib/keyword.ex:728: Keyword.update([], "source", "my_source", #Function<3.82657468/1 in Dict.do_merge/4>)
(elixir) lib/keyword.ex:733: Keyword.update/4
(elixir) lib/keyword.ex:733: Keyword.update/4
(elixir) lib/dict.ex:293: anonymous fn/4 in Dict.do_merge/4
(elixir) lib/enum.ex:3103: Enumerable.Map.do_reduce/3
(elixir) lib/dict.ex:292: Dict.do_merge/4
(metrix) lib/metrix.ex:87: Metrix.log/1
(metrix) lib/metrix.ex:56: Metrix.count/3
This doesn't appear to be isolated to count.
After more research, I tracked this down to Dict.merge
and how it merges keyword lists. If Strings are used as keys and the key does not exist in the map, Elixir throws an error.
Reversing the args to Dict.merge(%{"meta" => "data"}, [meta: "data"]})
works as expected and allows for us to override the global context locally (which we aren't doing now).
iex(4)> [meta: "data"] |> Dict.merge( %{})
[meta: "data"]
iex(5)> [meta: "data"] |> Dict.merge( %{meta: "data_global"})
[meta: "data_global"]
iex(6)> [meta: "data"] |> Dict.merge( %{"meta": "data_global"})
[meta: "data_global"]
iex(7)> [meta: "data"] |> Dict.merge( %{"meta" => "data_global"})
** (FunctionClauseError) no function clause matching in Keyword.update/4
(elixir) lib/keyword.ex:692: Keyword.update([], "meta", "data_global", #Function<3.97265964/1 in Dict.do_merge/4>)
(elixir) lib/keyword.ex:697: Keyword.update/4
(elixir) lib/dict.ex:293: anonymous fn/4 in Dict.do_merge/4
(elixir) lib/enum.ex:2865: Enumerable.Map.do_reduce/3
(elixir) lib/dict.ex:292: Dict.do_merge/4
# Key does not exist, and only Strings are used as keys
iex(18)> [meta: "data"] |> Dict.merge( %{"other" => "data_global"})
** (FunctionClauseError) no function clause matching in Keyword.update/4
(elixir) lib/keyword.ex:692: Keyword.update([], "other", "data_global", #Function<3.97265964/1 in Dict.do_merge/4>)
(elixir) lib/keyword.ex:697: Keyword.update/4
(elixir) lib/dict.ex:293: anonymous fn/4 in Dict.do_merge/4
(elixir) lib/enum.ex:2865: Enumerable.Map.do_reduce/3
(elixir) lib/dict.ex:292: Dict.do_merge/4