Splitting Registry for action and process-statistics and clean up repositry.

config.yml was only an example, so name it as config.yml.example and
ignore any config.yml, that checkout could be used as local
project-directory without conflicts.

DnsblCollector will have singleton-behaviour like process configs and an
own Registry.  Config was loaded every request, yet.
There was one Registry, which was reused for every request.  Now every
request will use his own Registry.

Requests will get the content of both Registries.
This commit is contained in:
Denis Knauf 2021-05-09 14:39:21 +02:00
parent a3e7b85a50
commit 392ac36312
4 changed files with 68 additions and 36 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*.sw[pomnqrst]
*.gem
config.yml
Gemfile.lock

View file

@ -1,6 +1,9 @@
# vim: set noet sw=2 ts=2 sts=2:
require 'rack'
require './dnsbl_exporter'
require_relative 'dnsbl_exporter'
require 'yaml'
DnsblCollector.load_config './config.yml'
run lambda {|env|
begin
@ -16,7 +19,8 @@ run lambda {|env|
end
collector.collect target
[200, {"Content-Type" => "text/plain"}, [
Prometheus::Client::Formats::Text.marshal( collector.prometheus)
Prometheus::Client::Formats::Text.marshal( collector.registry),
Prometheus::Client::Formats::Text.marshal( DnsblCollector.registry),
]]
else
[404, {"Content-Type" => "text/plain"}, ["Not found.\nYou want to try /metrics?\n"]]

View file

@ -1,7 +1,7 @@
# vim: set et sw=2 ts=2 sts=2:
---
resolver:
nameservers: 8.8.8.8
nameservers: '::1'
blacklists:
- all.s5h.net
- b.barracudacentral.org
@ -17,7 +17,6 @@ blacklists:
- dnsbl-1.uceprotect.net
- dnsbl-2.uceprotect.net
- dnsbl-3.uceprotect.net
- dnsbl.anticaptcha.net
- dnsbl.dronebl.org
- dnsbl.inps.de
- dnsbl.sorbs.net

View file

@ -1,52 +1,76 @@
# vim: set noet sw=2 ts=2 sts=2:
require 'prometheus/client'
require 'prometheus/client/formats/text'
require 'net/dns'
require 'yaml'
require 'ostruct'
class DnsblCollector
attr_reader :lists, :prometheus, :configfile, :resolver, :metrics
class DnsblCollector
class <<self
attr_reader :blacklists, :resolver, :registry
def initialize prometheus: nil, configfile: nil
@configfile = configfile || 'config.yml'
@prometheus = prometheus || Prometheus::Client.registry
%i[dnsbl_listed dnsbl_query_error].each {|m| @prometheus.unregister m }
@metrics = {
dnsbl_listed: @prometheus.gauge( :dnsbl_listed, 'IP listed currently on Blacklist'),
dnsbl_query_error: @prometheus.counter( :dnsbl_query_error, 'Errors while query for blacklist'),
}
load_config
def load_config file = nil
config = YAML.load_file file || './config.yml'
self.blacklists = config['blacklists']
self.resolver = config['resolver']
end
def blacklists= lists
@blacklists =
lists.map do |bl|
case bl
when String then {blacklist: bl}
when Hash then bl
else raise ConfigError, "Unexpected Element in blacklists: #{bl}"
end
end
end
def resolver= resolver_cnf
@resolver =
case resolver_cnf
when Net::DNS::Resolver then resolver_cnf
when Hash then Net::DNS::Resolver.new resolver_cnf
else
raise ConfigError, "DnsblCollector.resolver= expects a Net::DNS::Resolver or a resolver-config as Hash"
end
end
def registry= registry
@registry = registry
@registry.counter :dnsbl_query_error_count, docstring: 'Errors while query for blacklist', labels: %i[blacklist target]
@registry.counter :dnsbl_query_blacklist_duration_sum, docstring: 'Total duration for querieng this blacklist', labels: %i[blacklist]
@registry.counter :dnsbl_query_blacklist_count, docstring: 'Total count of queries this blacklist', labels: %i[blacklist]
end
end
def load_config
config = YAML.load_file @configfile
@resolver = config['resolver']
@lists =
config['blacklists'].map do |bl|
case bl
when String then {blacklist: bl}
when Hash then bl
else raise ConfigError, "Unexpected Element in blacklists: #{bl}"
end
end
self.registry = Prometheus::Client::Registry.new
attr_reader :lists, :registry, :configfile, :resolver, :metrics
def initialize registry: nil
@registry = registry || Prometheus::Client::Registry.new
@registry.gauge :dnsbl_listed, docstring: 'IP listed currently on Blacklist', labels: %i[blacklist target]
@metrics = OpenStruct.new @registry.instance_variable_get( :@metrics).merge( self.class.registry.instance_variable_get( :@metrics))
end
def collect ip
prefix = ip.send :_reverse
ip = ip.to_s
dns = Net::DNS::Resolver.new @resolver
todo = @lists.sort{|_|rand}
durs = {}
todo = self.class.blacklists.sort{|_|rand}
resolver = self.class.resolver
10.times.map do
Thread.new do
while bl = @lists.pop
b = Time.now
while bl = todo.pop
name, b = bl[:blacklist], Time.now
begin
r = dns.search( "#{prefix}.#{bl[:blacklist]}", Net::DNS::A).answer.empty?
@metrics[:dnsbl_listed].set( {blacklist: bl[:blacklist], target: ip}, r ? 0 : 1)
r = resolver.search( "#{prefix}.#{name}", Net::DNS::A).answer.empty?
@metrics.dnsbl_listed.set r ? 0 : 1, labels: {blacklist: name, target: ip}
rescue Net::DNS::Resolver::NoResponseError
@metrics[:dnsbl_query_error].increment( {blacklist: bl[:blacklist], target: ip})
@metrics.dnsbl_query_error_count.increment labels: {blacklist: name, target: ip}
end
durs[bl[:blacklist]] = Time.now-b
dur = Time.now-b
@metrics.dnsbl_query_blacklist_duration_sum.increment by: dur, labels: {blacklist: name}
@metrics.dnsbl_query_blacklist_count.increment labels: {blacklist: name}
end
end
end.each &:join