loga 2.2.0 → 2.3.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.
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