kiev 2.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +25 -0
- data/.ruby-version +1 -0
- data/.travis.yml +27 -0
- data/Gemfile +5 -0
- data/LICENSE.md +7 -0
- data/README.md +461 -0
- data/Rakefile +18 -0
- data/bin/console +8 -0
- data/config.ru +9 -0
- data/gemfiles/que_0.12.2.gemfile +14 -0
- data/gemfiles/que_0.12.3.gemfile +15 -0
- data/gemfiles/rails_4.1.gemfile +13 -0
- data/gemfiles/rails_4.2.gemfile +13 -0
- data/gemfiles/sidekiq_4.2.gemfile +14 -0
- data/gemfiles/sinatra_1.4.gemfile +15 -0
- data/gemfiles/sinatra_2.0.gemfile +15 -0
- data/kiev.gemspec +28 -0
- data/lib/ext/rack/common_logger.rb +12 -0
- data/lib/kiev.rb +9 -0
- data/lib/kiev/base.rb +51 -0
- data/lib/kiev/base52.rb +20 -0
- data/lib/kiev/config.rb +164 -0
- data/lib/kiev/her_ext/client_request_id.rb +14 -0
- data/lib/kiev/httparty.rb +11 -0
- data/lib/kiev/json.rb +118 -0
- data/lib/kiev/logger.rb +122 -0
- data/lib/kiev/param_filter.rb +30 -0
- data/lib/kiev/que/job.rb +78 -0
- data/lib/kiev/rack.rb +20 -0
- data/lib/kiev/rack/request_id.rb +68 -0
- data/lib/kiev/rack/request_logger.rb +140 -0
- data/lib/kiev/rack/silence_action_dispatch_logger.rb +22 -0
- data/lib/kiev/rack/store_request_details.rb +21 -0
- data/lib/kiev/railtie.rb +55 -0
- data/lib/kiev/request_body_filter.rb +36 -0
- data/lib/kiev/request_body_filter/default.rb +11 -0
- data/lib/kiev/request_body_filter/form_data.rb +12 -0
- data/lib/kiev/request_body_filter/json.rb +14 -0
- data/lib/kiev/request_body_filter/xml.rb +18 -0
- data/lib/kiev/request_store.rb +32 -0
- data/lib/kiev/sidekiq.rb +41 -0
- data/lib/kiev/sidekiq/client_request_id.rb +12 -0
- data/lib/kiev/sidekiq/request_id.rb +39 -0
- data/lib/kiev/sidekiq/request_logger.rb +39 -0
- data/lib/kiev/sidekiq/request_store.rb +13 -0
- data/lib/kiev/sidekiq/store_request_details.rb +27 -0
- data/lib/kiev/subrequest_helper.rb +61 -0
- data/lib/kiev/util.rb +14 -0
- data/lib/kiev/version.rb +5 -0
- metadata +208 -0
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rspec/core/rake_task"
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
require "rake/testtask"
|
7
|
+
Rake::TestTask.new do |t|
|
8
|
+
t.libs << "test"
|
9
|
+
t.pattern = "test/**/*_test.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
require "rubocop/rake_task"
|
13
|
+
desc "Run RuboCop"
|
14
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
15
|
+
task.options = ["--display-cop-names"]
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: %w(spec test rubocop)
|
data/bin/console
ADDED
data/config.ru
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "oj"
|
4
|
+
|
5
|
+
# Build brakes with 0.12.3, TODO: handle this
|
6
|
+
gem "que", "0.12.2"
|
7
|
+
gem "pg"
|
8
|
+
gem "sequel"
|
9
|
+
|
10
|
+
gem "rack-test", require: false
|
11
|
+
gem "rspec", require: false
|
12
|
+
gem "minitest-reporters", require: false
|
13
|
+
|
14
|
+
gemspec :path => "../"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# need it because of bug in https://github.com/chanks/que/issues/191
|
4
|
+
gem "multi_json"
|
5
|
+
gem "oj"
|
6
|
+
|
7
|
+
gem "que", ">= 0.12.3"
|
8
|
+
gem "pg"
|
9
|
+
gem "sequel"
|
10
|
+
|
11
|
+
gem "rack-test", require: false
|
12
|
+
gem "rspec", require: false
|
13
|
+
gem "minitest-reporters", require: false
|
14
|
+
|
15
|
+
gemspec :path => "../"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "oj"
|
4
|
+
|
5
|
+
gem "xml-simple"
|
6
|
+
|
7
|
+
gem "sinatra", "1.4.7"
|
8
|
+
gem "sinatra-contrib"
|
9
|
+
gem "rack-parser", :require => "rack/parser"
|
10
|
+
|
11
|
+
gem "rack-test", require: false
|
12
|
+
gem "rspec", require: false
|
13
|
+
gem "minitest-reporters", require: false
|
14
|
+
|
15
|
+
gemspec :path => "../"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "oj"
|
4
|
+
|
5
|
+
gem "xml-simple"
|
6
|
+
|
7
|
+
gem "sinatra", "2.0.0"
|
8
|
+
gem "sinatra-contrib"
|
9
|
+
gem "rack-parser", :require => "rack/parser"
|
10
|
+
|
11
|
+
gem "rack-test", require: false
|
12
|
+
gem "rspec", require: false
|
13
|
+
gem "minitest-reporters", require: false
|
14
|
+
|
15
|
+
gemspec :path => "../"
|
data/kiev.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), "lib/kiev/version")
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "kiev"
|
7
|
+
spec.version = Kiev::VERSION
|
8
|
+
spec.authors = ["Blacklane"]
|
9
|
+
spec.licenses = ["MIT"]
|
10
|
+
|
11
|
+
spec.summary = "Distributed logging to JSON integrated with various Ruby frameworks and tools"
|
12
|
+
spec.description = "Kiev is a logging tool aimed at distributed environments. It logs to JSON, while providing human-readable output in development mode. It integrates nicely with Rails, Sinatra and other Rack-based frameworks, Sidekiq, Que, HTTParty, Her and other Faraday-based HTTP clients."
|
13
|
+
spec.homepage = "https://github.com/blacklane/kiev"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.required_ruby_version = ">= 2.0.0"
|
21
|
+
spec.add_dependency "rack", ">= 1", "< 3"
|
22
|
+
spec.add_dependency "request_store", ">= 1.0", "< 1.4"
|
23
|
+
spec.add_dependency "oga", "~> 2.2"
|
24
|
+
spec.add_dependency "ruby_dig", "~> 0.0.2" # to support ruby 2.2
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "rubocop", "0.49.1"
|
28
|
+
end
|
data/lib/kiev.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "kiev/base"
|
4
|
+
require_relative "kiev/rack" if defined?(Rack)
|
5
|
+
require_relative "kiev/railtie" if defined?(Rails)
|
6
|
+
require_relative "kiev/sidekiq" if defined?(Sidekiq)
|
7
|
+
require_relative "kiev/her_ext/client_request_id" if defined?(Faraday)
|
8
|
+
require_relative "kiev/httparty" if defined?(HTTParty)
|
9
|
+
require_relative "kiev/que/job" if defined?(Que::Job)
|
data/lib/kiev/base.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "request_store"
|
4
|
+
require "ruby_dig"
|
5
|
+
require_relative "request_store"
|
6
|
+
require_relative "logger"
|
7
|
+
require_relative "param_filter"
|
8
|
+
require_relative "request_body_filter"
|
9
|
+
require_relative "json"
|
10
|
+
require_relative "version"
|
11
|
+
require_relative "config"
|
12
|
+
require_relative "util"
|
13
|
+
require_relative "subrequest_helper"
|
14
|
+
|
15
|
+
module Kiev
|
16
|
+
class << self
|
17
|
+
EMPTY_OBJ = {}.freeze
|
18
|
+
|
19
|
+
def configure
|
20
|
+
yield(Config.instance)
|
21
|
+
end
|
22
|
+
|
23
|
+
def logger
|
24
|
+
Config.instance.logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def event(event_name, data = EMPTY_OBJ)
|
28
|
+
logger.log(::Logger::Severity::INFO, data, event_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def []=(name, value)
|
32
|
+
RequestStore.store[:payload] ||= {}
|
33
|
+
RequestStore.store[:payload][name] = value
|
34
|
+
end
|
35
|
+
|
36
|
+
def payload(data)
|
37
|
+
raise ArgumentError, "Hash expected" unless data.is_a?(Hash)
|
38
|
+
|
39
|
+
RequestStore.store[:payload] ||= {}
|
40
|
+
RequestStore.store[:payload].merge!(data)
|
41
|
+
end
|
42
|
+
|
43
|
+
def error=(value)
|
44
|
+
RequestStore.store[:error] = value
|
45
|
+
end
|
46
|
+
|
47
|
+
def request_id
|
48
|
+
RequestStore.store[:request_id]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/kiev/base52.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Kiev
|
4
|
+
module Base52
|
5
|
+
KEYS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".freeze
|
6
|
+
BASE = KEYS.length.freeze
|
7
|
+
|
8
|
+
def self.encode(num)
|
9
|
+
return KEYS[0] if num == 0
|
10
|
+
return nil if num < 0
|
11
|
+
|
12
|
+
str = ""
|
13
|
+
while num > 0
|
14
|
+
str.prepend(KEYS[num % BASE])
|
15
|
+
num /= BASE
|
16
|
+
end
|
17
|
+
str
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/kiev/config.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module Kiev
|
6
|
+
class Config
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
DEFAULT_LOG_REQUEST_REGEXP = %r{(^(/ping|/health))|(\.(js|css|png|jpg|gif|ico|svg)$)}
|
10
|
+
private_constant :DEFAULT_LOG_REQUEST_REGEXP
|
11
|
+
|
12
|
+
DEFAULT_LOG_REQUEST_CONDITION = proc do |request, _response|
|
13
|
+
!DEFAULT_LOG_REQUEST_REGEXP.match(request.path)
|
14
|
+
end
|
15
|
+
|
16
|
+
DEFAULT_LOG_REQUEST_ERROR_CONDITION = proc do |_request, response|
|
17
|
+
response.status != 404
|
18
|
+
end
|
19
|
+
|
20
|
+
DEFAULT_LOG_RESPONSE_BODY_REGEXP = /(json|xml)/
|
21
|
+
private_constant :DEFAULT_LOG_RESPONSE_BODY_REGEXP
|
22
|
+
|
23
|
+
DEFAULT_LOG_RESPONSE_BODY_CONDITION = proc do |_request, response|
|
24
|
+
!!(response.status >= 400 && response.status < 500 && response.content_type =~ DEFAULT_LOG_RESPONSE_BODY_REGEXP)
|
25
|
+
end
|
26
|
+
|
27
|
+
DEFAULT_LOG_REQUEST_BODY_CONDITION = proc do |request, _response|
|
28
|
+
!!(request.content_type =~ /(application|text)\/xml/)
|
29
|
+
end
|
30
|
+
|
31
|
+
DEFAULT_IGNORED_RACK_EXCEPTIONS =
|
32
|
+
%w(
|
33
|
+
ActiveRecord::RecordNotFound
|
34
|
+
Mongoid::Errors::DocumentNotFound
|
35
|
+
Sequel::RecordNotFound
|
36
|
+
).freeze
|
37
|
+
|
38
|
+
FILTERED_PARAMS =
|
39
|
+
%w(
|
40
|
+
client_secret
|
41
|
+
token
|
42
|
+
password
|
43
|
+
password_confirmation
|
44
|
+
old_password
|
45
|
+
credit_card_number
|
46
|
+
credit_card_cvv
|
47
|
+
credit_card_holder
|
48
|
+
credit_card_expiry_month
|
49
|
+
credit_card_expiry_year
|
50
|
+
CardNumber
|
51
|
+
CardCVV
|
52
|
+
CardExpires
|
53
|
+
).freeze
|
54
|
+
|
55
|
+
IGNORED_PARAMS =
|
56
|
+
(%w(
|
57
|
+
controller
|
58
|
+
action
|
59
|
+
format
|
60
|
+
authenticity_token
|
61
|
+
utf8
|
62
|
+
tempfile
|
63
|
+
) << :tempfile).freeze
|
64
|
+
|
65
|
+
DEFAULT_HTTP_PROPAGATED_FIELDS = {
|
66
|
+
request_id: "X-Request-Id",
|
67
|
+
request_depth: "X-Request-Depth",
|
68
|
+
tree_path: "X-Tree-Path"
|
69
|
+
}.freeze
|
70
|
+
|
71
|
+
DEFAULT_PRE_RACK_HOOK = proc do |env|
|
72
|
+
Config.instance.http_propagated_fields.each do |key, http_key|
|
73
|
+
Kiev[key] = Util.sanitize(env[Util.to_http(http_key)])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_accessor :app,
|
78
|
+
:log_request_condition,
|
79
|
+
:log_request_error_condition,
|
80
|
+
:log_response_body_condition,
|
81
|
+
:log_request_body_condition,
|
82
|
+
:filtered_params,
|
83
|
+
:ignored_params,
|
84
|
+
:ignored_rack_exceptions,
|
85
|
+
:disable_default_logger,
|
86
|
+
:persistent_log_fields,
|
87
|
+
:pre_rack_hook
|
88
|
+
|
89
|
+
attr_reader :development_mode,
|
90
|
+
:logger,
|
91
|
+
:http_propagated_fields,
|
92
|
+
:jobs_propagated_fields,
|
93
|
+
:all_http_propagated_fields, # for internal use
|
94
|
+
:all_jobs_propagated_fields # for internal use
|
95
|
+
|
96
|
+
def initialize
|
97
|
+
@log_request_condition = DEFAULT_LOG_REQUEST_CONDITION
|
98
|
+
@log_request_error_condition = DEFAULT_LOG_REQUEST_ERROR_CONDITION
|
99
|
+
@log_response_body_condition = DEFAULT_LOG_RESPONSE_BODY_CONDITION
|
100
|
+
@log_request_body_condition = DEFAULT_LOG_REQUEST_BODY_CONDITION
|
101
|
+
@filtered_params = FILTERED_PARAMS
|
102
|
+
@ignored_params = IGNORED_PARAMS
|
103
|
+
@disable_default_logger = true
|
104
|
+
@development_mode = false
|
105
|
+
@ignored_rack_exceptions = DEFAULT_IGNORED_RACK_EXCEPTIONS.dup
|
106
|
+
@logger = Kiev::Logger.new(STDOUT)
|
107
|
+
@log_level = nil
|
108
|
+
@persistent_log_fields = []
|
109
|
+
@pre_rack_hook = DEFAULT_PRE_RACK_HOOK
|
110
|
+
self.propagated_fields = {}
|
111
|
+
update_logger_settings
|
112
|
+
end
|
113
|
+
|
114
|
+
def http_propagated_fields=(value)
|
115
|
+
@all_http_propagated_fields = DEFAULT_HTTP_PROPAGATED_FIELDS.merge(value)
|
116
|
+
@http_propagated_fields = @all_http_propagated_fields.dup
|
117
|
+
DEFAULT_HTTP_PROPAGATED_FIELDS.keys.each do |key|
|
118
|
+
@http_propagated_fields.delete(key)
|
119
|
+
end
|
120
|
+
@http_propagated_fields.freeze
|
121
|
+
end
|
122
|
+
|
123
|
+
def jobs_propagated_fields=(value)
|
124
|
+
@all_jobs_propagated_fields = (DEFAULT_HTTP_PROPAGATED_FIELDS.keys + value).uniq.freeze
|
125
|
+
@jobs_propagated_fields = (@all_jobs_propagated_fields - DEFAULT_HTTP_PROPAGATED_FIELDS.keys).freeze
|
126
|
+
end
|
127
|
+
|
128
|
+
# shortcut
|
129
|
+
def propagated_fields=(value)
|
130
|
+
self.http_propagated_fields = value
|
131
|
+
self.jobs_propagated_fields = value.keys
|
132
|
+
end
|
133
|
+
|
134
|
+
def log_path=(value)
|
135
|
+
logger.path = value
|
136
|
+
update_logger_settings
|
137
|
+
end
|
138
|
+
|
139
|
+
def log_level=(value)
|
140
|
+
@log_level = value
|
141
|
+
update_logger_settings
|
142
|
+
end
|
143
|
+
|
144
|
+
def development_mode=(value)
|
145
|
+
@development_mode = value
|
146
|
+
update_logger_settings
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def update_logger_settings
|
152
|
+
@logger.formatter = formatter
|
153
|
+
@logger.level = @log_level || default_log_level
|
154
|
+
end
|
155
|
+
|
156
|
+
def formatter
|
157
|
+
development_mode ? Logger::DEVELOPMENT_FORMATTER : Logger::FORMATTER
|
158
|
+
end
|
159
|
+
|
160
|
+
def default_log_level
|
161
|
+
development_mode ? ::Logger::DEBUG : ::Logger::INFO
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Kiev
|
6
|
+
module HerExt
|
7
|
+
class ClientRequestId < Faraday::Middleware
|
8
|
+
def call(env)
|
9
|
+
env[:request_headers].merge!(SubrequestHelper.headers)
|
10
|
+
@app.call(env)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|