wfgilman

wfgilman

ExUnit.CaptureLog assert capture_log/2 not capturing level "info"

I’m testing my rate limiting plug and I want to make sure the plug logs an rate limit violations. However, I want this log to be at level :info. The assertion works when I log it at level :error or :warn, but not at :info. I tried setting the options in capture_log/2 but it didn’t have any effect. Am I missing something?

Test

test "rate_limit/2 puts 429 status if rate limit is exceeded", %{conn: conn, opts: opts} do
  breach = opts[:max_requests] + 1
  for req <- 1..breach do
    if req == breach do
      assert capture_log([level: :info], fn ->
        conn = Api.RateLimit.rate_limit(conn, opts)
        assert conn.status == 429
      end) =~ "Rate limit violation for bucket"
    else
      Api.RateLimit.rate_limit(conn, opts)
    end
  end
end

Function

  def rate_limit(conn, opts) do
    case check_rate(conn, opts) do
      {:ok, _count} ->
        conn
      {:error, _count} ->
        Logger.info(fn ->
          bucket = opts[:bucket_name] || default_bucket_name(conn)
          "Rate limit violation for bucket: #{inspect bucket}"
        end)
        render_error(conn)
    end
  end

Marked As Solved

OvermindDL1

OvermindDL1

@wfgilman Have you looked at: https://github.com/wfgilman/log_capture_test/blob/master/config/test.exs#L9-L10

# Print only warnings and errors during test
config :logger, level: :warn

And considering the test that is not passing runs this code: https://github.com/wfgilman/log_capture_test/blob/master/lib/log_capture/rate_limit.ex#L5-L8

def rate_limit(conn, _opts) do
  Logger.info(fn -> "Rate limit violation" end)
  conn
end

It will not print anything, hence why it does not pass. ^.^

You need to adjust the test config to be :info instead of :warn or so.

Also Liked

eteeselink

eteeselink

At the risk of terrible necroposting and of stating the obvious: I ran into this same problem and saw that the OP’s last remarks went unanswered. I found a solution, so maybe other googlers are helped by this:

Our test.exs had

config :logger,
 level: :warn 

and only by setting it to :info I could get my capture_log assertions to capture the relevant logs.

However, it totally polluted the test output. As described, setting the log level to :warn actually removes the :debug and :info level log statements from the compiled code entirely.

Fortunately, there’s a way around this:

# capture all logs...
config :logger,
  level: :debug

# ... but show only warnings and up on the console
config :logger, :console, 
  level: :warn

This works because Logger’s default backend, console, can be separately configured to filter log levels. That way the Logger.info calls etc are not removed from the code, but the console output is still sane.

I found it all to be documented pretty well in the Logger docs btw: https://hexdocs.pm/logger/Logger.html

jc00ke

jc00ke

Best. Necropost. Ever.

I must have missed it, so thank you for stating the obvious!

My logs are now much less noisy :pray:

jc00ke

jc00ke

I had this exact issue, changing to level: :info worked wonders.

However, now my test output is really noisy. Any way to get the benefits of warn with respect to test output but still able to capture info?

Am I reading this incorrectly? elixir/lib/ex_unit/lib/ex_unit/capture_log.ex at v1.7.4 · elixir-lang/elixir · GitHub

It is possible to configure the level to capture with :level , which will set the capturing level for the duration of the capture, for instance, if the log level is set to :error any message with the lower level will be ignored. The default level is nil , which will capture all messages. The behaviour is undetermined if async tests change Logger level.

I would expect that, even if config :logger, level: :warn is set, that

capture_log([level: :info], fn ->
  Logger.info "..."
end)

would still capture, though that would seemingly contradict

The Logger.info/2 macro emits the provided message at the :info level. Note the arguments given to info/2 will only be evaluated if a message is logged. For instance, if the Logger level is set to :warn , :info messages are never logged and therefore the arguments given above won’t even be executed.

wfgilman

wfgilman

Ah, yes I overlooked that. I updated the config and that test passed. Thanks for spotting that. By default, capture_log/2 is supposed to capture all logs, but I need to make sure the application is emitting all logs for that to work :slight_smile:

josevalim

josevalim

Creator of Elixir

Can you please confirm how you are calling Logger.info? The API used in your example above is invalid and will raise an ArgumentError.

Where Next?

Popular in Questions Top

LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
Kagamiiiii
Student &amp; New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
sabri
Can someone explain the settings of pool_size of Ecto in config file? and what is the recommend size? Thanks
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

Other popular topics Top

pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

We're in Beta

About us Mission Statement