kiev 2.7.3

Sign up to get free protection for your applications and to get access to all the features.
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