sidekiq-logstash 0.2.6

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