Skip to content

Commit

Permalink
Allow passing the slicer module in as an option to the Tesla middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivor committed Oct 7, 2024
1 parent 24377d1 commit 1cbee1a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 38 deletions.
76 changes: 40 additions & 36 deletions lib/meta_logger/slicer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,46 @@ defmodule MetaLogger.Slicer do

@typedoc "Max length in bytes or `:infinity` if the entry should not be sliced."
@type max_entry_length :: non_neg_integer() | :infinity

@doc """
Returns sliced log entries according to the given max entry length.
If the entry is smaller than given max length, or if `:infinity ` is given
as option, a list with one entry is returned. Otherwise a list with multiple
entries is returned.
## Examples
iex> #{inspect(__MODULE__)}.slice("1234567890", 10)
["1234567890"]
iex> #{inspect(__MODULE__)}.slice("1234567890", :infinity)
["1234567890"]
iex> #{inspect(__MODULE__)}.slice("1234567890", 5)
["12345", "67890"]
"""
@spec slice(String.t(), max_entry_length()) :: [String.t()]
def slice(entry, max_entry_length)
when max_entry_length == :infinity
when byte_size(entry) <= max_entry_length,
do: [entry]

def slice(entry, max_entry_length) do
entry_length = byte_size(entry)
rem = rem(entry_length, max_entry_length)
sliced_entries = for <<slice::binary-size(max_entry_length) <- entry>>, do: slice

if rem > 0 do
remainder_entry = binary_part(entry, entry_length, rem * -1)
sliced_entries ++ [remainder_entry]
else
sliced_entries
@callback slice(String.t(), max_entry_length()) :: [String.t()]

defmodule Default do

Check warning on line 10 in lib/meta_logger/slicer.ex

View workflow job for this annotation

GitHub Actions / Static Code Analysis

Modules should have a @moduledoc tag.
@behaviour MetaLogger.Slicer
@doc """
Returns sliced log entries according to the given max entry length.
If the entry is smaller than given max length, or if `:infinity ` is given
as option, a list with one entry is returned. Otherwise a list with multiple
entries is returned.
## Examples
iex> #{inspect(__MODULE__)}.slice("1234567890", 10)
["1234567890"]
iex> #{inspect(__MODULE__)}.slice("1234567890", :infinity)
["1234567890"]
iex> #{inspect(__MODULE__)}.slice("1234567890", 5)
["12345", "67890"]
"""
@impl MetaLogger.Slicer
def slice(entry, max_entry_length)
when max_entry_length == :infinity
when byte_size(entry) <= max_entry_length,
do: [entry]

def slice(entry, max_entry_length) do
entry_length = byte_size(entry)
rem = rem(entry_length, max_entry_length)
sliced_entries = for <<slice::binary-size(max_entry_length) <- entry>>, do: slice

if rem > 0 do
remainder_entry = binary_part(entry, entry_length, rem * -1)
sliced_entries ++ [remainder_entry]
else
sliced_entries
end
end
end
end
4 changes: 3 additions & 1 deletion lib/tesla/middleware/meta_logger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ if Code.ensure_loaded?(Tesla) do
|> maybe_put_default_value(:log_level, :info)
|> maybe_put_default_value(:log_tag, __MODULE__)
|> maybe_put_default_value(:max_entry_length, :infinity)
|> maybe_put_default_value(:slicer, MetaLogger.Slicer.Default)
end

@spec maybe_put_default_values(Env.opts(), [atom()], any()) :: Env.opts()
Expand Down Expand Up @@ -182,9 +183,10 @@ if Code.ensure_loaded?(Tesla) do

defp log(message, level, options) when is_binary(message) do
max_entry_length = Keyword.get(options, :max_entry_length)
slicer = Keyword.get(options, :slicer)

message
|> Slicer.slice(max_entry_length)
|> slicer.slice(max_entry_length)
|> Enum.map(&prepend_tag(&1, options))
|> Enum.each(&MetaLogger.log(level, &1))
end
Expand Down
2 changes: 1 addition & 1 deletion test/meta_logger/slicer_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule MetaLogger.SlicerTest do
use ExUnit.Case, async: true

alias MetaLogger.Slicer, as: Subject
alias MetaLogger.Slicer.Default, as: Subject

doctest Subject

Expand Down
21 changes: 21 additions & 0 deletions test/tesla/middleware/meta_logger_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ defmodule Tesla.Middleware.MetaLoggerTest do

alias Tesla.Middleware.MetaLogger, as: Subject

defmodule AlternativeSlicer do
@behaviour MetaLogger.Slicer

@impl MetaLogger.Slicer
def slice(entry, _max_entry_length) do
["slice1", "slice2"]
end
end

defmodule FakeClient do
use Tesla

Expand Down Expand Up @@ -251,6 +260,18 @@ defmodule Tesla.Middleware.MetaLoggerTest do
assert logs =~ "[warning] [#{inspect(Subject)}] response body moved"
end

test "when a slicer module is given, uses it to slice the message" do
logs =
capture_log(fn ->
FakeClient.post("/huge-response", "1234567890",
opts: [slicer: __MODULE__.AlternativeSlicer]
)
end)

assert logs =~ "[debug] [Tesla.Middleware.MetaLogger] slice1"
assert logs =~ "[debug] [Tesla.Middleware.MetaLogger] slice2"
end

test "when the request fails to connect, logs the error" do
logs = capture_log(fn -> FakeClient.get("/connection-error") end)

Expand Down

0 comments on commit 1cbee1a

Please sign in to comment.