Packages
honeybadger
0.15.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.1
0.24.0
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.1
0.18.0
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.7.0-beta
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.0
0.3.1
0.3.0
0.2.0
0.1.2
0.1.1
0.1.0
Elixir client, Plug and error_logger for integrating with the Honeybadger.io exception tracker"
Current section
Files
Jump to
Current section
Files
lib/honeybadger/utils.ex
defmodule Honeybadger.Utils do
@moduledoc """
Assorted helper functions used through out the Honeybadger package.
"""
@doc """
Internally all modules are prefixed with Elixir. This function removes the
`Elixir` prefix from the module when it is converted to a string.
# Example
iex> Honeybadger.Utils.module_to_string(Honeybadger.Utils)
"Honeybadger.Utils"
"""
def module_to_string(module) do
module
|> Module.split()
|> Enum.join(".")
end
@doc """
Transform value into a consistently cased string representation
# Example
iex> Honeybadger.Utils.canonicalize(:User_SSN)
"user_ssn"
"""
def canonicalize(val) do
val
|> to_string()
|> String.downcase()
end
@doc """
Configurable data sanitization. This currently:
- recursively truncates deep structures (to a depth of 20)
- constrains large string values (to 64k)
- filters out any map keys that might contain sensitive information.
"""
@depth_token "[DEPTH]"
@truncated_token "[TRUNCATED]"
@filtered_token "[FILTERED]"
# 64k with enough space to concat truncated_token
@default_max_string_size 64 * 1024 - 11
@default_max_depth 20
def sanitize(value, opts \\ []) do
base = %{
max_depth: @default_max_depth,
max_string_size: @default_max_string_size,
filter_keys: Honeybadger.get_env(:filter_keys)
}
opts =
Enum.into(opts, base)
|> Map.update!(:filter_keys, fn v -> MapSet.new(v, &canonicalize/1) end)
sanitize_val(value, Map.put(opts, :depth, 0))
end
defp sanitize_val(v, %{depth: depth, max_depth: depth}) when is_map(v) or is_list(v) do
@depth_token
end
defp sanitize_val(%{__struct__: _} = struct, opts) do
sanitize_val(Map.from_struct(struct), opts)
end
defp sanitize_val(v, %{depth: depth, filter_keys: filter_keys} = opts) when is_map(v) do
for {key, val} <- v, into: %{} do
if MapSet.member?(filter_keys, canonicalize(key)) do
{key, @filtered_token}
else
{key, sanitize_val(val, Map.put(opts, :depth, depth + 1))}
end
end
end
defp sanitize_val(v, %{depth: depth} = opts) when is_list(v) do
Enum.map(v, &sanitize_val(&1, Map.put(opts, :depth, depth + 1)))
end
defp sanitize_val(v, %{max_string_size: max_string_size}) when is_binary(v) do
if String.valid?(v) and String.length(v) > max_string_size do
String.slice(v, 0, max_string_size) <> @truncated_token
else
v
end
end
defp sanitize_val(v, _), do: v
end