In our application we want to filter certain parameters differently depending on their usage... for example passwords should always be filtered entirely, but for email and name we want to retain parts of the value for debugging and support.
To do this, we've used a custom proc to format them:
1_filter_parameter_logging.rb
:
Rails.application.config.filter_parameters += [
:password
]
Rails.application.config.filter_parameters << proc do |param_name, value|
if %w[email name].include?(param_name)
if param_name.to_s == 'email'
value.gsub!(/(?<=^.{2}).*?(?=@)/, '*') # test partial filter
else
value.replace('[FILTERED_CUSTOM]') # test custom filter
end
end
end
Then in 2_airbrake.rb
we use these settings as so:
c.blacklist_keys = Rails.application.config.filter_parameters
To test this theory, we deliberately throw an exception in our app with this example controller action:
class ExampleController
def show
raise StandardError, 'Testing Filter Parameter Logging'
end
end
And then make a simple request to that endpoint:
http://localhost:3000/example?name=cameron&[email protected]&password=test
In our logs we see the following:
Processing by ExampleController#show as HTML
Parameters: {"name"=>"[FILTERED_CUSTOM]", "email"=>"ca*@test.com", "password"=>"[FILTERED]"}
And then an error from Airbake:
**Airbrake: one of the patterns in Airbrake::Filters::KeysBlacklist is invalid. Known patterns: [:password, nil]
And if we look at the error in Airbrake we see that it hasn't filtered them:
{
"action" => "show",
"controller" => "example",
"email" => "[email protected]",
"name" => "cameron",
"password" => "[Filtered]"
}
Why is Airbrake throwing that error, seems Rails is able to filter those parameters using that proc based on those logs, but then Airbrake fails to filter them and allows them through.
Airbrake doesn't explain exactly what's invalid with the pattern... just that it doesn't see it as valid, which isn't very helpful.
The param filtering offered by Rails is different than Airbrake.
Rails allows for complex param filtering. You can define a proc
that takes in the parameter key
and value
as arguments and returns the filtered value. The execution of the proc
happens here in ActiveSupport::ParameterFilter#value_for_key
.
Airbrake is more limited. It can only filter parameter names by comparing them against a String, Symbol, or Regexp. The documentation indicates that you can define a proc
but it only gets executed once on the first notification and:
The Proc must return an Array consisting only of the elements, which are considered to be valid for this option.
The proc
is executed here. It is called without any arguments. If your example proc
is called without arguments it returns nil
. Since this doesn't match a String, Symbol, or Regexp an exception is raised here.
Airbrake uses a should_filter?
method that takes just the param key
. If that method returns true
the "[Filtered]"
string replaces the value. This existing structure isn't easy to quickly override to get the behavior you want. But you could try to completely override the Airbrake::Filters::KeysBlocklist
class and Airbrake::Filters::KeysFilter
module.
Note that the info here and all the links are for the current version of airbrake-ruby
. blacklist_keys
was replaced by blocklist_keys
several years ago. And classes like KeysBlacklist
were replaced by KeysBlocklist
. But these were just naming changes and functionality has remained relatively the same over time.
Rather than override the standard Airbrake param filtering, you're probably better off trying to add a custom filter. Here's an example of what you could try to put into an initializer in your app:
Airbrake.add_filter do |notice|
notice[:params].each do |key, value|
if key == :email
value.gsub!(/(?<=^.{2}).*?(?=@)/, '*') # test partial filter
elsif key == :name
value.replace('[FILTERED_CUSTOM]') # test custom filter
end
end
end