loga 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +1 -0
  3. data/.codeclimate.yml +3 -1
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +29 -2
  6. data/Appraisals +4 -0
  7. data/CHANGELOG.md +4 -0
  8. data/Guardfile +14 -0
  9. data/README.md +4 -0
  10. data/gemfiles/sidekiq51.gemfile +11 -0
  11. data/lib/loga.rb +4 -3
  12. data/lib/loga/ext/core/tempfile.rb +1 -1
  13. data/lib/loga/formatters/simple_formatter.rb +1 -3
  14. data/lib/loga/rack/request.rb +2 -2
  15. data/lib/loga/sidekiq.rb +16 -0
  16. data/lib/loga/sidekiq/job_logger.rb +62 -0
  17. data/lib/loga/utilities.rb +1 -1
  18. data/lib/loga/version.rb +1 -1
  19. data/loga.gemspec +4 -2
  20. data/spec/fixtures/rails32.rb +1 -0
  21. data/spec/integration/rails/railtie_spec.rb +9 -8
  22. data/spec/integration/rails/request_spec.rb +2 -2
  23. data/spec/integration/sidekiq_spec.rb +131 -0
  24. data/spec/integration/sinatra_spec.rb +17 -16
  25. data/spec/loga/sidekiq/job_logger_spec.rb +115 -0
  26. data/spec/loga/sidekiq_spec.rb +53 -0
  27. data/spec/spec_helper.rb +21 -0
  28. data/spec/support/helpers.rb +8 -1
  29. data/spec/support/request_spec.rb +4 -4
  30. data/spec/support/timecop_shared.rb +1 -0
  31. data/spec/unit/loga/configuration_spec.rb +7 -4
  32. data/spec/unit/loga/event_spec.rb +2 -2
  33. data/spec/unit/loga/formatters/gelf_formatter_spec.rb +7 -5
  34. data/spec/unit/loga/formatters/simple_formatter_spec.rb +3 -0
  35. data/spec/unit/loga/log_subscribers/action_mailer_spec.rb +14 -13
  36. data/spec/unit/loga/parameter_filter_spec.rb +1 -1
  37. data/spec/unit/loga/rack/logger_spec.rb +10 -6
  38. data/spec/unit/loga/rack/request_spec.rb +4 -3
  39. data/spec/unit/loga/utilities_spec.rb +3 -3
  40. data/spec/unit/loga_spec.rb +6 -3
  41. metadata +44 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7c3c0cd9e1fab4d284e3adc88c1d27ee6c61f97832eb29510bbc4f44c59b302
4
- data.tar.gz: 7215fed59ad0cb9e9e66ae6b8d60ed5c8da4929a4d7e91372bdae98b266a0783
3
+ metadata.gz: 99d4525427d3cfa44d95be9d47f82188246743e71aab9f8d40489214e02e4c02
4
+ data.tar.gz: 33fc287f4ecabf93cdc6d789f81a040c64eb411d7a018459fa39c91ae03c46c8
5
5
  SHA512:
6
- metadata.gz: b447cbd98d83ed537851a626688de411fffa053a97fb7d24bc0988dd5f21c6a9cee63f4ac88948cba9bafe820a94b1478da3fcb9617041bfb6c70ce652a402b1
7
- data.tar.gz: 517841207ffc10a6f3badab0893cf13f7ad45c1e4c21dcc0b92752b7ee0de0f270f9bfe0be75739f0a034edc74b5bcafe9f8a73ba53220ee1527f70dcbbd7f49
6
+ metadata.gz: 6ce2b115d84a4b3c1c93bf8070b0f3d7ed148df4eb1169ab57d8de2357ad03ea23c21fab2f30f6c0b24236919cbaee21565eee7fed007949a7fa6601118ef510
7
+ data.tar.gz: df05bfcd3ba233ef8a64e743fcb40c9948caeb1a82039340ae6cb24a839b2cab08044da8009f91196bf444b0b960cbcc29bd2fe9b08f8f3ac003f2757ad5d320
@@ -95,6 +95,7 @@ jobs:
95
95
  - deploy:
96
96
  name: Publish to rubygems
97
97
  command: |
98
+ mkdir ~/.gem
98
99
  echo ":rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials
99
100
  chmod 0600 ~/.gem/credentials
100
101
  gem push $CIRCLE_PROJECT_REPONAME-$(echo $CIRCLE_TAG | sed -e 's/v//').gem
@@ -1,4 +1,6 @@
1
1
  engines:
2
2
  rubocop:
3
3
  enabled: true
4
- channel: rubocop-0-50
4
+ channel: rubocop-0-57
5
+ config:
6
+ file: rubocop.yml
data/.gitignore CHANGED
@@ -25,3 +25,5 @@ spec/fixtures/**/*.log
25
25
  gemfiles/*.lock
26
26
  vendor/bundle
27
27
  .byebug_history
28
+ .DS_Store
29
+
@@ -1,8 +1,12 @@
1
1
  AllCops:
2
2
  Exclude:
3
3
  - '*.gemspec'
4
+ - 'gemfiles/*'
4
5
  - 'spec/fixtures/**/*'
5
6
  - 'vendor/bundle/**/*'
7
+ - 'gemfiles/vendor/bundle/**/*'
8
+
9
+ require: rubocop-rspec
6
10
 
7
11
  Documentation:
8
12
  Enabled: false
@@ -28,6 +32,25 @@ Metrics/MethodLength:
28
32
  Enabled: true
29
33
  Max: 15
30
34
 
35
+ RSpec/DescribeClass:
36
+ Enabled: false
37
+
38
+ RSpec/ExampleLength:
39
+ Enabled: false
40
+
41
+ RSpec/FilePath:
42
+ Exclude:
43
+ - spec/integration/rails/action_mailer_spec.rb
44
+ - spec/integration/rails/railtie_spec.rb
45
+
46
+ RSpec/MultipleExpectations:
47
+ Enabled: false
48
+
49
+ RSpec/NamedSubject:
50
+ Enabled: false
51
+
52
+ RSpec/NestedGroups:
53
+ Enabled: false
31
54
  Style/BlockDelimiters:
32
55
  Enabled: false
33
56
 
@@ -37,10 +60,14 @@ Style/FormatString:
37
60
  Style/PerlBackrefs:
38
61
  Enabled: false
39
62
 
40
- Style/TrailingCommaInLiteral:
63
+ Style/TrailingCommaInArguments:
64
+ Enabled: true
65
+ EnforcedStyleForMultiline: comma
66
+
67
+ Style/TrailingCommaInArrayLiteral:
41
68
  Enabled: true
42
69
  EnforcedStyleForMultiline: comma
43
70
 
44
- Style/TrailingCommaInArguments:
71
+ Style/TrailingCommaInHashLiteral:
45
72
  Enabled: true
46
73
  EnforcedStyleForMultiline: comma
data/Appraisals CHANGED
@@ -24,5 +24,9 @@ appraise 'rails52' do
24
24
  gem 'rails', '~> 5.2.0'
25
25
  end
26
26
 
27
+ appraise 'sidekiq51' do
28
+ gem 'sidekiq', '~> 5.1.0'
29
+ end
30
+
27
31
  appraise 'unit' do
28
32
  end
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [2.3.0] - 2018-06-29
8
+ ### Added
9
+ Support for Sidekiq `~> 5.0`.
10
+
7
11
  ## [2.2.0] - 2018-05-10
8
12
  ### Added
9
13
  Subscribe to `ActionMailer` events
data/Guardfile CHANGED
@@ -39,6 +39,20 @@ group :rails do
39
39
  end
40
40
  end
41
41
 
42
+ group :sidekiq do
43
+ cmd = 'bundle exec appraisal sidekiq51 rspec'
44
+
45
+ guard :rspec, all_on_start: true, cmd: cmd do
46
+ watch('lib/loga/sidekiq/job_logger.rb') do
47
+ [
48
+ 'spec/integration/sidekiq_spec.rb',
49
+ 'spec/loga/sidekiq/job_logger_spec.rb',
50
+ 'spec/loga/sidekiq_spec.rb',
51
+ ]
52
+ end
53
+ end
54
+ end
55
+
42
56
  group :unit do
43
57
  guard :rspec, cmd: 'bundle exec appraisal unit rspec' do
44
58
  watch(%r{^spec/unit/.+_spec\.rb$})
data/README.md CHANGED
@@ -148,6 +148,10 @@ environment variable therefore it must be removed.
148
148
  LOGA_FORMAT=simple rackup
149
149
  ```
150
150
 
151
+ ### Sidekiq
152
+
153
+ Loga `2.3` provides an out-of-the-box support for `Sidekiq ~> 5.0`.
154
+
151
155
  ## Output Example
152
156
 
153
157
  ### GELF Format
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sidekiq", "~> 5.1.0"
6
+
7
+ group :test do
8
+ gem "simplecov"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -8,6 +8,7 @@ require 'loga/rack/logger'
8
8
  require 'loga/rack/request'
9
9
  require 'loga/rack/request_id'
10
10
  require 'loga/railtie' if defined?(Rails)
11
+ require 'loga/sidekiq'
11
12
 
12
13
  module Loga
13
14
  ConfigurationError = Class.new(StandardError)
@@ -22,11 +23,11 @@ module Loga
22
23
  end
23
24
 
24
25
  def self.configure(options, framework_options = {})
25
- if @configuration
26
- raise ConfigurationError, 'Loga has already been configured'
27
- end
26
+ raise ConfigurationError, 'Loga has already been configured' if @configuration
28
27
 
29
28
  @configuration ||= Configuration.new(options, framework_options)
29
+
30
+ Loga::Sidekiq.configure_logging
30
31
  end
31
32
 
32
33
  def self.logger
@@ -1,7 +1,7 @@
1
1
  # Fixes encoding error when converting uploaded file to JSON
2
2
  # https://github.com/rails/rails/issues/25250
3
3
  class Tempfile
4
- def as_json(_ = nil)
4
+ def as_json(_any = nil)
5
5
  to_s
6
6
  end
7
7
  end
@@ -30,9 +30,7 @@ module Loga
30
30
  components = [event.message]
31
31
 
32
32
  %i[type data exception].each do |attr|
33
- if event.public_send(attr)
34
- components.push "#{attr}=#{event.public_send(attr)}"
35
- end
33
+ components.push "#{attr}=#{event.public_send(attr)}" if event.public_send(attr)
36
34
  end
37
35
 
38
36
  components.join(' ')
@@ -50,7 +50,7 @@ module Loga
50
50
  end
51
51
 
52
52
  def filtered_form_hash
53
- @filter_form_hash ||= filter_hash(form_hash)
53
+ @filtered_form_hash ||= filter_hash(form_hash)
54
54
  end
55
55
 
56
56
  private
@@ -78,7 +78,7 @@ module Loga
78
78
  end
79
79
 
80
80
  def parameter_filter
81
- @filter_parameters ||=
81
+ @parameter_filter ||=
82
82
  ParameterFilter.new(loga_filter_parameters | action_dispatch_filter_params)
83
83
  end
84
84
 
@@ -0,0 +1,16 @@
1
+ require 'loga/sidekiq/job_logger'
2
+
3
+ module Loga
4
+ module Sidekiq
5
+ def self.configure_logging
6
+ return unless defined?(::Sidekiq)
7
+ return if Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('5.0')
8
+
9
+ ::Sidekiq.configure_server do |config|
10
+ config.options[:job_logger] = Loga::Sidekiq::JobLogger
11
+ end
12
+
13
+ ::Sidekiq::Logging.logger = Loga.configuration.logger
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ module Loga
2
+ module Sidekiq
3
+ # The approach of using a custom job logger in sidekiq was introduced
4
+ # in v5.0: https://github.com/mperham/sidekiq/pull/3235
5
+ # This job logger does not support logging for Sidekiq versions
6
+ # that are before 5.0
7
+ class JobLogger
8
+ include Loga::Utilities
9
+
10
+ EVENT_TYPE = 'sidekiq'.freeze
11
+
12
+ attr_reader :started_at, :data
13
+
14
+ def initialize
15
+ @started_at = Time.now
16
+ @data = {}
17
+ end
18
+
19
+ def call(item, _queue)
20
+ yield
21
+ rescue Exception => ex # rubocop:disable Lint/RescueException
22
+ data['exception'] = ex
23
+
24
+ raise
25
+ ensure
26
+ assign_data(item)
27
+ send_message
28
+ end
29
+
30
+ private
31
+
32
+ def assign_data(item)
33
+ data['created_at'] = item['created_at']
34
+ data['enqueued_at'] = item['enqueued_at']
35
+ data['jid'] = item['jid']
36
+ data['queue'] = item['queue']
37
+ data['retry'] = item['retry']
38
+ data['params'] = item['args']
39
+ data['class'] = item['class']
40
+ data['duration'] = duration_in_ms(started_at)
41
+ end
42
+
43
+ def short_message
44
+ "#{data['class']} with jid: '#{data['jid']}' executed in #{data['duration']}ms"
45
+ end
46
+
47
+ def send_message
48
+ event = Event.new(data: data, message: short_message, type: EVENT_TYPE)
49
+
50
+ logger.public_send(compute_level, event)
51
+ end
52
+
53
+ def compute_level
54
+ data.key?('exception') ? :warn : :info
55
+ end
56
+
57
+ def logger
58
+ Loga.logger
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,6 +1,6 @@
1
1
  module Loga
2
2
  module Utilities
3
- def duration_in_ms(started_at, ended_at)
3
+ def duration_in_ms(started_at, ended_at = Time.now)
4
4
  ((ended_at - started_at) * 1000).round
5
5
  end
6
6
  end
@@ -1,3 +1,3 @@
1
1
  module Loga
2
- VERSION = '2.2.0'.freeze
2
+ VERSION = '2.3.0'.freeze
3
3
  end
@@ -30,7 +30,9 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency 'pry'
31
31
  spec.add_development_dependency 'rack-test'
32
32
  spec.add_development_dependency 'rake'
33
- spec.add_development_dependency 'rspec', '~> 3.6.0'
34
- spec.add_development_dependency 'rubocop', '~> 0.50.0'
33
+ spec.add_development_dependency 'fakeredis'
34
+ spec.add_development_dependency 'rspec', '~> 3.7.0'
35
+ spec.add_development_dependency 'rubocop', '~> 0.57.0'
36
+ spec.add_development_dependency 'rubocop-rspec'
35
37
  spec.add_development_dependency 'timecop'
36
38
  end
@@ -18,6 +18,7 @@ class Dummy < Rails::Application
18
18
  service_version: '1.0',
19
19
  }
20
20
  config.action_mailer.delivery_method = :test
21
+ config.active_support.deprecation = :notify
21
22
  end
22
23
 
23
24
  class ApplicationController < ActionController::Base
@@ -6,12 +6,13 @@ RSpec.describe Loga::Railtie do
6
6
 
7
7
  describe 'Tempfile' do
8
8
  let(:tempfile) { Tempfile.new('README.md') }
9
+
9
10
  it 'monkey patches #as_json' do
10
11
  expect(tempfile.as_json).to eql(tempfile.to_s)
11
12
  end
12
13
  end
13
14
 
14
- context 'development', if: Rails.env.development? do
15
+ context 'when development', if: Rails.env.development? do
15
16
  describe 'loga_initialize_logger' do
16
17
  let(:formatter) { Loga::Formatters::SimpleFormatter }
17
18
 
@@ -25,7 +26,7 @@ RSpec.describe Loga::Railtie do
25
26
  end
26
27
  end
27
28
 
28
- context 'production', if: Rails.env.production? do
29
+ context 'when production', if: Rails.env.production? do
29
30
  describe 'loga_initialize_logger' do
30
31
  it 'assign Loga logger to Rails logger' do
31
32
  expect(Loga.logger).to equal(Rails.logger)
@@ -57,7 +58,7 @@ RSpec.describe Loga::Railtie do
57
58
  listeners.map { |l| l.instance_variable_get(:@delegate).class }
58
59
  end
59
60
 
60
- context 'ActionView' do
61
+ describe 'ActionView' do
61
62
  [
62
63
  'render_collection.action_view',
63
64
  'render_partial.action_view',
@@ -66,12 +67,12 @@ RSpec.describe Loga::Railtie do
66
67
  let(:notification) { notification }
67
68
 
68
69
  it 'removes ActionView::LogSubscriber' do
69
- expect(subscribers).to_not include(ActionView::LogSubscriber)
70
+ expect(subscribers).not_to include(ActionView::LogSubscriber)
70
71
  end
71
72
  end
72
73
  end
73
74
 
74
- context 'ActionController' do
75
+ describe 'ActionController' do
75
76
  [
76
77
  'exist_fragment?.action_controller',
77
78
  'expire_fragment.action_controller',
@@ -91,12 +92,12 @@ RSpec.describe Loga::Railtie do
91
92
  let(:notification) { notification }
92
93
 
93
94
  it 'removes ActionController::LogSubscriber' do
94
- expect(subscribers).to_not include(ActionController::LogSubscriber)
95
+ expect(subscribers).not_to include(ActionController::LogSubscriber)
95
96
  end
96
97
  end
97
98
  end
98
99
 
99
- context 'ActionMailer' do
100
+ describe 'ActionMailer' do
100
101
  [
101
102
  'receive.action_mailer',
102
103
  'deliver.action_mailer',
@@ -105,7 +106,7 @@ RSpec.describe Loga::Railtie do
105
106
  let(:notification) { notification }
106
107
 
107
108
  it 'removes ActionMailer::LogSubscriber' do
108
- expect(subscribers).to_not include(ActionMailer::LogSubscriber)
109
+ expect(subscribers).not_to include(ActionMailer::LogSubscriber)
109
110
  end
110
111
  end
111
112
  end
@@ -31,7 +31,7 @@ RSpec.describe 'Structured logging with Rails', timecop: true,
31
31
  end
32
32
 
33
33
  describe 'LogSubscriber' do
34
- context 'ActionController' do
34
+ describe 'ActionController' do
35
35
  let(:action_controller_notifications) do
36
36
  log_entries.select { |e| e.to_json =~ /Processing by|Completed/ }
37
37
  end
@@ -42,7 +42,7 @@ RSpec.describe 'Structured logging with Rails', timecop: true,
42
42
  end
43
43
  end
44
44
 
45
- context 'ActionView' do
45
+ describe 'ActionView' do
46
46
  let(:action_view_notifications) do
47
47
  log_entries.select { |e| e.to_json =~ /Rendered/ }
48
48
  end
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+ require 'timecop'
3
+ require 'fakeredis'
4
+
5
+ dummy_redis_config = ConnectionPool.new(size: 5) { Redis.new }
6
+
7
+ Sidekiq.configure_client do |config|
8
+ config.redis = dummy_redis_config
9
+ end
10
+
11
+ Sidekiq.configure_server do |config|
12
+ config.redis = dummy_redis_config
13
+ end
14
+
15
+ class MySidekiqWorker
16
+ include Sidekiq::Worker
17
+
18
+ def perform(_name); end
19
+ end
20
+
21
+ describe 'Sidekiq client logger' do
22
+ let(:target) { StringIO.new }
23
+
24
+ let(:json_line) do
25
+ target.rewind
26
+ JSON.parse(target.read)
27
+ end
28
+
29
+ before do
30
+ Redis.current.flushall
31
+
32
+ Loga.reset
33
+
34
+ Loga.configure(
35
+ service_name: 'hello_world_app',
36
+ service_version: '1.0',
37
+ device: target,
38
+ format: :gelf,
39
+ )
40
+ end
41
+
42
+ it 'has the proper job logger' do
43
+ job_logger = Loga::Sidekiq::JobLogger
44
+
45
+ expect(Sidekiq.options[:job_logger]).to eq job_logger
46
+ end
47
+
48
+ it 'has the proper logger Sidekiq::Logging.logger' do
49
+ expect(Sidekiq::Logging.logger).to eq Loga.logger
50
+ end
51
+
52
+ it 'has the proper logger for Sidekiq.logger' do
53
+ expect(Sidekiq.logger).to eq Loga.logger
54
+ end
55
+
56
+ it 'pushes a new element in the default queue' do
57
+ MySidekiqWorker.perform_async('Bob')
58
+
59
+ last_element = JSON.parse(Redis.current.lpop('queue:default'))
60
+
61
+ aggregate_failures do
62
+ expect(last_element['class']).to eq 'MySidekiqWorker'
63
+ expect(last_element['args']).to eq ['Bob']
64
+ expect(last_element['retry']).to eq true
65
+ expect(last_element['queue']).to eq 'default'
66
+ end
67
+ end
68
+
69
+ if ENV['BUNDLE_GEMFILE'] =~ /sidekiq51/
70
+ # https://github.com/mperham/sidekiq/blob/97363210b47a4f8a1d8c1233aaa059d6643f5040/test/test_actors.rb#L57-L79
71
+ let(:mgr) do
72
+ Class.new do
73
+ attr_reader :latest_error, :mutex, :cond
74
+
75
+ def initialize
76
+ @mutex = ::Mutex.new
77
+ @cond = ::ConditionVariable.new
78
+ end
79
+
80
+ def processor_died(_inst, err)
81
+ @latest_error = err
82
+
83
+ @mutex.synchronize { @cond.signal }
84
+ end
85
+
86
+ def processor_stopped(_inst)
87
+ @mutex.synchronize { @cond.signal }
88
+ end
89
+
90
+ def options
91
+ {
92
+ concurrency: 3,
93
+ queues: ['default'],
94
+ job_logger: Loga::Sidekiq::JobLogger,
95
+ }
96
+ end
97
+ end
98
+ end
99
+
100
+ it 'logs the job processing event' do
101
+ MySidekiqWorker.perform_async('Bob')
102
+
103
+ require 'sidekiq/processor'
104
+ Sidekiq::Processor.new(mgr.new).start
105
+ sleep 0.5
106
+
107
+ expected_attributes = {
108
+ '_queue'=> 'default',
109
+ '_retry'=> true,
110
+ '_params'=> ['Bob'],
111
+ '_class'=> 'MySidekiqWorker',
112
+ '_type'=> 'sidekiq',
113
+ '_service.name'=> 'hello_world_app',
114
+ '_service.version'=> '1.0',
115
+ '_tags'=> '',
116
+ 'level'=> 6,
117
+ 'version'=> '1.1',
118
+ }
119
+
120
+ aggregate_failures do
121
+ expect(json_line).to include(expected_attributes)
122
+
123
+ %w[_created_at _enqueued_at _jid _duration timestamp host].each do |key|
124
+ expect(json_line).to have_key(key)
125
+ end
126
+
127
+ expect(json_line['short_message']).to match(/MySidekiqWorker with jid:*/)
128
+ end
129
+ end
130
+ end
131
+ end