sidekiq-logstash 0.2.6

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6fe579d57bfb9c6b9852fb75ddb7717c76347491
4
+ data.tar.gz: c92117609504b57e5802d0b0657ac7117bb39e85
5
+ SHA512:
6
+ metadata.gz: 89832527fb8baa0f0bcda0d9e95b4ef888617a307abe696c1baa7c789d3df4eb54fe59fcdeefbd68972d20102c82c26289ba84965ed2063a4276e2f0e8524859
7
+ data.tar.gz: 718580d0fa6d681a3600733be5a6678b3eca8903196a6c84d09570b4a5b68ba01a7ca0d8acf6bb7cbbda3638ebd345107ae1a9878be7cf7878b062ccfb85b165
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea
11
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sidekiq-logstash.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Sidekiq::Logstash
2
+
3
+ [<img src="https://img.shields.io/badge/version-0.2.6-green.svg" alt="version" />](https://github.com/iMacTia/sidekiq-logstash) [<img src="https://travis-ci.org/iMacTia/sidekiq-logstash.svg?branch=master" alt="version" />](https://travis-ci.org/iMacTia/sidekiq-logstash)
4
+
5
+ Sidekiq::Logstash turns your [Sidekiq](https://github.com/mperham/sidekiq) log into an organised, aggregated, JSON-syntax log ready to be sent to a logstash server.
6
+
7
+ ```json
8
+ {
9
+ "class" : "MyWorker",
10
+ "args" : ["first_param","second_param"],
11
+ "retry" : true,
12
+ "queue" : "default",
13
+ "status" : "fail",
14
+ "jid" : "fd71783c0afa3f5e0958f3e9",
15
+ "created_at" : "2016-07-02T14:03:26.423Z",
16
+ "enqueued_at" : "2016-07-02T14:03:26.425Z",
17
+ "retried_at" : "2016-07-02T16:28:42.195Z",
18
+ "failed_at" : "2016-07-02T13:04:58.298Z",
19
+ "retried_at" : "2016-07-02T14:04:11.051Z",
20
+ "retry_count" : 1,
21
+ "pid" : 70354,
22
+ "duration" : 0.306,
23
+ "error_message" : "An error message that occurred during job execution.",
24
+ "error_backtrace" : "...",
25
+ "@timestamp" : "2016-07-02T14:03:27.259Z",
26
+ "@version" : "1"
27
+ }
28
+ ```
29
+
30
+ ## Installation
31
+
32
+ Add this line to your application's Gemfile:
33
+
34
+ ```ruby
35
+ gem 'sidekiq-logstash'
36
+ ```
37
+
38
+ And then execute:
39
+
40
+ ```bash
41
+ $ bundle
42
+ ```
43
+
44
+ Or install it yourself as:
45
+
46
+ ```bash
47
+ $ gem install sidekiq-logstash
48
+ ```
49
+
50
+ ## Usage
51
+
52
+ Simply add the following to your sidekiq configuration (in Rails, this will be `initializers/sidekiq.rb`)
53
+
54
+ ```ruby
55
+ Sidekiq::Logstash.setup
56
+ ```
57
+
58
+ I suggest you add it on top of it, before any other `Sidekiq.configure_server` initialization, in order to avoid unformatted logging.
59
+
60
+ ## Configuration
61
+
62
+ Sidekiq::Logstash allows you to provide custom configuration
63
+
64
+ ```ruby
65
+ Sidekiq::Logstash.configure do |config|
66
+ # filter_args will allow you to filter the job arguments removing
67
+ # it works just like rails params filtering (http://guides.rubyonrails.org/action_controller_overview.html#parameters-filtering)
68
+ config.filter_args << 'foo'
69
+
70
+ # custom_option is a Proc that will be called before logging the payload, allowing you to add fields to it
71
+ config.custom_options = lambda do |payload|
72
+ payload['my_custom_field'] = 'my_custom_value'
73
+ end
74
+ end
75
+ ```
76
+
77
+ ## Development
78
+
79
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
80
+
81
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
82
+
83
+ ## Contributing
84
+
85
+ Bug reports and pull requests are welcome on GitHub at https://github.com/iMacTia/sidekiq-logstash.
86
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'sidekiq/logstash'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/test_console ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'sidekiq/logstash'
5
+ require_relative '../spec/spec_helper'
6
+ FactoryGirl.find_definitions
7
+
8
+ require 'irb'
9
+ IRB.start
@@ -0,0 +1,77 @@
1
+ # This implementation is taken directly from https://github.com/rails/rails/blob/52ce6ece8c8f74064bb64e0a0b1ddd83092718e1/actionpack/lib/action_dispatch/http/parameter_filter.rb
2
+ # Adding actionpack to the gem dependencies would have been too heavy, so here is just what we need.
3
+
4
+ module Sidekiq
5
+ module Logging
6
+ class ArgumentFilter
7
+ FILTERED = '[FILTERED]'.freeze
8
+
9
+ def initialize(filters = [])
10
+ @filters = filters
11
+ end
12
+
13
+ def filter(args)
14
+ compiled_filter.call(args)
15
+ end
16
+
17
+ private
18
+
19
+ def compiled_filter
20
+ @compiled_filter ||= CompiledFilter.compile(@filters)
21
+ end
22
+
23
+ class CompiledFilter # :nodoc:
24
+ def self.compile(filters)
25
+ return lambda { |args| args.dup } if filters.empty?
26
+ strings, regexps, blocks = [], [], []
27
+ filters.each do |item|
28
+ case item
29
+ when Proc
30
+ blocks << item
31
+ when Regexp
32
+ regexps << item
33
+ else
34
+ strings << Regexp.escape(item.to_s)
35
+ end
36
+ end
37
+ deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
38
+ deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
39
+ regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty?
40
+ deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty?
41
+ new regexps, deep_regexps, blocks
42
+ end
43
+
44
+ attr_reader :regexps, :deep_regexps, :blocks
45
+
46
+ def initialize(regexps, deep_regexps, blocks)
47
+ @regexps = regexps
48
+ @deep_regexps = deep_regexps.any? ? deep_regexps : nil
49
+ @blocks = blocks
50
+ end
51
+
52
+ def call(original_args, parents = [])
53
+ filtered_args = {}
54
+ original_args.each do |key, value|
55
+ parents.push(key) if deep_regexps
56
+ if regexps.any? { |r| key =~ r }
57
+ value = FILTERED
58
+ elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r }
59
+ value = FILTERED
60
+ elsif value.is_a?(Hash)
61
+ value = call(value, parents)
62
+ elsif value.is_a?(Array)
63
+ value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
64
+ elsif blocks.any?
65
+ key = key.dup rescue key
66
+ value = value.dup rescue value
67
+ blocks.each { |b| b.call(key, value) }
68
+ end
69
+ parents.pop if deep_regexps
70
+ filtered_args[key] = value
71
+ end
72
+ filtered_args
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,28 @@
1
+ require 'logstash-event'
2
+
3
+ module Sidekiq
4
+ module Logging
5
+ class LogstashFormatter
6
+ def call(severity, time, progname, data)
7
+ if data.is_a? Hash
8
+ json_data = data
9
+ else
10
+ json_data = {
11
+ severity: severity,
12
+ message: data
13
+ }
14
+ end
15
+
16
+ # Merge custom_options to provide customization
17
+ custom_options.call(json_data) if custom_options rescue nil
18
+ event = LogStash::Event.new(json_data)
19
+
20
+ "#{event.to_json}\n"
21
+ end
22
+
23
+ def custom_options
24
+ Sidekiq::Logstash.configuration.custom_options
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module Sidekiq
2
+ module Logstash
3
+ class Configuration
4
+ attr_accessor :custom_options, :filter_args
5
+
6
+ def initialize
7
+ @filter_args = []
8
+ end
9
+
10
+ # Added to ensure custom_options is a Proc
11
+ def custom_options=(proc)
12
+ raise ArgumentError, 'Argument must be a Proc.' unless proc.is_a?(Proc)
13
+ @custom_options = proc
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module Sidekiq
2
+ module Logstash
3
+ VERSION = '0.2.6'
4
+ end
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'sidekiq/logstash/configuration'
2
+ require 'sidekiq/logstash/version'
3
+ require 'sidekiq/middleware/server/logstah_logging'
4
+ require 'sidekiq/logging/logstash_formatter'
5
+ require 'sidekiq/logging/argument_filter'
6
+
7
+ module Sidekiq
8
+ module Logstash
9
+ def self.configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+
13
+ def self.configure
14
+ yield(configuration)
15
+ end
16
+
17
+ def self.setup(opts = {})
18
+ # Calls Sidekiq.configure_server to inject logics
19
+ Sidekiq.configure_server do |config|
20
+ # Remove default Sidekiq error_handler that logs errors
21
+ config.error_handlers.delete_if {|h| h.is_a?(Sidekiq::ExceptionHandler::Logger) }
22
+
23
+ # Add logstash support
24
+ config.server_middleware do |chain|
25
+ chain.add Sidekiq::Middleware::Server::LogstashLogging
26
+ chain.remove Sidekiq::Middleware::Server::Logging
27
+ end
28
+
29
+ # Set custom formatter for Sidekiq logger
30
+ config.logger.formatter = Sidekiq::Logging::LogstashFormatter.new
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,80 @@
1
+ module Sidekiq
2
+ module Middleware
3
+ module Server
4
+ class LogstashLogging
5
+ def call(_, job, _)
6
+ started_at = Time.now.utc
7
+ yield
8
+ Sidekiq.logger.info log_job(job, started_at)
9
+ rescue => exc
10
+ begin
11
+ Sidekiq.logger.warn log_job(job, started_at, exc)
12
+ rescue => ex
13
+ Sidekiq.logger.error 'Error logging the job execution!'
14
+ Sidekiq.logger.error "Job: #{job}"
15
+ Sidekiq.logger.error "Job Exception: #{exc}"
16
+ Sidekiq.logger.error "Log Exception: #{ex}"
17
+ end
18
+ raise
19
+ end
20
+
21
+ def log_job(payload, started_at, exc = nil)
22
+ # Create a copy of the payload using JSON
23
+ # This should always be possible since Sidekiq store it in Redis
24
+ payload = JSON.parse(JSON.unparse(payload))
25
+
26
+ # Convert timestamps into Time instances
27
+ %w( created_at enqueued_at retried_at failed_at completed_at ).each do |key|
28
+ payload[key] = parse_time(payload[key]) if payload[key]
29
+ end
30
+
31
+ # Add process id params
32
+ payload['pid'] = ::Process.pid
33
+ payload['duration'] = elapsed(started_at)
34
+
35
+ message = "#{payload['class']} JID-#{payload['jid']}"
36
+
37
+ if exc
38
+ payload['message'] = "#{message}: fail: #{payload['duration']} sec"
39
+ payload['job_status'] = 'fail'
40
+ payload['error_message'] = exc.message
41
+ payload['error'] = exc.class
42
+ payload['error_backtrace'] = %('#{exc.backtrace.join("\n")}')
43
+ else
44
+ payload['message'] = "#{message}: done: #{payload['duration']} sec"
45
+ payload['job_status'] = 'done'
46
+ payload['completed_at'] = Time.now.utc
47
+ end
48
+
49
+ # Filter sensitive parameters
50
+ unless filter_args.empty?
51
+ args_filter = Sidekiq::Logging::ArgumentFilter.new(filter_args)
52
+ payload['args'] = args_filter.filter({ args: payload['args'] })[:args]
53
+ end
54
+
55
+ # Needs to map all args to strings for ElasticSearch compatibility
56
+ payload['args'].map!(&:to_s)
57
+
58
+ payload
59
+ end
60
+
61
+ def elapsed(start)
62
+ (Time.now.utc - start).round(3)
63
+ end
64
+
65
+ def parse_time(timestamp)
66
+ return timestamp if timestamp.is_a? Time
67
+ timestamp.is_a?(Float) ?
68
+ Time.at(timestamp).utc :
69
+ Time.parse(timestamp)
70
+ rescue
71
+ timestamp
72
+ end
73
+
74
+ def filter_args
75
+ Sidekiq::Logstash.configuration.filter_args
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sidekiq/logstash/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'sidekiq-logstash'
8
+ spec.version = Sidekiq::Logstash::VERSION
9
+ spec.authors = ['Mattia Giuffrida']
10
+ spec.email = ['giuffrida.mattia@gmail.com']
11
+
12
+ spec.summary = %q{Logstash plugin for Sidekiq}
13
+ spec.description = <<-DESC
14
+ Sidekiq::Logstash turns your Sidekiq log into an organised, aggregated, JSON-syntax log ready to be sent to a logstash server.
15
+ DESC
16
+ spec.homepage = 'https://github.com/iMacTia/sidekiq-logstash'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'logstash-event', '~> 1.2'
24
+ spec.add_runtime_dependency 'sidekiq', '~> 4.0'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.11'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.0'
29
+ spec.add_development_dependency 'factory_girl', '~> 4.0'
30
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-logstash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.6
5
+ platform: ruby
6
+ authors:
7
+ - Mattia Giuffrida
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.2'
19
+ name: logstash-event
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '4.0'
33
+ name: sidekiq
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.11'
47
+ name: bundler
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.11'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '10.0'
61
+ name: rake
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ name: rspec
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '4.0'
89
+ name: factory_girl
90
+ prerelease: false
91
+ type: :development
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '4.0'
97
+ description: 'Sidekiq::Logstash turns your Sidekiq log into an organised, aggregated,
98
+ JSON-syntax log ready to be sent to a logstash server.
99
+
100
+ '
101
+ email:
102
+ - giuffrida.mattia@gmail.com
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - ".gitignore"
108
+ - ".rspec"
109
+ - ".travis.yml"
110
+ - Gemfile
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - bin/test_console
116
+ - lib/sidekiq/logging/argument_filter.rb
117
+ - lib/sidekiq/logging/logstash_formatter.rb
118
+ - lib/sidekiq/logstash.rb
119
+ - lib/sidekiq/logstash/configuration.rb
120
+ - lib/sidekiq/logstash/version.rb
121
+ - lib/sidekiq/middleware/server/logstah_logging.rb
122
+ - sidekiq-logstash.gemspec
123
+ homepage: https://github.com/iMacTia/sidekiq-logstash
124
+ licenses: []
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.6.10
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Logstash plugin for Sidekiq
146
+ test_files: []