kiev 4.3.0 → 4.7.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/push.yml +80 -0
- data/.rubocop.yml +8 -1
- data/.ruby-version +1 -1
- data/Gemfile +1 -1
- data/README.md +34 -2
- data/gemfiles/que_0.12.2.gemfile +3 -1
- data/gemfiles/que_0.12.3.gemfile +3 -1
- data/gemfiles/rails_4.1.gemfile +3 -1
- data/gemfiles/rails_4.2.gemfile +3 -1
- data/gemfiles/rails_5.2.gemfile +15 -0
- data/gemfiles/ruby_kafka.gemfile +11 -0
- data/gemfiles/{shoryuken_3.1.gemfile → shoryuken_4.0.gemfile} +4 -2
- data/gemfiles/sidekiq_4.2.gemfile +3 -2
- data/gemfiles/sinatra_1.4.gemfile +4 -2
- data/gemfiles/sinatra_2.0.gemfile +4 -2
- data/kiev.gemspec +8 -6
- data/lib/kiev/aws_sns/context_injector.rb +22 -0
- data/lib/kiev/aws_sns.rb +16 -0
- data/lib/kiev/base.rb +17 -3
- data/lib/kiev/base52.rb +1 -1
- data/lib/kiev/config.rb +1 -0
- data/lib/kiev/context_reader.rb +6 -3
- data/lib/kiev/kafka/context_extractor.rb +26 -0
- data/lib/kiev/kafka/context_injector.rb +20 -0
- data/lib/kiev/kafka/message_context.rb +27 -0
- data/lib/kiev/kafka.rb +22 -0
- data/lib/kiev/logger.rb +13 -12
- data/lib/kiev/param_filter.rb +27 -4
- data/lib/kiev/que/job.rb +2 -1
- data/lib/kiev/rack/request_id.rb +15 -13
- data/lib/kiev/rack/request_logger.rb +2 -4
- data/lib/kiev/request_id.rb +2 -1
- data/lib/kiev/request_logger.rb +3 -2
- data/lib/kiev/shoryuken/context_reader.rb +2 -0
- data/lib/kiev/shoryuken/middleware/message_tracer.rb +4 -7
- data/lib/kiev/test.rb +2 -1
- data/lib/kiev/util.rb +1 -0
- data/lib/kiev/version.rb +1 -1
- data/lib/kiev.rb +2 -0
- metadata +43 -34
- data/.travis.yml +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5da27510343d0217fedb4e4282cf9fc6468a63be4484935e2495e31205a2b188
|
4
|
+
data.tar.gz: 3a7ac16381946c418fa4265ab440da10397514766e5c091a87847f4451644251
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee5e47a70aae2576a0d119c0347fa9707f8a1ff53e8db3f5c1b8ae0bcc39907fd755f1d6112eca317e3b22ce8e2bdb59e83f3e9b70b86014fae995a4377da466
|
7
|
+
data.tar.gz: d976cb714c3e9ca5a2f3aa9c0a505a78d38d4a1c77faddc408555dec2ff3f337dbc9430d881630165933084e2a5c88051ef6fbe530a2c79ebf2f24b64949a329
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Main CI
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
strategy:
|
21
|
+
matrix:
|
22
|
+
ruby: ['2.5.1', '2.7.2', '2.6.5']
|
23
|
+
gemfile:
|
24
|
+
- gemfiles/ruby_kafka.gemfile
|
25
|
+
- gemfiles/que_0.12.2.gemfile
|
26
|
+
- gemfiles/que_0.12.3.gemfile
|
27
|
+
- gemfiles/rails_5.2.gemfile
|
28
|
+
- gemfiles/shoryuken_4.0.gemfile
|
29
|
+
- gemfiles/sidekiq_4.2.gemfile
|
30
|
+
- gemfiles/sinatra_1.4.gemfile
|
31
|
+
- gemfiles/sinatra_2.0.gemfile
|
32
|
+
allow_failures:
|
33
|
+
- false
|
34
|
+
include:
|
35
|
+
- os: ubuntu
|
36
|
+
ruby-version: ruby-head
|
37
|
+
gemfile: gemfiles/rails_5.2.gemfile
|
38
|
+
allow_failures: true
|
39
|
+
env:
|
40
|
+
BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
|
41
|
+
ALLOW_FAILURES: "${{ matrix.allow_failures }}"
|
42
|
+
REDIS_URL: "redis://localhost:6379/4"
|
43
|
+
DATABASE_URL: ${{ (startsWith(matrix.gemfile,'gemfiles/que') && 'postgres://postgres:postgres@localhost:5432/que_test') || 'sqlite3:db/combustion_test.sqlite'}}
|
44
|
+
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
|
45
|
+
|
46
|
+
# Service containers to run with `container-job`
|
47
|
+
services:
|
48
|
+
redis:
|
49
|
+
image: redis:latest
|
50
|
+
ports:
|
51
|
+
- 6379:6379
|
52
|
+
# Label used to access the service container
|
53
|
+
postgres:
|
54
|
+
# Docker Hub image
|
55
|
+
image: postgres:9.4
|
56
|
+
# Provide the password for postgres
|
57
|
+
env:
|
58
|
+
POSTGRES_PASSWORD: postgres
|
59
|
+
POSTGRES_DB: que_test
|
60
|
+
# Set health checks to wait until postgres has started
|
61
|
+
ports:
|
62
|
+
- 5432:5432
|
63
|
+
options: >-
|
64
|
+
--health-cmd pg_isready
|
65
|
+
--health-interval 10s
|
66
|
+
--health-timeout 5s
|
67
|
+
--health-retries 5
|
68
|
+
steps:
|
69
|
+
- uses: actions/checkout@v2
|
70
|
+
- name: Set up Ruby
|
71
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
72
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
73
|
+
# uses: ruby/setup-ruby@v1
|
74
|
+
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
75
|
+
with:
|
76
|
+
ruby-version: ${{ matrix.ruby }}
|
77
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
78
|
+
|
79
|
+
- name: Run tests
|
80
|
+
run: bundle exec rake || $ALLOW_FAILURES
|
data/.rubocop.yml
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
inherit_from:
|
2
2
|
- https://raw.githubusercontent.com/blacklane/rubocop/master/rubocop.yml
|
3
3
|
|
4
|
-
|
4
|
+
AllCops:
|
5
|
+
TargetRubyVersion: 2.5
|
6
|
+
Exclude:
|
7
|
+
- test/rails_app/**/*.rb # auto-generated
|
8
|
+
- spec/**/*.rb
|
9
|
+
- test/**/*.rb
|
10
|
+
- vendor/bundle/**/*
|
11
|
+
Lint/SuppressedException:
|
5
12
|
Exclude:
|
6
13
|
- test/**/*.rb
|
7
14
|
- spec/**/*.rb
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.5.1
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Kiev [](https://github.com/blacklane/kiev/actions?query=workflow%3A%22Main+CI%22) [](https://badge.fury.io/rb/kiev)
|
2
2
|
|
3
3
|
Kiev is a comprehensive logging library aimed at covering a wide range of frameworks and tools from the Ruby ecosystem:
|
4
4
|
|
@@ -154,6 +154,36 @@ Kiev::Shoryuken.enable
|
|
154
154
|
|
155
155
|
The name of the worker class is not logged by default. Configure [`persistent_log_fields` option](#persistent_log_fields) to include `"shoryuken_class"` if you want this.
|
156
156
|
|
157
|
+
### AWS SNS
|
158
|
+
|
159
|
+
To enhance messages published to SNS topics you can use the ContextInjector:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
sns_message = { topic_arn: "...", message: "{...}" }
|
163
|
+
Kiev::Kafka.inject_context(sns_message[:message_attributes])
|
164
|
+
|
165
|
+
```
|
166
|
+
|
167
|
+
After this operation the message attributes will also include required context for the Kiev logger.
|
168
|
+
|
169
|
+
### Kafka
|
170
|
+
|
171
|
+
To enhance messages published to Kafka topics you can use the ContextInjector:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
Kiev::Kafka.inject_context(headers)
|
175
|
+
```
|
176
|
+
|
177
|
+
After this operation the headers variable will also include required context for the Kiev logger.
|
178
|
+
|
179
|
+
If you have a consumed `Kafka::FetchedMessage` you can extract logger context with:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
Kiev::Kafka.extract_context(message)
|
183
|
+
```
|
184
|
+
|
185
|
+
This will work regardless if headers are in HTTP format, e.g. `X-Tracking-Id` or plain field names: `tracking_id`. Plus the `message_key` field will contain the key of processed message. In case you want to log some more fields configure `persistent_log_fields` and `jobs_propagated_fields`.
|
186
|
+
|
157
187
|
### Que
|
158
188
|
|
159
189
|
Add the following lines to your initializer code:
|
@@ -219,7 +249,9 @@ For web requests the Kiev middleware will log the following information by defau
|
|
219
249
|
|
220
250
|
* `params` attribute will store both query parameters and request body fields (as long as they are parseable). Sensitive fields will be filtered out - see the `#filtered_params` option.
|
221
251
|
|
222
|
-
* `request_id` is the correlation ID and will be the same across all requests within a chain of requests. It's represented as a UUID (version 4).
|
252
|
+
* `request_id` is the correlation ID and will be the same across all requests within a chain of requests. It's represented as a UUID (version 4). (currently deprecated in favor of a new name: `tracking_id`)
|
253
|
+
|
254
|
+
* `tracking_id` is the correlation ID and will be the same across all requests within a chain of requests. It's represented as a UUID (version 4). If not provided the value is seeded from deprecated `request_id`.
|
223
255
|
|
224
256
|
* `request_depth` represents the position of the current request within a chain of requests. It starts with 0.
|
225
257
|
|
data/gemfiles/que_0.12.2.gemfile
CHANGED
data/gemfiles/que_0.12.3.gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
# need it because of bug in https://github.com/chanks/que/issues/191
|
@@ -12,4 +14,4 @@ gem "rack-test", require: false
|
|
12
14
|
gem "rspec", require: false
|
13
15
|
gem "minitest-reporters", require: false
|
14
16
|
|
15
|
-
gemspec :
|
17
|
+
gemspec path: "../"
|
data/gemfiles/rails_4.1.gemfile
CHANGED
data/gemfiles/rails_4.2.gemfile
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "oj"
|
6
|
+
|
7
|
+
gem "rails", "~> 5.2.4"
|
8
|
+
gem "sqlite3", "1.3.13"
|
9
|
+
|
10
|
+
gem "combustion"
|
11
|
+
gem "rspec", require: false
|
12
|
+
gem "rspec-rails", require: false
|
13
|
+
gem "minitest-reporters", require: false
|
14
|
+
|
15
|
+
gemspec path: "../"
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
gem "aws-sdk", "~> 2.0"
|
4
|
-
gem "shoryuken", "~>
|
6
|
+
gem "shoryuken", "~> 4.0"
|
5
7
|
|
6
8
|
gem "rack-test", require: false
|
7
9
|
gem "minitest-reporters", require: false
|
8
10
|
|
9
|
-
gemspec :
|
11
|
+
gemspec path: "../"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
gem "oj"
|
@@ -6,10 +8,10 @@ gem "xml-simple"
|
|
6
8
|
|
7
9
|
gem "sinatra", "1.4.7"
|
8
10
|
gem "sinatra-contrib"
|
9
|
-
gem "rack-parser", :
|
11
|
+
gem "rack-parser", require: "rack/parser"
|
10
12
|
|
11
13
|
gem "rack-test", require: false
|
12
14
|
gem "rspec", require: false
|
13
15
|
gem "minitest-reporters", require: false
|
14
16
|
|
15
|
-
gemspec :
|
17
|
+
gemspec path: "../"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
gem "oj"
|
@@ -6,10 +8,10 @@ gem "xml-simple"
|
|
6
8
|
|
7
9
|
gem "sinatra", "2.0.0"
|
8
10
|
gem "sinatra-contrib"
|
9
|
-
gem "rack-parser", :
|
11
|
+
gem "rack-parser", require: "rack/parser"
|
10
12
|
|
11
13
|
gem "rack-test", require: false
|
12
14
|
gem "rspec", require: false
|
13
15
|
gem "minitest-reporters", require: false
|
14
16
|
|
15
|
-
gemspec :
|
17
|
+
gemspec path: "../"
|
data/kiev.gemspec
CHANGED
@@ -9,7 +9,9 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.licenses = ["MIT"]
|
10
10
|
|
11
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
|
12
|
+
spec.description = "Kiev is a logging tool aimed at distributed environments. It logs to JSON, while providing "\
|
13
|
+
"human-readable output in development mode. It integrates nicely with Rails, Sinatra and other"\
|
14
|
+
" Rack-based frameworks, Sidekiq, Que, HTTParty, Her and other Faraday-based HTTP clients."
|
13
15
|
spec.homepage = "https://github.com/blacklane/kiev"
|
14
16
|
|
15
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
@@ -17,12 +19,12 @@ Gem::Specification.new do |spec|
|
|
17
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
20
|
spec.require_paths = ["lib"]
|
19
21
|
|
20
|
-
spec.required_ruby_version = ">= 2.
|
22
|
+
spec.required_ruby_version = ">= 2.5"
|
23
|
+
spec.add_dependency "oga", "~> 2.2"
|
21
24
|
spec.add_dependency "rack", ">= 1", "< 3"
|
22
25
|
spec.add_dependency "request_store", ">= 1.0", "< 1.4"
|
23
|
-
spec.add_dependency "oga", "~> 2.2"
|
24
26
|
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.
|
27
|
+
spec.add_development_dependency "rake", "~> 0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.10"
|
29
|
+
spec.add_development_dependency "rubocop", "~> 0.54"
|
28
30
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "kiev/config"
|
4
|
+
require "kiev/subrequest_helper"
|
5
|
+
|
6
|
+
module Kiev
|
7
|
+
module AwsSns
|
8
|
+
class ContextInjector
|
9
|
+
# @param [Hash] message_attributes Injects context headers
|
10
|
+
# @return [Hash]
|
11
|
+
def call(message_attributes = {})
|
12
|
+
Kiev::SubrequestHelper.payload.each do |key, value|
|
13
|
+
message_attributes[key] = {
|
14
|
+
data_type: "String",
|
15
|
+
string_value: value.to_s
|
16
|
+
}
|
17
|
+
end
|
18
|
+
message_attributes
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/kiev/aws_sns.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Kiev
|
6
|
+
module AwsSns
|
7
|
+
require_relative "kafka/context_injector"
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# @param [Hash] headers
|
11
|
+
def inject_context(headers = {})
|
12
|
+
Kiev::AwsSns::ContextInjector.new.call(headers)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/kiev/base.rb
CHANGED
@@ -26,8 +26,20 @@ module Kiev
|
|
26
26
|
Config.instance.logger
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
29
|
+
def filtered_params
|
30
|
+
Config.instance.filtered_params
|
31
|
+
end
|
32
|
+
|
33
|
+
def ignored_params
|
34
|
+
Config.instance.ignored_params
|
35
|
+
end
|
36
|
+
|
37
|
+
def event(log_name, data = EMPTY_OBJ)
|
38
|
+
logger.log(
|
39
|
+
::Logger::Severity::INFO,
|
40
|
+
ParamFilter.filter(data, filtered_params, ignored_params),
|
41
|
+
log_name
|
42
|
+
)
|
31
43
|
end
|
32
44
|
|
33
45
|
def []=(name, value)
|
@@ -47,7 +59,9 @@ module Kiev
|
|
47
59
|
end
|
48
60
|
|
49
61
|
def request_id
|
50
|
-
RequestStore.store[:
|
62
|
+
RequestStore.store[:tracking_id]
|
51
63
|
end
|
64
|
+
|
65
|
+
alias_method :tracking_id, :request_id
|
52
66
|
end
|
53
67
|
end
|
data/lib/kiev/base52.rb
CHANGED
data/lib/kiev/config.rb
CHANGED
data/lib/kiev/context_reader.rb
CHANGED
@@ -6,6 +6,7 @@ module Kiev
|
|
6
6
|
# change field lookup.
|
7
7
|
class ContextReader
|
8
8
|
REQUEST_ID = "request_id"
|
9
|
+
TRACKING_ID = "tracking_id"
|
9
10
|
REQUEST_DEPTH = "request_depth"
|
10
11
|
TREE_PATH = "tree_path"
|
11
12
|
|
@@ -17,12 +18,14 @@ module Kiev
|
|
17
18
|
subject[key]
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
self[REQUEST_ID] || SecureRandom.uuid
|
21
|
+
def tracking_id
|
22
|
+
self[TRACKING_ID] || self[REQUEST_ID] || SecureRandom.uuid
|
22
23
|
end
|
23
24
|
|
25
|
+
alias_method :request_id, :tracking_id
|
26
|
+
|
24
27
|
def tree_root?
|
25
|
-
!self[REQUEST_ID]
|
28
|
+
!self[TRACKING_ID] && !self[REQUEST_ID]
|
26
29
|
end
|
27
30
|
|
28
31
|
def request_depth
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "message_context"
|
4
|
+
require "kiev/request_id"
|
5
|
+
require "kiev/context_reader"
|
6
|
+
|
7
|
+
module Kiev
|
8
|
+
module Kafka
|
9
|
+
class ContextExtractor
|
10
|
+
include Kiev::RequestId::Mixin
|
11
|
+
|
12
|
+
# @param [Kafka::FetchedMessage] message
|
13
|
+
def call(message)
|
14
|
+
context = Kiev::Kafka::MessageContext.new(message)
|
15
|
+
context_reader = Kiev::ContextReader.new(context)
|
16
|
+
wrap_request_id(context_reader) {}
|
17
|
+
|
18
|
+
Kiev[:message_key] = message.key
|
19
|
+
|
20
|
+
Config.instance.jobs_propagated_fields.each do |key|
|
21
|
+
Kiev[key] = context_reader[key]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "kiev/config"
|
4
|
+
require "kiev/subrequest_helper"
|
5
|
+
|
6
|
+
module Kiev
|
7
|
+
module Kafka
|
8
|
+
class ContextInjector
|
9
|
+
# @param [Hash] headers Injects context headers
|
10
|
+
# @return [Hash]
|
11
|
+
def call(headers = {})
|
12
|
+
Kiev::SubrequestHelper.payload.each do |key, value|
|
13
|
+
field_key = Kiev::Config::DEFAULT_HTTP_PROPAGATED_FIELDS.fetch(key.to_sym, key)
|
14
|
+
headers[field_key] = value
|
15
|
+
end
|
16
|
+
headers
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kiev
|
4
|
+
module Kafka
|
5
|
+
class MessageContext
|
6
|
+
# @param [Kafka::FetchedMessage] message
|
7
|
+
def initialize(message)
|
8
|
+
@headers = message.headers
|
9
|
+
end
|
10
|
+
|
11
|
+
def value(field)
|
12
|
+
headers[header_key(field)] || headers[field.to_s]
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :[], :value
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :headers
|
20
|
+
|
21
|
+
# @param [String] field
|
22
|
+
def header_key(field)
|
23
|
+
"x_#{field}".gsub("_", " ").split.map(&:capitalize).join("-")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/kiev/kafka.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Kiev
|
6
|
+
module Kafka
|
7
|
+
require_relative "kafka/context_extractor"
|
8
|
+
require_relative "kafka/context_injector"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# @param [Kafka::FetchedMessage] message
|
12
|
+
def extract_context(message)
|
13
|
+
Kiev::Kafka::ContextExtractor.new.call(message)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [Hash] headers
|
17
|
+
def inject_context(headers = {})
|
18
|
+
Kiev::Kafka::ContextInjector.new.call(headers)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/kiev/logger.rb
CHANGED
@@ -12,17 +12,20 @@ module Kiev
|
|
12
12
|
extend Forwardable
|
13
13
|
def_delegators(*([:@logger] + ::Logger.instance_methods(false)))
|
14
14
|
|
15
|
-
|
15
|
+
DEFAULT_LOG_NAME = "log"
|
16
|
+
DEFAULT_MESSAGE = "log"
|
16
17
|
LOG_ERROR = "ERROR"
|
17
18
|
ERROR_STATUS = 500
|
18
19
|
|
19
|
-
FORMATTER = proc do |severity, time,
|
20
|
+
FORMATTER = proc do |severity, time, log_name, data|
|
20
21
|
entry =
|
21
22
|
{
|
22
23
|
application: Config.instance.app,
|
23
|
-
|
24
|
+
log_name: log_name || DEFAULT_LOG_NAME,
|
24
25
|
level: severity,
|
25
26
|
timestamp: time.utc,
|
27
|
+
message: log_name || DEFAULT_MESSAGE,
|
28
|
+
tracking_id: RequestStore.store[:tracking_id],
|
26
29
|
request_id: RequestStore.store[:request_id],
|
27
30
|
request_depth: RequestStore.store[:request_depth],
|
28
31
|
tree_path: RequestStore.store[:tree_path]
|
@@ -38,12 +41,12 @@ module Kiev
|
|
38
41
|
entry[:jid] = RequestStore.store[:jid]
|
39
42
|
end
|
40
43
|
|
41
|
-
if !RequestStore.store[:subrequest_count] && %i(request_finished job_finished).include?(
|
44
|
+
if !RequestStore.store[:subrequest_count] && %i(request_finished job_finished).include?(log_name)
|
42
45
|
entry[:tree_leaf] = true
|
43
46
|
end
|
44
47
|
|
45
48
|
if RequestStore.store[:payload]
|
46
|
-
if %i(request_finished job_finished).include?(
|
49
|
+
if %i(request_finished job_finished).include?(log_name)
|
47
50
|
entry.merge!(RequestStore.store[:payload])
|
48
51
|
else
|
49
52
|
Config.instance.persistent_log_fields.each do |field|
|
@@ -67,17 +70,17 @@ module Kiev
|
|
67
70
|
JSON.logstash(entry)
|
68
71
|
end
|
69
72
|
|
70
|
-
DEVELOPMENT_FORMATTER = proc do |severity, time,
|
73
|
+
DEVELOPMENT_FORMATTER = proc do |severity, time, log_name, data|
|
71
74
|
entry = []
|
72
75
|
|
73
76
|
entry << time.iso8601
|
74
|
-
entry << (
|
77
|
+
entry << (log_name || severity).upcase
|
75
78
|
|
76
79
|
if data.is_a?(String)
|
77
80
|
entry << "#{data}\n"
|
78
81
|
end
|
79
82
|
|
80
|
-
if %i(request_finished job_finished).include?(
|
83
|
+
if %i(request_finished job_finished).include?(log_name)
|
81
84
|
verb = RequestStore.store[:request_verb]
|
82
85
|
path = RequestStore.store[:request_path]
|
83
86
|
entry << "#{verb} #{path}" if verb && path
|
@@ -92,10 +95,8 @@ module Kiev
|
|
92
95
|
entry << "(#{duration}ms)" if duration
|
93
96
|
entry << "\n"
|
94
97
|
|
95
|
-
meta =
|
96
|
-
|
97
|
-
request_depth: RequestStore.store[:request_depth]
|
98
|
-
}.merge!(Hash(RequestStore.store[:payload]))
|
98
|
+
meta = RequestStore.store.slice(:trakcing_id, :request_id, :request_depth)
|
99
|
+
.reverse_merge!(Hash(RequestStore.store[:payload]))
|
99
100
|
|
100
101
|
meta.reject! { |_, value| value.nil? }
|
101
102
|
|
data/lib/kiev/param_filter.rb
CHANGED
@@ -1,12 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Kiev
|
4
|
-
|
4
|
+
class ParamFilter
|
5
5
|
FILTERED = "[FILTERED]"
|
6
6
|
|
7
7
|
def self.filter(params, filtered_params, ignored_params)
|
8
|
+
new(filtered_params, ignored_params).call(params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(filtered_params, ignored_params)
|
12
|
+
@filtered_params = normalize(filtered_params)
|
13
|
+
@ignored_params = normalize(ignored_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(params)
|
17
|
+
return params unless filterable?(params)
|
18
|
+
|
8
19
|
params.each_with_object({}) do |(key, value), acc|
|
9
|
-
next if ignored_params.include?(key)
|
20
|
+
next if ignored_params.include?(key.to_s)
|
10
21
|
|
11
22
|
if defined?(ActionDispatch) && value.is_a?(ActionDispatch::Http::UploadedFile)
|
12
23
|
value = {
|
@@ -17,14 +28,26 @@ module Kiev
|
|
17
28
|
end
|
18
29
|
|
19
30
|
acc[key] =
|
20
|
-
if filtered_params.include?(key) && !value.is_a?(Hash)
|
31
|
+
if filtered_params.include?(key.to_s) && !value.is_a?(Hash)
|
21
32
|
FILTERED
|
22
33
|
elsif value.is_a?(Hash)
|
23
|
-
|
34
|
+
call(value)
|
24
35
|
else
|
25
36
|
value
|
26
37
|
end
|
27
38
|
end
|
28
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :filtered_params, :ignored_params
|
44
|
+
|
45
|
+
def filterable?(params)
|
46
|
+
params.respond_to?(:each_with_object)
|
47
|
+
end
|
48
|
+
|
49
|
+
def normalize(params)
|
50
|
+
Set.new(params.map(&:to_s))
|
51
|
+
end
|
29
52
|
end
|
30
53
|
end
|
data/lib/kiev/que/job.rb
CHANGED
@@ -47,7 +47,8 @@ module Kiev
|
|
47
47
|
Kiev[key] = payload[key]
|
48
48
|
end
|
49
49
|
request_store = Kiev::RequestStore.store
|
50
|
-
request_store[:
|
50
|
+
request_store[:tracking_id] = payload[:tracking_id]
|
51
|
+
request_store[:request_id] = payload[:tracking_id] || payload[:request_id]
|
51
52
|
request_store[:request_depth] = payload[:request_depth].to_i + 1
|
52
53
|
request_store[:tree_path] = payload[:tree_path]
|
53
54
|
|
data/lib/kiev/rack/request_id.rb
CHANGED
@@ -14,24 +14,26 @@ module Kiev
|
|
14
14
|
|
15
15
|
def call(env)
|
16
16
|
request_id_header_out = to_rack(:request_id)
|
17
|
-
|
17
|
+
tracking_id_header_out = to_rack(:tracking_id)
|
18
18
|
|
19
|
-
|
20
|
-
RequestStore.store[:
|
19
|
+
tracking_id = make_tracking_id(env[to_http(:tracking_id)] || env[RAILS_REQUEST_ID] || env[to_http(:request_id)])
|
20
|
+
RequestStore.store[:tracking_id] = tracking_id
|
21
|
+
RequestStore.store[:request_id] = tracking_id
|
21
22
|
RequestStore.store[:request_depth] = request_depth(env)
|
22
23
|
RequestStore.store[:tree_path] = tree_path(env)
|
23
24
|
|
24
|
-
@app.call(env).tap
|
25
|
+
@app.call(env).tap do |_status, headers, _body|
|
26
|
+
headers[tracking_id_header_out] = tracking_id
|
27
|
+
headers[request_id_header_out] = tracking_id
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
private
|
28
32
|
|
29
|
-
# TODO: in Rails 5 they set `headers[X_REQUEST_ID]`, so this will not work
|
30
|
-
# https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/request_id.rb
|
31
|
-
# https://github.com/interagent/pliny/blob/master/lib/pliny/middleware/request_id.rb
|
32
33
|
def tree_root?(env)
|
34
|
+
tracking_id_header_in = to_http(:tracking_id)
|
33
35
|
request_id_header_in = to_http(:request_id)
|
34
|
-
!env[request_id_header_in]
|
36
|
+
!env[tracking_id_header_in] && !env[request_id_header_in]
|
35
37
|
end
|
36
38
|
|
37
39
|
def request_depth(env)
|
@@ -52,15 +54,15 @@ module Kiev
|
|
52
54
|
Config.instance.all_http_propagated_fields[value]
|
53
55
|
end
|
54
56
|
|
55
|
-
def
|
56
|
-
if
|
57
|
-
|
57
|
+
def make_tracking_id(tracking_id)
|
58
|
+
if tracking_id.nil? || tracking_id.empty?
|
59
|
+
internal_tracking_id
|
58
60
|
else
|
59
|
-
Util.sanitize(
|
61
|
+
Util.sanitize(tracking_id)
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
|
-
def
|
65
|
+
def internal_tracking_id
|
64
66
|
SecureRandom.uuid
|
65
67
|
end
|
66
68
|
end
|
@@ -85,8 +85,6 @@ module Kiev
|
|
85
85
|
request.params
|
86
86
|
end
|
87
87
|
|
88
|
-
params = ParamFilter.filter(params, config.filtered_params, config.ignored_params)
|
89
|
-
|
90
88
|
data = {
|
91
89
|
host: request.host, # env["HTTP_HOST"] || env["HTTPS_HOST"],
|
92
90
|
params: params.empty? ? nil : params, # env[Rack::QUERY_STRING],
|
@@ -125,8 +123,8 @@ module Kiev
|
|
125
123
|
sio = StringIO.new(data[:body])
|
126
124
|
gz = Zlib::GzipReader.new(sio)
|
127
125
|
data[:body] = gz.read
|
128
|
-
rescue Zlib::GzipFile::Error =>
|
129
|
-
data[:gzip_parse_error] =
|
126
|
+
rescue Zlib::GzipFile::Error => e
|
127
|
+
data[:gzip_parse_error] = e.message
|
130
128
|
end
|
131
129
|
end
|
132
130
|
end
|
data/lib/kiev/request_id.rb
CHANGED
@@ -7,7 +7,8 @@ module Kiev
|
|
7
7
|
|
8
8
|
def wrap_request_id(context_reader, &_block)
|
9
9
|
request_store = Kiev::RequestStore.store
|
10
|
-
request_store[:
|
10
|
+
request_store[:tracking_id] = context_reader.tracking_id || context_reader.request_id
|
11
|
+
request_store[:request_id] = request_store[:tracking_id]
|
11
12
|
request_store[:request_depth] = context_reader.request_depth
|
12
13
|
request_store[:tree_path] = context_reader.tree_path
|
13
14
|
yield
|
data/lib/kiev/request_logger.rb
CHANGED
@@ -12,8 +12,8 @@ module Kiev
|
|
12
12
|
|
13
13
|
begin
|
14
14
|
return_value = yield
|
15
|
-
rescue StandardError =>
|
16
|
-
error =
|
15
|
+
rescue StandardError => e
|
16
|
+
error = e
|
17
17
|
end
|
18
18
|
|
19
19
|
begin
|
@@ -28,6 +28,7 @@ module Kiev
|
|
28
28
|
Kiev.event(event, data)
|
29
29
|
ensure
|
30
30
|
raise error if error
|
31
|
+
|
31
32
|
return_value
|
32
33
|
end
|
33
34
|
end
|
@@ -1,17 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "kiev/aws_sns/context_injector"
|
4
|
+
|
3
5
|
module Kiev
|
4
6
|
module Shoryuken
|
5
7
|
module Middleware
|
6
8
|
class MessageTracer
|
7
9
|
def call(options)
|
8
|
-
|
9
|
-
|
10
|
-
attrbutes[key] = {
|
11
|
-
data_type: "String",
|
12
|
-
string_value: value.to_s
|
13
|
-
}
|
14
|
-
end
|
10
|
+
options[:message_attributes] ||= {}
|
11
|
+
Kiev::AwsSns::ContextInjector.new.call(options[:message_attributes])
|
15
12
|
yield
|
16
13
|
end
|
17
14
|
end
|
data/lib/kiev/test.rb
CHANGED
data/lib/kiev/util.rb
CHANGED
data/lib/kiev/version.rb
CHANGED
data/lib/kiev.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "kiev/base"
|
4
|
+
require_relative "kiev/aws_sns" if defined?(AWS::SNS)
|
5
|
+
require_relative "kiev/kafka" if defined?(Kafka)
|
4
6
|
require_relative "kiev/rack" if defined?(Rack)
|
5
7
|
require_relative "kiev/railtie" if defined?(Rails)
|
6
8
|
require_relative "kiev/sidekiq" if defined?(Sidekiq)
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kiev
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blacklane
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: oga
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.2'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rack
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,20 +64,6 @@ dependencies:
|
|
50
64
|
- - "<"
|
51
65
|
- !ruby/object:Gem::Version
|
52
66
|
version: '1.4'
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: oga
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - "~>"
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: '2.2'
|
60
|
-
type: :runtime
|
61
|
-
prerelease: false
|
62
|
-
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
requirements:
|
64
|
-
- - "~>"
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '2.2'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: ruby_dig
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,58 +82,58 @@ dependencies:
|
|
82
82
|
name: rake
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
84
84
|
requirements:
|
85
|
-
- - "
|
85
|
+
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
|
-
- - "
|
92
|
+
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
94
|
version: '0'
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
96
|
name: rspec
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
98
98
|
requirements:
|
99
|
-
- - "
|
99
|
+
- - "~>"
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '
|
101
|
+
version: '3.10'
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
|
-
- - "
|
106
|
+
- - "~>"
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version: '
|
108
|
+
version: '3.10'
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: rubocop
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
|
-
- -
|
113
|
+
- - "~>"
|
114
114
|
- !ruby/object:Gem::Version
|
115
|
-
version: 0.
|
115
|
+
version: '0.54'
|
116
116
|
type: :development
|
117
117
|
prerelease: false
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
119
119
|
requirements:
|
120
|
-
- -
|
120
|
+
- - "~>"
|
121
121
|
- !ruby/object:Gem::Version
|
122
|
-
version: 0.
|
122
|
+
version: '0.54'
|
123
123
|
description: Kiev is a logging tool aimed at distributed environments. It logs to
|
124
124
|
JSON, while providing human-readable output in development mode. It integrates nicely
|
125
125
|
with Rails, Sinatra and other Rack-based frameworks, Sidekiq, Que, HTTParty, Her
|
126
126
|
and other Faraday-based HTTP clients.
|
127
|
-
email:
|
127
|
+
email:
|
128
128
|
executables: []
|
129
129
|
extensions: []
|
130
130
|
extra_rdoc_files: []
|
131
131
|
files:
|
132
|
+
- ".github/workflows/push.yml"
|
132
133
|
- ".gitignore"
|
133
134
|
- ".rspec"
|
134
135
|
- ".rubocop.yml"
|
135
136
|
- ".ruby-version"
|
136
|
-
- ".travis.yml"
|
137
137
|
- Gemfile
|
138
138
|
- LICENSE.md
|
139
139
|
- README.md
|
@@ -144,13 +144,17 @@ files:
|
|
144
144
|
- gemfiles/que_0.12.3.gemfile
|
145
145
|
- gemfiles/rails_4.1.gemfile
|
146
146
|
- gemfiles/rails_4.2.gemfile
|
147
|
-
- gemfiles/
|
147
|
+
- gemfiles/rails_5.2.gemfile
|
148
|
+
- gemfiles/ruby_kafka.gemfile
|
149
|
+
- gemfiles/shoryuken_4.0.gemfile
|
148
150
|
- gemfiles/sidekiq_4.2.gemfile
|
149
151
|
- gemfiles/sinatra_1.4.gemfile
|
150
152
|
- gemfiles/sinatra_2.0.gemfile
|
151
153
|
- kiev.gemspec
|
152
154
|
- lib/ext/rack/common_logger.rb
|
153
155
|
- lib/kiev.rb
|
156
|
+
- lib/kiev/aws_sns.rb
|
157
|
+
- lib/kiev/aws_sns/context_injector.rb
|
154
158
|
- lib/kiev/base.rb
|
155
159
|
- lib/kiev/base52.rb
|
156
160
|
- lib/kiev/config.rb
|
@@ -159,6 +163,10 @@ files:
|
|
159
163
|
- lib/kiev/her_ext/client_request_id.rb
|
160
164
|
- lib/kiev/httparty.rb
|
161
165
|
- lib/kiev/json.rb
|
166
|
+
- lib/kiev/kafka.rb
|
167
|
+
- lib/kiev/kafka/context_extractor.rb
|
168
|
+
- lib/kiev/kafka/context_injector.rb
|
169
|
+
- lib/kiev/kafka/message_context.rb
|
162
170
|
- lib/kiev/logger.rb
|
163
171
|
- lib/kiev/param_filter.rb
|
164
172
|
- lib/kiev/que/job.rb
|
@@ -199,7 +207,7 @@ homepage: https://github.com/blacklane/kiev
|
|
199
207
|
licenses:
|
200
208
|
- MIT
|
201
209
|
metadata: {}
|
202
|
-
post_install_message:
|
210
|
+
post_install_message:
|
203
211
|
rdoc_options: []
|
204
212
|
require_paths:
|
205
213
|
- lib
|
@@ -207,15 +215,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
207
215
|
requirements:
|
208
216
|
- - ">="
|
209
217
|
- !ruby/object:Gem::Version
|
210
|
-
version: 2.
|
218
|
+
version: '2.5'
|
211
219
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
212
220
|
requirements:
|
213
221
|
- - ">="
|
214
222
|
- !ruby/object:Gem::Version
|
215
223
|
version: '0'
|
216
224
|
requirements: []
|
217
|
-
|
218
|
-
|
225
|
+
rubyforge_project:
|
226
|
+
rubygems_version: 2.7.6
|
227
|
+
signing_key:
|
219
228
|
specification_version: 4
|
220
229
|
summary: Distributed logging to JSON integrated with various Ruby frameworks and tools
|
221
230
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
branches:
|
3
|
-
only:
|
4
|
-
- master
|
5
|
-
cache:
|
6
|
-
- bundler
|
7
|
-
language: ruby
|
8
|
-
rvm:
|
9
|
-
- 2.3.3
|
10
|
-
- 2.2.3
|
11
|
-
addons:
|
12
|
-
postgresql: "9.4"
|
13
|
-
services:
|
14
|
-
- postgresql
|
15
|
-
- redis-server
|
16
|
-
before_script:
|
17
|
-
- psql -c 'create database que_test;' -U postgres
|
18
|
-
gemfile:
|
19
|
-
- gemfiles/que_0.12.2.gemfile
|
20
|
-
- gemfiles/que_0.12.3.gemfile
|
21
|
-
- gemfiles/rails_4.1.gemfile
|
22
|
-
- gemfiles/rails_4.2.gemfile
|
23
|
-
- gemfiles/shoryuken_3.1.gemfile
|
24
|
-
- gemfiles/sidekiq_4.2.gemfile
|
25
|
-
- gemfiles/sinatra_1.4.gemfile
|
26
|
-
- gemfiles/sinatra_2.0.gemfile
|
27
|
-
matrix:
|
28
|
-
fast_finish: true
|