The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package App;

use Mojo::Base 'Mojolicious';

use Data::Dumper;
use File::Spec;

has options => sub { {} };

sub startup
{
    $Data::Dumper::Sortkeys = 1;

    my $self = shift;
    $self->plugin('ParamLogger', %{$self->options});

    my %log;
    $self->app->log->path(File::Spec->devnull);
    $self->app->log->on(message => sub {
	my ($log, $level, @messages) = @_;
	$log{$messages[0]} = $level;
    });

    $self->routes->get('/')->to(cb => sub {
	my $data = '';
	$data .= "$log{$_}: $_\n" for keys %log;

	shift->render(text => $data);
	%log = ();
    });
}

package main;

use Mojo::Base -strict;
use Test::More tests => 17;
use Test::Mojo;

$ENV{MOJO_LOG_LEVEL} = 'debug';

eval { App->new(options => { level => 'bad' }) };
like($@, qr/unknown log level 'bad'/);

my $t = Test::Mojo->new(App->new);
$t->get_ok('/')->content_like(qr|debug: GET / \{}|, 'no params logged');
$t->get_ok('/?a=1&b=2')->content_like(qr|debug: GET / \{ "a" => 1, "b" => 2 }|, 'multiple params logged');
$t->get_ok('/?password=p@ss')->content_like(qr|debug: GET / \{ "password" => "########" }|, 'password filtered');

$t = Test::Mojo->new(App->new(options => { filter => 'a' }));
$t->get_ok('/?a=1')->content_like(qr|debug: GET / \{ "a" => "########" }|, 'single param filtered');

$t = Test::Mojo->new(App->new(options => { filter => ['a', 'b'] }));
$t->get_ok('/?a=1&b=2&c=3')->content_like(qr|debug: GET / \{ "a" => "########", "b" => "########", "c" => 3 }|, 'multiple params filtered');

$t = Test::Mojo->new(App->new(options => { level => 'info' }));
$t->get_ok('/')->content_like(qr|info: GET / \{}|, 'log level');

$t = Test::Mojo->new(App->new(mode => 'production'));
$t->get_ok('/')->content_unlike(qr|info: GET / \{}|, 'disabled for production');

$t = Test::Mojo->new(App->new(mode => 'production', options => { production => 1 }));
$t->get_ok('/')->content_like(qr|info: GET / \{}|, 'enabled for production');