kiev 2.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +25 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +27 -0
  7. data/Gemfile +5 -0
  8. data/LICENSE.md +7 -0
  9. data/README.md +461 -0
  10. data/Rakefile +18 -0
  11. data/bin/console +8 -0
  12. data/config.ru +9 -0
  13. data/gemfiles/que_0.12.2.gemfile +14 -0
  14. data/gemfiles/que_0.12.3.gemfile +15 -0
  15. data/gemfiles/rails_4.1.gemfile +13 -0
  16. data/gemfiles/rails_4.2.gemfile +13 -0
  17. data/gemfiles/sidekiq_4.2.gemfile +14 -0
  18. data/gemfiles/sinatra_1.4.gemfile +15 -0
  19. data/gemfiles/sinatra_2.0.gemfile +15 -0
  20. data/kiev.gemspec +28 -0
  21. data/lib/ext/rack/common_logger.rb +12 -0
  22. data/lib/kiev.rb +9 -0
  23. data/lib/kiev/base.rb +51 -0
  24. data/lib/kiev/base52.rb +20 -0
  25. data/lib/kiev/config.rb +164 -0
  26. data/lib/kiev/her_ext/client_request_id.rb +14 -0
  27. data/lib/kiev/httparty.rb +11 -0
  28. data/lib/kiev/json.rb +118 -0
  29. data/lib/kiev/logger.rb +122 -0
  30. data/lib/kiev/param_filter.rb +30 -0
  31. data/lib/kiev/que/job.rb +78 -0
  32. data/lib/kiev/rack.rb +20 -0
  33. data/lib/kiev/rack/request_id.rb +68 -0
  34. data/lib/kiev/rack/request_logger.rb +140 -0
  35. data/lib/kiev/rack/silence_action_dispatch_logger.rb +22 -0
  36. data/lib/kiev/rack/store_request_details.rb +21 -0
  37. data/lib/kiev/railtie.rb +55 -0
  38. data/lib/kiev/request_body_filter.rb +36 -0
  39. data/lib/kiev/request_body_filter/default.rb +11 -0
  40. data/lib/kiev/request_body_filter/form_data.rb +12 -0
  41. data/lib/kiev/request_body_filter/json.rb +14 -0
  42. data/lib/kiev/request_body_filter/xml.rb +18 -0
  43. data/lib/kiev/request_store.rb +32 -0
  44. data/lib/kiev/sidekiq.rb +41 -0
  45. data/lib/kiev/sidekiq/client_request_id.rb +12 -0
  46. data/lib/kiev/sidekiq/request_id.rb +39 -0
  47. data/lib/kiev/sidekiq/request_logger.rb +39 -0
  48. data/lib/kiev/sidekiq/request_store.rb +13 -0
  49. data/lib/kiev/sidekiq/store_request_details.rb +27 -0
  50. data/lib/kiev/subrequest_helper.rb +61 -0
  51. data/lib/kiev/util.rb +14 -0
  52. data/lib/kiev/version.rb +5 -0
  53. metadata +208 -0
@@ -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)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require_relative "../lib/kiev"
6
+
7
+ require "irb"
8
+ IRB.start
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubygems"
4
+ require "bundler"
5
+
6
+ Bundler.require :default, :development
7
+
8
+ Combustion.initialize!(:all)
9
+ run Combustion::Application
@@ -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,13 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "oj"
4
+
5
+ gem "rails", "4.1.16"
6
+ gem "sqlite3"
7
+
8
+ gem "combustion"
9
+ gem "rspec", require: false
10
+ gem "rspec-rails", require: false
11
+ gem "minitest-reporters", require: false
12
+
13
+ gemspec :path => "../"
@@ -0,0 +1,13 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "oj"
4
+
5
+ gem "rails", "4.2.7"
6
+ gem "sqlite3"
7
+
8
+ gem "combustion"
9
+ gem "rspec", require: false
10
+ gem "rspec-rails", require: false
11
+ gem "minitest-reporters", require: false
12
+
13
+ gemspec :path => "../"
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "oj", "~> 2"
4
+
5
+ gem "sidekiq", "~> 4.2.0"
6
+
7
+ gem "rack-test", require: false
8
+ gem "rspec", require: false
9
+ gem "minitest-reporters", require: false
10
+
11
+ gem "her"
12
+
13
+ gemspec :path => "../"
14
+
@@ -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 => "../"
@@ -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
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Disable useless rack logger completely!
4
+ # for some reason disable :logging doesn't work for sinatra
5
+ module Rack
6
+ class CommonLogger
7
+ def call(env)
8
+ # do nothing
9
+ @app.call(env)
10
+ end
11
+ end
12
+ end
@@ -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)
@@ -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
@@ -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
@@ -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