logstasher 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/logstasher/log_subscriber.rb +5 -4
- data/lib/logstasher/version.rb +1 -1
- metadata +6 -26
- data/.gitignore +0 -5
- data/.rspec +0 -2
- data/.travis.yml +0 -12
- data/Gemfile +0 -15
- data/Guardfile +0 -10
- data/README.md +0 -162
- data/Rakefile +0 -50
- data/logstasher.gemspec +0 -27
- data/sample_logstash_configurations/quickstart.conf +0 -23
- data/spec/lib/logstasher/device/redis_spec.rb +0 -79
- data/spec/lib/logstasher/instrumentation_spec.rb +0 -62
- data/spec/lib/logstasher/log_subscriber_spec.rb +0 -265
- data/spec/lib/logstasher_spec.rb +0 -263
- data/spec/spec_helper.rb +0 -52
- data/spec/support/sample_mailer.rb +0 -16
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YjJhNTIyM2IxMDc5NDU0ZmZjZTNlMzhlZTg1MTRkNzE4NDNkMDQ2OQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OWI5OTI4ZDUzYThmMTM3NGJjNjUzY2VhYTc3ZTcwNWExMzFhNzdhZg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2FlMTgzZGMxMjk3MDFmOTE2NzM4YTc4ZjJmNTgwMGFmZmVhMTYyYzk5ZjM3
|
10
|
+
YzM1NDVlYjUxYWM5ZGE4OTJkOWU0ZTgxZjEzMWJlNGZhZTYxMzk0NDcxNTJl
|
11
|
+
MDcwMjgzMDQ0NTVmODVhYTEwZDE2ODFiNWJkYTg5NTgwYTMzYmM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
N2E4ZGM1NzU4MTIwZjZlM2RiNzY1NDhiMzE0ZjY1Yjg1YTQxMjA4YTcxNzMx
|
14
|
+
NmEwNTQwZWY0ODYxYzBmNzEwNzZlMDNlZTVkZjExYjlhZjRmYTY1YzcyNzVk
|
15
|
+
YzFhOTQwY2FhNjlkNmVkYzAyYmU0ZGE5ZDYxODI2OTJhYmQwNmM=
|
@@ -109,7 +109,12 @@ module LogStasher
|
|
109
109
|
process_event(event, ['mailer', 'process'])
|
110
110
|
end
|
111
111
|
|
112
|
+
def logger
|
113
|
+
LogStasher.logger
|
114
|
+
end
|
115
|
+
|
112
116
|
private
|
117
|
+
|
113
118
|
def process_event(event, tags)
|
114
119
|
data = LogStasher.request_context.merge(extract_metadata(event.payload))
|
115
120
|
event = LogStash::Event.new('@source' => LogStasher.source, '@fields' => data, '@tags' => tags)
|
@@ -119,9 +124,5 @@ module LogStasher
|
|
119
124
|
def extract_metadata(payload)
|
120
125
|
payload.slice(*MAILER_FIELDS)
|
121
126
|
end
|
122
|
-
|
123
|
-
def logger
|
124
|
-
LogStasher.logger
|
125
|
-
end
|
126
127
|
end
|
127
128
|
end
|
data/lib/logstasher/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstasher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shadab Ahmed
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-event
|
@@ -87,13 +87,6 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
-
- .gitignore
|
91
|
-
- .rspec
|
92
|
-
- .travis.yml
|
93
|
-
- Gemfile
|
94
|
-
- Guardfile
|
95
|
-
- README.md
|
96
|
-
- Rakefile
|
97
90
|
- lib/logstasher.rb
|
98
91
|
- lib/logstasher/device/redis.rb
|
99
92
|
- lib/logstasher/log_subscriber.rb
|
@@ -101,16 +94,9 @@ files:
|
|
101
94
|
- lib/logstasher/rails_ext/rack/logger.rb
|
102
95
|
- lib/logstasher/railtie.rb
|
103
96
|
- lib/logstasher/version.rb
|
104
|
-
- logstasher.gemspec
|
105
|
-
- sample_logstash_configurations/quickstart.conf
|
106
|
-
- spec/lib/logstasher/device/redis_spec.rb
|
107
|
-
- spec/lib/logstasher/instrumentation_spec.rb
|
108
|
-
- spec/lib/logstasher/log_subscriber_spec.rb
|
109
|
-
- spec/lib/logstasher_spec.rb
|
110
|
-
- spec/spec_helper.rb
|
111
|
-
- spec/support/sample_mailer.rb
|
112
97
|
homepage: https://github.com/shadabahmed/logstasher
|
113
|
-
licenses:
|
98
|
+
licenses:
|
99
|
+
- MIT
|
114
100
|
metadata: {}
|
115
101
|
post_install_message:
|
116
102
|
rdoc_options: []
|
@@ -127,15 +113,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
113
|
- !ruby/object:Gem::Version
|
128
114
|
version: '0'
|
129
115
|
requirements: []
|
130
|
-
rubyforge_project:
|
116
|
+
rubyforge_project:
|
131
117
|
rubygems_version: 2.2.2
|
132
118
|
signing_key:
|
133
119
|
specification_version: 4
|
134
120
|
summary: Awesome rails logs
|
135
|
-
test_files:
|
136
|
-
- spec/lib/logstasher/device/redis_spec.rb
|
137
|
-
- spec/lib/logstasher/instrumentation_spec.rb
|
138
|
-
- spec/lib/logstasher/log_subscriber_spec.rb
|
139
|
-
- spec/lib/logstasher_spec.rb
|
140
|
-
- spec/spec_helper.rb
|
141
|
-
- spec/support/sample_mailer.rb
|
121
|
+
test_files: []
|
data/.rspec
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in logstasher.gemspec
|
4
|
-
gemspec
|
5
|
-
|
6
|
-
group :test do
|
7
|
-
gem 'growl'
|
8
|
-
gem 'guard'
|
9
|
-
gem 'guard-rspec'
|
10
|
-
gem 'rails', "~> #{ENV["RAILS_VERSION"] || "3.2.0"}"
|
11
|
-
gem 'rb-fsevent', '~> 0.9'
|
12
|
-
gem 'rcov', :platforms => :mri_18
|
13
|
-
gem 'redis', :require => false
|
14
|
-
gem 'simplecov', :platforms => :mri_19, :require => false
|
15
|
-
end
|
data/Guardfile
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
# A sample Guardfile
|
2
|
-
# More info at https://github.com/guard/guard#readme
|
3
|
-
interactor :simple
|
4
|
-
|
5
|
-
guard 'rspec', :version => 2 do
|
6
|
-
watch(%r{^spec/.+_spec\.rb$})
|
7
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
8
|
-
watch('spec/spec_helper.rb') { "spec" }
|
9
|
-
end
|
10
|
-
|
data/README.md
DELETED
@@ -1,162 +0,0 @@
|
|
1
|
-
# Logstasher [![Gem Version](https://badge.fury.io/rb/logstasher.png)](http://badge.fury.io/rb/logstasher) [![Build Status](https://secure.travis-ci.org/shadabahmed/logstasher.png)](https://secure.travis-ci.org/shadabahmed/logstasher)
|
2
|
-
### Awesome Logging for Rails !!
|
3
|
-
|
4
|
-
This gem is heavily inspired from [lograge](https://github.com/roidrage/lograge), but it's focused on one thing and one thing only. That's making your logs awesome like this:
|
5
|
-
|
6
|
-
[![Awesome Logs](https://f.cloud.github.com/assets/830679/2407078/dcde03e8-aa82-11e3-85ac-8c5b3a86676e.png)](https://f.cloud.github.com/assets/830679/2407078/dcde03e8-aa82-11e3-85ac-8c5b3a86676e.png)
|
7
|
-
|
8
|
-
How it's done ?
|
9
|
-
|
10
|
-
By, using these awesome tools:
|
11
|
-
* [Logstash](http://logstash.net) - Store and index your logs
|
12
|
-
* [Kibana](http://kibana.org/) - for awesome visualization. This is optional though, and you can use any other visualizer
|
13
|
-
|
14
|
-
Update: Logstash now includes Kibana build in, so no need to separately install. Logstasher has been test with **logstash version 1.3.3**
|
15
|
-
|
16
|
-
See [quickstart](#quick-setup-for-logstash) for quickly setting up logstash
|
17
|
-
|
18
|
-
## About logstasher
|
19
|
-
|
20
|
-
This gem purely focuses on how to generate logstash compatible logs i.e. *logstash json event format*, without any overhead. Infact, logstasher logs to a separate log file named `logstash_<environment>.log`.
|
21
|
-
The reason for this separation:
|
22
|
-
* To have a pure json log file
|
23
|
-
* Prevent any logger messages(e.g. info) getting into our pure json logs
|
24
|
-
|
25
|
-
Before **logstasher** :
|
26
|
-
|
27
|
-
```
|
28
|
-
Started GET "/login" for 10.109.10.135 at 2013-04-30 08:59:01 -0400
|
29
|
-
Processing by SessionsController#new as HTML
|
30
|
-
Rendered sessions/new.html.haml within layouts/application (4.3ms)
|
31
|
-
Rendered shared/_javascript.html.haml (0.6ms)
|
32
|
-
Rendered shared/_flashes.html.haml (0.2ms)
|
33
|
-
Rendered shared/_header.html.haml (52.9ms)
|
34
|
-
Rendered shared/_title.html.haml (0.2ms)
|
35
|
-
Rendered shared/_footer.html.haml (0.2ms)
|
36
|
-
Completed 200 OK in 532ms (Views: 62.4ms | ActiveRecord: 0.0ms | ND API: 0.0ms)
|
37
|
-
```
|
38
|
-
|
39
|
-
After **logstasher**:
|
40
|
-
|
41
|
-
```
|
42
|
-
{"@source":"unknown","@tags":["request"],"@fields":{"method":"GET","path":"/","format":"html","controller":"file_servers"
|
43
|
-
,"action":"index","status":200,"duration":28.34,"view":25.96,"db":0.88,"ip":"127.0.0.1","route":"file_servers#index",
|
44
|
-
"parameters":"","ndapi_time":null,"uuid":"e81ecd178ed3b591099f4d489760dfb6","user":"shadab_ahmed@abc.com",
|
45
|
-
"site":"internal"},"@timestamp":"2013-04-30T13:00:46.354500+00:00"}
|
46
|
-
```
|
47
|
-
|
48
|
-
By default, the older format rails request logs are disabled, though you can enable them.
|
49
|
-
|
50
|
-
## Installation
|
51
|
-
|
52
|
-
In your Gemfile:
|
53
|
-
|
54
|
-
gem 'logstasher'
|
55
|
-
|
56
|
-
### Configure your `<environment>.rb` e.g. `development.rb`
|
57
|
-
|
58
|
-
# Enable the logstasher logs for the current environment
|
59
|
-
config.logstasher.enabled = true
|
60
|
-
|
61
|
-
# This line is optional if you do not want to suppress app logs in your <environment>.log
|
62
|
-
config.logstasher.suppress_app_log = false
|
63
|
-
|
64
|
-
# This line is optional, it allows you to set a custom value for the @source field of the log event
|
65
|
-
config.logstasher.source = 'your.arbitrary.source'
|
66
|
-
|
67
|
-
## Logging params hash
|
68
|
-
|
69
|
-
Logstasher can be configured to log the contents of the params hash. When enabled, the contents of the params hash (minus the ActionController internal params)
|
70
|
-
will be added to the log as a deep hash. This can cause conflicts within the Elasticsearch mappings though, so should be enabled with care. Conflicts will occur
|
71
|
-
if different actions (or even different applications logging to the same Elasticsearch cluster) use the same params key, but with a different data type (e.g. a
|
72
|
-
string vs. a hash). This can lead to lost log entries. Enabling this can also significantly increase the size of the Elasticsearch indexes.
|
73
|
-
|
74
|
-
To enable this, add the following to your `<environment>.rb`
|
75
|
-
|
76
|
-
# Enable logging of controller params
|
77
|
-
config.logstasher.log_controller_parameters = true
|
78
|
-
|
79
|
-
## Adding custom fields to the log
|
80
|
-
|
81
|
-
Since some fields are very specific to your application for e.g. *user_name*, so it is left upto you, to add them. Here's how to add those fields to the logs:
|
82
|
-
|
83
|
-
# Create a file - config/initializers/logstasher.rb
|
84
|
-
|
85
|
-
if LogStasher.enabled
|
86
|
-
LogStasher.add_custom_fields do |fields|
|
87
|
-
# This block is run in application_controller context,
|
88
|
-
# so you have access to all controller methods
|
89
|
-
fields[:user] = current_user && current_user.mail
|
90
|
-
fields[:site] = request.path =~ /^\/api/ ? 'api' : 'user'
|
91
|
-
|
92
|
-
# If you are using custom instrumentation, just add it to logstasher custom fields
|
93
|
-
LogStasher.custom_fields << :myapi_runtime
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
## Logging ActionMailer events
|
98
|
-
|
99
|
-
Logstasher can easily log messages from `ActionMailer`, such as incoming/outgoing e-mails and e-mail content generation (Rails >= 4.1).
|
100
|
-
This functionality is automatically enabled. Since the relationship between a concrete HTTP request and a mailer invocation is lost
|
101
|
-
once in an `ActionMailer` instance method, global (per-request) state is kept to correlate HTTP requests and events from other parts
|
102
|
-
of rails, such as `ActionMailer`. Every time a request is invoked, a `request_id` key is added which is present on every `ActionMailer` event.
|
103
|
-
|
104
|
-
Note: Since mailers are executed within the lifetime of a request, they will show up in logs prior to the actual request.
|
105
|
-
|
106
|
-
## Listening to `ActiveSupport::Notifications` events
|
107
|
-
|
108
|
-
It is possible to listen to any `ActiveSupport::Notifications` events and store arbitrary data to be included in the final JSON log entry:
|
109
|
-
|
110
|
-
# In config/initializers/logstasher.rb
|
111
|
-
|
112
|
-
# Watch calls the block with the same arguments than any ActiveSupport::Notification, plus a store
|
113
|
-
LogStasher.watch('some.activesupport.notification') do |name, start, finish, id, payload, store|
|
114
|
-
# Do something
|
115
|
-
store[:count] = 42
|
116
|
-
end
|
117
|
-
|
118
|
-
Would change the log entry to:
|
119
|
-
|
120
|
-
```
|
121
|
-
{"@source":"unknown","@tags":["request"],"@fields":{"method":"GET","path":"/","format":"html","controller":"file_servers","action":"index","status":200,"duration":28.34,"view":25.96,"db":0.88,"ip":"127.0.0.1","route":"file_servers#index", "parameters":"","ndapi_time":null,"uuid":"e81ecd178ed3b591099f4d489760dfb6","user":"shadab_ahmed@abc.com", "site":"internal","some.activesupport.notification":{"count":42}},"@timestamp":"2013-04-30T13:00:46.354500+00:00"}
|
122
|
-
```
|
123
|
-
|
124
|
-
The store exposed to the blocked passed to `watch` is thread-safe, and reset after each request.
|
125
|
-
By default, the store is only shared between occurences of the same event.
|
126
|
-
You can easily share the same store between different types of notifications, by assigning them to the same event group:
|
127
|
-
|
128
|
-
# In config/initializers/logstasher.rb
|
129
|
-
|
130
|
-
LogStasher.watch('foo.notification', event_group: 'notification') do |*args, store|
|
131
|
-
# Shared store with 'bar.notification'
|
132
|
-
end
|
133
|
-
|
134
|
-
LogStasher.watch('bar.notification', event_group: 'notification') do |*args, store|
|
135
|
-
# Shared store with 'foo.notification'
|
136
|
-
end
|
137
|
-
|
138
|
-
## Quick Setup for Logstash
|
139
|
-
|
140
|
-
* Download logstash from [logstash.net](http://www.logstash.net/)
|
141
|
-
* Use this sample config file: [quickstart.conf](https://github.com/shadabahmed/logstasher/raw/master/sample_logstash_configurations/quickstart.conf)
|
142
|
-
* Start logstash with the following command:
|
143
|
-
```
|
144
|
-
java -jar logstash-1.3.3-flatjar.jar agent -f quickstart.conf -- web
|
145
|
-
```
|
146
|
-
* Visit http://localhost:9292/ to see the Kibana interface and your parsed logs
|
147
|
-
* For advanced options see the latest logstash documentation at [logstash.net](http://www.logstash.net/) or visit my blog at [shadabahmed.com](http://shadabahmed.com/blog/2013/04/30/logstasher-for-awesome-rails-logging) (slightly outdated but will sure give you ideas for distributed setup etc.)
|
148
|
-
|
149
|
-
## Versions
|
150
|
-
All versions require Rails 3.0.x and higher and Ruby 1.9.2+. Tested on Rails 4 and Ruby 2.0
|
151
|
-
|
152
|
-
## Development
|
153
|
-
- Run tests - `rake`
|
154
|
-
- Generate test coverage report - `rake coverage`. Coverage report path - coverage/index.html
|
155
|
-
|
156
|
-
## Copyright
|
157
|
-
|
158
|
-
Copyright (c) 2013 Shadab Ahmed, released under the MIT license
|
159
|
-
|
160
|
-
|
161
|
-
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/shadabahmed/logstasher/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
162
|
-
|
data/Rakefile
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
require 'rspec/core/rake_task'
|
3
|
-
|
4
|
-
# Add default task. When you type just rake command this would run. Travis CI runs this. Making this run spec
|
5
|
-
desc 'Default: run specs.'
|
6
|
-
task :default => :spec
|
7
|
-
|
8
|
-
# Defining spec task for running spec
|
9
|
-
desc "Run specs"
|
10
|
-
RSpec::Core::RakeTask.new('spec') do |spec|
|
11
|
-
# Pattern filr for spec files to run. This is default btw.
|
12
|
-
spec.pattern = "./spec/**/*_spec.rb"
|
13
|
-
end
|
14
|
-
|
15
|
-
# Run the rdoc task to generate rdocs for this gem
|
16
|
-
require 'rdoc/task'
|
17
|
-
RDoc::Task.new do |rdoc|
|
18
|
-
require "logstasher/version"
|
19
|
-
version = LogStasher::VERSION
|
20
|
-
|
21
|
-
rdoc.rdoc_dir = 'rdoc'
|
22
|
-
rdoc.title = "logstasher #{version}"
|
23
|
-
rdoc.rdoc_files.include('README*')
|
24
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
-
end
|
26
|
-
|
27
|
-
# Code coverage tasks. Different for Ruby 1.8 vs 1.9
|
28
|
-
if RUBY_VERSION =~ /^1\.8/
|
29
|
-
# Ruby 1.8 uses rcov for code coverage
|
30
|
-
RSpec::Core::RakeTask.new(:coverage) do |spec|
|
31
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
32
|
-
spec.rcov = true
|
33
|
-
spec.rcov_opts = %w{--exclude pkg\/,spec\/,features\/}
|
34
|
-
end
|
35
|
-
else
|
36
|
-
# Ruby 1.9+ using simplecov. Note: Simplecov config defined in spec_helper
|
37
|
-
desc "Code coverage detail"
|
38
|
-
task :coverage do
|
39
|
-
ENV['COVERAGE'] = "true"
|
40
|
-
Rake::Task['spec'].execute
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
task :console do
|
45
|
-
require 'irb'
|
46
|
-
require 'irb/completion'
|
47
|
-
require 'logstasher'
|
48
|
-
ARGV.clear
|
49
|
-
IRB.start
|
50
|
-
end
|
data/logstasher.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "logstasher/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "logstasher"
|
7
|
-
s.version = LogStasher::VERSION
|
8
|
-
s.authors = ["Shadab Ahmed"]
|
9
|
-
s.email = ["shadab.ansari@gmail.com"]
|
10
|
-
s.homepage = "https://github.com/shadabahmed/logstasher"
|
11
|
-
s.summary = %q{Awesome rails logs}
|
12
|
-
s.description = %q{Awesome rails logs}
|
13
|
-
|
14
|
-
s.rubyforge_project = "logstasher"
|
15
|
-
|
16
|
-
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
s.require_paths = ["lib"]
|
20
|
-
s.add_runtime_dependency "logstash-event", ["~> 1.1.0"]
|
21
|
-
s.add_runtime_dependency "request_store"
|
22
|
-
|
23
|
-
# specify any dependencies here; for example:
|
24
|
-
s.add_development_dependency "rspec", [">= 2.14"]
|
25
|
-
s.add_development_dependency("bundler", [">= 1.0.0"])
|
26
|
-
s.add_development_dependency("rails", [">= 3.0"])
|
27
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
input {
|
2
|
-
file {
|
3
|
-
type => "rails logs"
|
4
|
-
path => "/Users/shadab/test_project/logstash_development.log"
|
5
|
-
codec => json {
|
6
|
-
charset => "UTF-8"
|
7
|
-
}
|
8
|
-
}
|
9
|
-
}
|
10
|
-
|
11
|
-
output {
|
12
|
-
# Print each event to stdout.
|
13
|
-
stdout {
|
14
|
-
codec => rubydebug
|
15
|
-
}
|
16
|
-
|
17
|
-
elasticsearch {
|
18
|
-
# Setting 'embedded' will run a real elasticsearch server inside logstash.
|
19
|
-
# This option below saves you from having to run a separate process just
|
20
|
-
# for ElasticSearch, so you can get started quicker!
|
21
|
-
embedded => true
|
22
|
-
}
|
23
|
-
}
|
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'logstasher/device/redis'
|
4
|
-
|
5
|
-
describe LogStasher::Device::Redis do
|
6
|
-
|
7
|
-
let(:redis_mock) { double('Redis') }
|
8
|
-
|
9
|
-
let(:default_options) {{
|
10
|
-
key: 'logstash',
|
11
|
-
data_type: 'list'
|
12
|
-
}}
|
13
|
-
|
14
|
-
it 'has default options' do
|
15
|
-
device = LogStasher::Device::Redis.new
|
16
|
-
expect(device.options).to eq(default_options)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'creates a redis instance' do
|
20
|
-
expect(::Redis).to receive(:new).with({})
|
21
|
-
LogStasher::Device::Redis.new()
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'assumes unknown options are for redis' do
|
25
|
-
expect(::Redis).to receive(:new).with(hash_including(db: '0'))
|
26
|
-
device = LogStasher::Device::Redis.new(db: '0')
|
27
|
-
expect(device.redis_options).to eq(db: '0')
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'has a key' do
|
31
|
-
device = LogStasher::Device::Redis.new(key: 'the_key')
|
32
|
-
expect(device.key).to eq('the_key')
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'has a data_type' do
|
36
|
-
device = LogStasher::Device::Redis.new(data_type: 'channel')
|
37
|
-
expect(device.data_type).to eq('channel')
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'does not allow unsupported data types' do
|
41
|
-
expect {
|
42
|
-
device = LogStasher::Device::Redis.new(data_type: 'blargh')
|
43
|
-
}.to raise_error()
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'quits the redis connection on #close' do
|
47
|
-
device = LogStasher::Device::Redis.new
|
48
|
-
expect(device.redis).to receive(:quit)
|
49
|
-
device.close
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'works as a logger device' do
|
53
|
-
device = LogStasher::Device::Redis.new
|
54
|
-
expect(device).to receive(:write).with('blargh')
|
55
|
-
logger = Logger.new(device)
|
56
|
-
logger << 'blargh'
|
57
|
-
end
|
58
|
-
|
59
|
-
describe '#write' do
|
60
|
-
it "rpushes logs onto a list" do
|
61
|
-
device = LogStasher::Device::Redis.new(data_type: 'list')
|
62
|
-
expect(device.redis).to receive(:rpush).with('logstash', 'the log')
|
63
|
-
device.write('the log')
|
64
|
-
end
|
65
|
-
|
66
|
-
it "rpushes logs onto a custom key" do
|
67
|
-
device = LogStasher::Device::Redis.new(data_type: 'list', key: 'custom')
|
68
|
-
expect(device.redis).to receive(:rpush).with('custom', 'the log')
|
69
|
-
device.write('the log')
|
70
|
-
end
|
71
|
-
|
72
|
-
it "publishes logs onto a channel" do
|
73
|
-
device = LogStasher::Device::Redis.new(data_type: 'channel', key: 'custom')
|
74
|
-
expect(device.redis).to receive(:publish).with('custom', 'the log')
|
75
|
-
device.write('the log')
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'logstasher/rails_ext/action_controller/metal/instrumentation'
|
3
|
-
|
4
|
-
describe ActionController::Base do
|
5
|
-
before :each do
|
6
|
-
subject.request = ActionDispatch::TestRequest.new
|
7
|
-
subject.response = ActionDispatch::TestResponse.new
|
8
|
-
|
9
|
-
def subject.index(*args)
|
10
|
-
render text: 'OK'
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe ".process_action" do
|
15
|
-
it "adds default fields to payload" do
|
16
|
-
expect(LogStasher).to receive(:add_default_fields_to_payload).once
|
17
|
-
expect(LogStasher).to receive(:add_default_fields_to_request_context).once
|
18
|
-
subject.process_action(:index)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "creates the request context before processing" do
|
22
|
-
LogStasher.request_context[:some_key] = 'value'
|
23
|
-
expect(LogStasher).to receive(:clear_request_context).once.and_call_original
|
24
|
-
expect {
|
25
|
-
subject.process_action(:index)
|
26
|
-
}.to change { LogStasher.request_context }
|
27
|
-
end
|
28
|
-
|
29
|
-
it "notifies rails of a request coming in" do
|
30
|
-
expect(ActiveSupport::Notifications).to receive(:instrument).with("start_processing.action_controller", anything).once
|
31
|
-
expect(ActiveSupport::Notifications).to receive(:instrument).with("process_action.action_controller", anything).once
|
32
|
-
subject.process_action(:index)
|
33
|
-
end
|
34
|
-
|
35
|
-
context "request context has custom fields defined" do
|
36
|
-
before :each do
|
37
|
-
LogStasher.add_custom_fields_to_request_context do |fields|
|
38
|
-
fields[:some_field] = 'value'
|
39
|
-
end
|
40
|
-
|
41
|
-
ActiveSupport::Notifications.subscribe('process_action.action_controller') do |_, _, _, _, payload|
|
42
|
-
@payload = payload
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should retain the value in the request context" do
|
47
|
-
subject.process_action(:index)
|
48
|
-
end
|
49
|
-
|
50
|
-
after :each do
|
51
|
-
expect(@payload[:some_field]).to eq('value')
|
52
|
-
|
53
|
-
ActionController::Metal.class_eval do
|
54
|
-
undef logstasher_add_custom_fields_to_request_context
|
55
|
-
end
|
56
|
-
ActionController::Base.class_eval do
|
57
|
-
undef logstasher_add_custom_fields_to_request_context
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,265 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe LogStasher::RequestLogSubscriber do
|
4
|
-
let(:log_output) {StringIO.new}
|
5
|
-
let(:logger) {
|
6
|
-
logger = Logger.new(log_output)
|
7
|
-
logger.formatter = ->(_, _, _, msg) {
|
8
|
-
msg
|
9
|
-
}
|
10
|
-
def log_output.json
|
11
|
-
JSON.parse! self.string
|
12
|
-
end
|
13
|
-
logger
|
14
|
-
}
|
15
|
-
before do
|
16
|
-
LogStasher.logger = logger
|
17
|
-
LogStasher.log_controller_parameters = true
|
18
|
-
LogStasher.custom_fields = []
|
19
|
-
end
|
20
|
-
after do
|
21
|
-
LogStasher.log_controller_parameters = false
|
22
|
-
end
|
23
|
-
|
24
|
-
let(:subscriber) {LogStasher::RequestLogSubscriber.new}
|
25
|
-
let(:event) {
|
26
|
-
ActiveSupport::Notifications::Event.new(
|
27
|
-
'process_action.action_controller', Time.now, Time.now, 2, {
|
28
|
-
status: 200, format: 'application/json', method: 'GET', path: '/home?foo=bar', params: {
|
29
|
-
:controller => 'home', :action => 'index', 'foo' => 'bar'
|
30
|
-
}.with_indifferent_access, db_runtime: 0.02, view_runtime: 0.01
|
31
|
-
}
|
32
|
-
)
|
33
|
-
}
|
34
|
-
|
35
|
-
let(:redirect) {
|
36
|
-
ActiveSupport::Notifications::Event.new(
|
37
|
-
'redirect_to.action_controller', Time.now, Time.now, 1, location: 'http://example.com', status: 302
|
38
|
-
)
|
39
|
-
}
|
40
|
-
|
41
|
-
describe '.process_action' do
|
42
|
-
let!(:request_subscriber) { @request_subscriber ||= LogStasher::RequestLogSubscriber.new() }
|
43
|
-
let(:payload) { {} }
|
44
|
-
let(:event) { double(:payload => payload) }
|
45
|
-
let(:logger) { double }
|
46
|
-
let(:json) { "{\"@source\":\"unknown\",\"@tags\":[\"request\"],\"@fields\":{\"request\":true,\"status\":true,\"runtimes\":true,\"location\":true,\"exception\":true,\"custom\":true},\"@timestamp\":\"timestamp\"}\n" }
|
47
|
-
before do
|
48
|
-
allow(LogStasher).to receive(:logger).and_return(logger)
|
49
|
-
allow(LogStash::Time).to receive(:now).and_return('timestamp')
|
50
|
-
end
|
51
|
-
it 'calls all extractors and outputs the json' do
|
52
|
-
expect(request_subscriber).to receive(:extract_request).with(payload).and_return({:request => true})
|
53
|
-
expect(request_subscriber).to receive(:extract_status).with(payload).and_return({:status => true})
|
54
|
-
expect(request_subscriber).to receive(:runtimes).with(event).and_return({:runtimes => true})
|
55
|
-
expect(request_subscriber).to receive(:location).with(event).and_return({:location => true})
|
56
|
-
expect(request_subscriber).to receive(:extract_exception).with(payload).and_return({:exception => true})
|
57
|
-
expect(request_subscriber).to receive(:extract_custom_fields).with(payload).and_return({:custom => true})
|
58
|
-
expect(LogStasher.logger).to receive(:<<).with(json)
|
59
|
-
request_subscriber.process_action(event)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe 'logstasher output' do
|
64
|
-
|
65
|
-
it "should contain request tag" do
|
66
|
-
subscriber.process_action(event)
|
67
|
-
expect(log_output.json['@tags']).to include 'request'
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should contain HTTP method" do
|
71
|
-
subscriber.process_action(event)
|
72
|
-
expect(log_output.json['@fields']['method']).to eq 'GET'
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should include the path in the log output" do
|
76
|
-
subscriber.process_action(event)
|
77
|
-
expect(log_output.json['@fields']['path']).to eq '/home'
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should include the format in the log output" do
|
81
|
-
subscriber.process_action(event)
|
82
|
-
expect(log_output.json['@fields']['format']).to eq 'application/json'
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should include the status code" do
|
86
|
-
subscriber.process_action(event)
|
87
|
-
expect(log_output.json['@fields']['status']).to eq 200
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should include the controller" do
|
91
|
-
subscriber.process_action(event)
|
92
|
-
expect(log_output.json['@fields']['controller']).to eq 'home'
|
93
|
-
end
|
94
|
-
|
95
|
-
it "should include the action" do
|
96
|
-
subscriber.process_action(event)
|
97
|
-
expect(log_output.json['@fields']['action']).to eq 'index'
|
98
|
-
end
|
99
|
-
|
100
|
-
it "should include the view rendering time" do
|
101
|
-
subscriber.process_action(event)
|
102
|
-
expect(log_output.json['@fields']['view']).to eq 0.01
|
103
|
-
end
|
104
|
-
|
105
|
-
it "should include the database rendering time" do
|
106
|
-
subscriber.process_action(event)
|
107
|
-
expect(log_output.json['@fields']['db']).to eq 0.02
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should add a valid status when an exception occurred" do
|
111
|
-
begin
|
112
|
-
raise AbstractController::ActionNotFound.new('Could not find an action')
|
113
|
-
# working this in rescue to get access to $! variable
|
114
|
-
rescue
|
115
|
-
event.payload[:status] = nil
|
116
|
-
event.payload[:exception] = ['AbstractController::ActionNotFound', 'Route not found']
|
117
|
-
subscriber.process_action(event)
|
118
|
-
expect(log_output.json['@fields']['status']).to be >= 400
|
119
|
-
expect(log_output.json['@fields']['error']).to be =~ /AbstractController::ActionNotFound.*Route not found.*logstasher\/spec\/lib\/logstasher\/log_subscriber_spec\.rb/m
|
120
|
-
expect(log_output.json['@tags']).to include 'request'
|
121
|
-
expect(log_output.json['@tags']).to include 'exception'
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
it "should return an unknown status when no status or exception is found" do
|
126
|
-
event.payload[:status] = nil
|
127
|
-
event.payload[:exception] = nil
|
128
|
-
subscriber.process_action(event)
|
129
|
-
expect(log_output.json['@fields']['status']).to eq 0
|
130
|
-
end
|
131
|
-
|
132
|
-
describe "with a redirect" do
|
133
|
-
before do
|
134
|
-
Thread.current[:logstasher_location] = "http://www.example.com"
|
135
|
-
end
|
136
|
-
|
137
|
-
it "should add the location to the log line" do
|
138
|
-
subscriber.process_action(event)
|
139
|
-
expect(log_output.json['@fields']['location']).to eq 'http://www.example.com'
|
140
|
-
end
|
141
|
-
|
142
|
-
it "should remove the thread local variable" do
|
143
|
-
subscriber.process_action(event)
|
144
|
-
expect(Thread.current[:logstasher_location]).to be_nil
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
it "should not include a location by default" do
|
149
|
-
subscriber.process_action(event)
|
150
|
-
expect(log_output.json['@fields']['location']).to be_nil
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
describe "with append_custom_params block specified" do
|
155
|
-
let(:request) { double(:remote_ip => '10.0.0.1', :env => {})}
|
156
|
-
it "should add default custom data to the output" do
|
157
|
-
allow(request).to receive_messages(:params => event.payload[:params])
|
158
|
-
LogStasher.add_default_fields_to_payload(event.payload, request)
|
159
|
-
subscriber.process_action(event)
|
160
|
-
expect(log_output.json['@fields']['ip']).to eq '10.0.0.1'
|
161
|
-
expect(log_output.json['@fields']['route']).to eq'home#index'
|
162
|
-
expect(log_output.json['@fields']['parameters']).to eq 'foo' => 'bar'
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
describe "with append_custom_params block specified" do
|
167
|
-
before do
|
168
|
-
allow(LogStasher).to receive(:add_custom_fields) do |&block|
|
169
|
-
@block = block
|
170
|
-
end
|
171
|
-
LogStasher.add_custom_fields do |payload|
|
172
|
-
payload[:user] = 'user'
|
173
|
-
end
|
174
|
-
LogStasher.custom_fields += [:user]
|
175
|
-
end
|
176
|
-
|
177
|
-
it "should add the custom data to the output" do
|
178
|
-
@block.call(event.payload)
|
179
|
-
subscriber.process_action(event)
|
180
|
-
expect(log_output.json['@fields']['user']).to eq 'user'
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
describe "when processing a redirect" do
|
185
|
-
it "should store the location in a thread local variable" do
|
186
|
-
subscriber.redirect_to(redirect)
|
187
|
-
expect(Thread.current[:logstasher_location]).to eq "http://example.com"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
describe LogStasher::MailerLogSubscriber do
|
193
|
-
let(:log_output) {StringIO.new}
|
194
|
-
let(:logger) {
|
195
|
-
logger = Logger.new(log_output)
|
196
|
-
logger.formatter = ->(_, _, _, msg) {
|
197
|
-
msg
|
198
|
-
}
|
199
|
-
def log_output.json
|
200
|
-
JSON.parse!(self.string.split("\n").last)
|
201
|
-
end
|
202
|
-
logger
|
203
|
-
}
|
204
|
-
|
205
|
-
before :all do
|
206
|
-
SampleMailer.delivery_method = :test
|
207
|
-
LogStasher::MailerLogSubscriber.attach_to(:action_mailer)
|
208
|
-
end
|
209
|
-
|
210
|
-
before do
|
211
|
-
LogStasher.logger = logger
|
212
|
-
expect(LogStasher.request_context).to receive(:merge).at_most(2).times.and_call_original
|
213
|
-
end
|
214
|
-
|
215
|
-
let :message do
|
216
|
-
Mail.new do
|
217
|
-
from 'some-dude@example.com'
|
218
|
-
to 'some-other-dude@example.com'
|
219
|
-
subject 'Goodbye'
|
220
|
-
body 'LOL'
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
it 'receive an e-mail' do
|
225
|
-
SampleMailer.receive(message.encoded)
|
226
|
-
log_output.json.tap do |json|
|
227
|
-
expect(json['@source']).to eq(LogStasher.source)
|
228
|
-
expect(json['@tags']).to eq(['mailer', 'receive'])
|
229
|
-
json['@fields'].tap do |fields|
|
230
|
-
expect(fields['mailer']).to eq('SampleMailer')
|
231
|
-
expect(fields['from']).to eq(['some-dude@example.com'])
|
232
|
-
expect(fields['to']).to eq(['some-other-dude@example.com'])
|
233
|
-
expect(fields['message_id']).to eq(message.message_id)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
it 'deliver an outgoing e-mail' do
|
239
|
-
email = SampleMailer.welcome
|
240
|
-
|
241
|
-
if version = ENV['RAILS_VERSION'] and version >= '4.1'
|
242
|
-
log_output.json.tap do |json|
|
243
|
-
expect(json['@source']).to eq(LogStasher.source)
|
244
|
-
expect(json['@tags']).to eq(['mailer', 'process'])
|
245
|
-
json['@fields'].tap do |fields|
|
246
|
-
expect(fields['mailer']).to eq('SampleMailer')
|
247
|
-
expect(fields['action']).to eq('welcome')
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
email.deliver
|
253
|
-
log_output.json.tap do |json|
|
254
|
-
expect(json['@source']).to eq(LogStasher.source)
|
255
|
-
expect(json['@tags']).to eq(['mailer', 'deliver'])
|
256
|
-
json['@fields'].tap do |fields|
|
257
|
-
expect(fields['mailer']).to eq('SampleMailer')
|
258
|
-
expect(fields['from']).to eq(['some-dude@example.com'])
|
259
|
-
expect(fields['to']).to eq(['some-other-dude@example.com'])
|
260
|
-
# Message-Id appears not to be yet available at this point in time.
|
261
|
-
expect(fields['message_id']).to be_nil
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
data/spec/lib/logstasher_spec.rb
DELETED
@@ -1,263 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe LogStasher do
|
4
|
-
describe "when removing Rails' log subscribers" do
|
5
|
-
after do
|
6
|
-
ActionController::LogSubscriber.attach_to :action_controller
|
7
|
-
ActionView::LogSubscriber.attach_to :action_view
|
8
|
-
ActionMailer::LogSubscriber.attach_to :action_mailer
|
9
|
-
end
|
10
|
-
|
11
|
-
it "should remove subscribers for controller events" do
|
12
|
-
expect {
|
13
|
-
LogStasher.remove_existing_log_subscriptions
|
14
|
-
}.to change {
|
15
|
-
ActiveSupport::Notifications.notifier.listeners_for('process_action.action_controller')
|
16
|
-
}
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should remove subscribers for all events" do
|
20
|
-
expect {
|
21
|
-
LogStasher.remove_existing_log_subscriptions
|
22
|
-
}.to change {
|
23
|
-
ActiveSupport::Notifications.notifier.listeners_for('render_template.action_view')
|
24
|
-
}
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should remove subscribsers for mailer events" do
|
28
|
-
expect {
|
29
|
-
LogStasher.remove_existing_log_subscriptions
|
30
|
-
}.to change {
|
31
|
-
ActiveSupport::Notifications.notifier.listeners_for('deliver.action_mailer')
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
it "shouldn't remove subscribers that aren't from Rails" do
|
36
|
-
blk = -> {}
|
37
|
-
ActiveSupport::Notifications.subscribe("process_action.action_controller", &blk)
|
38
|
-
LogStasher.remove_existing_log_subscriptions
|
39
|
-
listeners = ActiveSupport::Notifications.notifier.listeners_for('process_action.action_controller')
|
40
|
-
expect(listeners).to_not be_empty
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe '.appened_default_info_to_payload' do
|
45
|
-
let(:params) { {'a' => '1', 'b' => 2, 'action' => 'action', 'controller' => 'test'}.with_indifferent_access }
|
46
|
-
let(:payload) { {:params => params} }
|
47
|
-
let(:request) { double(:params => params, :remote_ip => '10.0.0.1', :env => {})}
|
48
|
-
after do
|
49
|
-
LogStasher.custom_fields = []
|
50
|
-
LogStasher.log_controller_parameters = false
|
51
|
-
end
|
52
|
-
it 'appends default parameters to payload' do
|
53
|
-
LogStasher.log_controller_parameters = true
|
54
|
-
LogStasher.custom_fields = []
|
55
|
-
LogStasher.add_default_fields_to_payload(payload, request)
|
56
|
-
expect(payload[:ip]).to eq '10.0.0.1'
|
57
|
-
expect(payload[:route]).to eq 'test#action'
|
58
|
-
expect(payload[:parameters]).to eq 'a' => '1', 'b' => 2
|
59
|
-
expect(LogStasher.custom_fields).to eq [:ip, :route, :request_id, :parameters]
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'does not include parameters when not configured to' do
|
63
|
-
LogStasher.custom_fields = []
|
64
|
-
LogStasher.add_default_fields_to_payload(payload, request)
|
65
|
-
expect(payload).to_not have_key(:parameters)
|
66
|
-
expect(LogStasher.custom_fields).to eq [:ip, :route, :request_id]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe '.append_custom_params' do
|
71
|
-
let(:block) { ->(_, _){} }
|
72
|
-
it 'defines a method in ActionController::Base' do
|
73
|
-
expect(ActionController::Base).to receive(:send).with(:define_method, :logtasher_add_custom_fields_to_payload, &block)
|
74
|
-
LogStasher.add_custom_fields(&block)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe '.add_custom_fields_to_request_context' do
|
79
|
-
let(:block) { ->(_, _){} }
|
80
|
-
it 'defines a method in ActionController::Base' do
|
81
|
-
expect(ActionController::Base).to receive(:send).with(:define_method, :logstasher_add_custom_fields_to_request_context, &block)
|
82
|
-
expect(ActionController::Metal).to receive(:send).with(:define_method, :logstasher_add_custom_fields_to_request_context, &block)
|
83
|
-
LogStasher.add_custom_fields_to_request_context(&block)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
describe '.add_default_fields_to_request_context' do
|
88
|
-
it 'adds a request_id to the request context' do
|
89
|
-
LogStasher.clear_request_context
|
90
|
-
LogStasher.add_default_fields_to_request_context(double(env: {'action_dispatch.request_id' => 'lol'}))
|
91
|
-
expect(LogStasher.request_context).to eq({ request_id: 'lol' })
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
shared_examples 'setup' do
|
96
|
-
let(:logstasher_source) { nil }
|
97
|
-
let(:logstasher_config) { double(:logger => logger, :log_level => 'warn', :log_controller_parameters => nil, :source => logstasher_source, :logger_path => logger_path) }
|
98
|
-
let(:config) { double(:logstasher => logstasher_config) }
|
99
|
-
let(:app) { double(:config => config) }
|
100
|
-
before do
|
101
|
-
@previous_source = LogStasher.source
|
102
|
-
allow(config).to receive_messages(:action_dispatch => double(:rack_cache => false))
|
103
|
-
allow_message_expectations_on_nil
|
104
|
-
end
|
105
|
-
after { LogStasher.source = @previous_source } # Need to restore old source for specs
|
106
|
-
it 'defines a method in ActionController::Base' do
|
107
|
-
expect(LogStasher).to receive(:require).with('logstasher/rails_ext/action_controller/metal/instrumentation')
|
108
|
-
expect(LogStasher).to receive(:require).with('logstash-event')
|
109
|
-
expect(LogStasher).to receive(:suppress_app_logs).with(app)
|
110
|
-
expect(LogStasher::RequestLogSubscriber).to receive(:attach_to).with(:action_controller)
|
111
|
-
expect(LogStasher::MailerLogSubscriber).to receive(:attach_to).with(:action_mailer)
|
112
|
-
expect(logger).to receive(:level=).with('warn')
|
113
|
-
LogStasher.setup(app)
|
114
|
-
expect(LogStasher.source).to eq (logstasher_source || 'unknown')
|
115
|
-
expect(LogStasher).to be_enabled
|
116
|
-
expect(LogStasher.custom_fields).to be_empty
|
117
|
-
expect(LogStasher.log_controller_parameters).to eq false
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe '.setup' do
|
122
|
-
let(:logger) { double }
|
123
|
-
let(:logger_path) { nil }
|
124
|
-
|
125
|
-
describe 'with source set' do
|
126
|
-
let(:logstasher_source) { 'foo' }
|
127
|
-
it_behaves_like 'setup'
|
128
|
-
end
|
129
|
-
|
130
|
-
describe 'without source set (default behaviour)' do
|
131
|
-
let(:logstasher_source) { nil }
|
132
|
-
it_behaves_like 'setup'
|
133
|
-
end
|
134
|
-
|
135
|
-
describe 'with customized logging' do
|
136
|
-
let(:logger) { nil }
|
137
|
-
|
138
|
-
context 'with no logger passed in' do
|
139
|
-
before { expect(LogStasher).to receive(:new_logger).with('/log/logstash_test.log') }
|
140
|
-
it_behaves_like 'setup'
|
141
|
-
end
|
142
|
-
|
143
|
-
context 'with custom logger path passed in' do
|
144
|
-
let(:logger_path) { double }
|
145
|
-
|
146
|
-
before { expect(LogStasher).to receive(:new_logger).with(logger_path) }
|
147
|
-
it_behaves_like 'setup'
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
describe '.suppress_app_logs' do
|
153
|
-
let(:logstasher_config){ double(:logstasher => double(:suppress_app_log => true))}
|
154
|
-
let(:app){ double(:config => logstasher_config)}
|
155
|
-
it 'removes existing subscription if enabled' do
|
156
|
-
expect(LogStasher).to receive(:require).with('logstasher/rails_ext/rack/logger')
|
157
|
-
expect(LogStasher).to receive(:remove_existing_log_subscriptions)
|
158
|
-
LogStasher.suppress_app_logs(app)
|
159
|
-
end
|
160
|
-
|
161
|
-
context 'when disabled' do
|
162
|
-
let(:logstasher_config){ double(:logstasher => double(:suppress_app_log => false)) }
|
163
|
-
it 'does not remove existing subscription' do
|
164
|
-
expect(LogStasher).to_not receive(:remove_existing_log_subscriptions)
|
165
|
-
LogStasher.suppress_app_logs(app)
|
166
|
-
end
|
167
|
-
|
168
|
-
describe "backward compatibility" do
|
169
|
-
context 'with spelling "supress_app_log"' do
|
170
|
-
let(:logstasher_config){ double(:logstasher => double(:suppress_app_log => nil, :supress_app_log => false)) }
|
171
|
-
it 'does not remove existing subscription' do
|
172
|
-
expect(LogStasher).to_not receive(:remove_existing_log_subscriptions)
|
173
|
-
LogStasher.suppress_app_logs(app)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
describe '.appended_params' do
|
181
|
-
it 'returns the stored var in current thread' do
|
182
|
-
Thread.current[:logstasher_custom_fields] = :test
|
183
|
-
expect(LogStasher.custom_fields).to eq :test
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
describe '.appended_params=' do
|
188
|
-
it 'returns the stored var in current thread' do
|
189
|
-
LogStasher.custom_fields = :test
|
190
|
-
expect(Thread.current[:logstasher_custom_fields]).to eq :test
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
describe '.log' do
|
195
|
-
let(:logger) { double() }
|
196
|
-
before do
|
197
|
-
LogStasher.logger = logger
|
198
|
-
allow(LogStash::Time).to receive_messages(:now => 'timestamp')
|
199
|
-
allow_message_expectations_on_nil
|
200
|
-
end
|
201
|
-
it 'adds to log with specified level' do
|
202
|
-
expect(logger).to receive(:send).with('warn?').and_return(true)
|
203
|
-
expect(logger).to receive(:send).with('warn',"{\"@source\":\"unknown\",\"@tags\":[\"log\"],\"@fields\":{\"message\":\"WARNING\",\"level\":\"warn\"},\"@timestamp\":\"timestamp\"}")
|
204
|
-
LogStasher.log('warn', 'WARNING')
|
205
|
-
end
|
206
|
-
context 'with a source specified' do
|
207
|
-
before :each do
|
208
|
-
LogStasher.source = 'foo'
|
209
|
-
end
|
210
|
-
it 'sets the correct source' do
|
211
|
-
expect(logger).to receive(:send).with('warn?').and_return(true)
|
212
|
-
expect(logger).to receive(:send).with('warn',"{\"@source\":\"foo\",\"@tags\":[\"log\"],\"@fields\":{\"message\":\"WARNING\",\"level\":\"warn\"},\"@timestamp\":\"timestamp\"}")
|
213
|
-
LogStasher.log('warn', 'WARNING')
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
%w( fatal error warn info debug unknown ).each do |severity|
|
219
|
-
describe ".#{severity}" do
|
220
|
-
let(:message) { "This is a #{severity} message" }
|
221
|
-
it 'should log with specified level' do
|
222
|
-
expect(LogStasher).to receive(:log).with(severity.to_sym, message)
|
223
|
-
LogStasher.send(severity, message )
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
describe '.store' do
|
229
|
-
it "returns a new Hash for each key" do
|
230
|
-
expect(LogStasher.store['a'].object_id).to_not be(LogStasher.store['b'].object_id)
|
231
|
-
end
|
232
|
-
|
233
|
-
it "returns the same store if called several time with the same key" do
|
234
|
-
expect(LogStasher.store['a'].object_id).to be(LogStasher.store['a'].object_id)
|
235
|
-
end
|
236
|
-
|
237
|
-
end
|
238
|
-
|
239
|
-
describe ".watch" do
|
240
|
-
before(:each) { LogStasher.custom_fields = [] }
|
241
|
-
|
242
|
-
it "subscribes to the required event" do
|
243
|
-
expect(ActiveSupport::Notifications).to receive(:subscribe).with('event_name')
|
244
|
-
LogStasher.watch('event_name')
|
245
|
-
end
|
246
|
-
|
247
|
-
it 'executes the block when receiving an event' do
|
248
|
-
probe = lambda {}
|
249
|
-
LogStasher.watch('custom.event.foo', &probe)
|
250
|
-
expect(probe).to receive(:call)
|
251
|
-
ActiveSupport::Notifications.instrument('custom.event.foo', {})
|
252
|
-
end
|
253
|
-
|
254
|
-
describe "store" do
|
255
|
-
it 'stores the events in a store with the event\'s name' do
|
256
|
-
probe = lambda { |*args, store| store[:foo] = :bar }
|
257
|
-
LogStasher.watch('custom.event.bar', &probe)
|
258
|
-
ActiveSupport::Notifications.instrument('custom.event.bar', {})
|
259
|
-
expect(LogStasher.store['custom.event.bar']).to eq :foo => :bar
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
# Notice there is a .rspec file in the root folder. It defines rspec arguments
|
2
|
-
|
3
|
-
# Ruby 1.9 uses simplecov. The ENV['COVERAGE'] is set when rake coverage is run in ruby 1.9
|
4
|
-
if ENV['COVERAGE']
|
5
|
-
require 'simplecov'
|
6
|
-
SimpleCov.start do
|
7
|
-
# Remove the spec folder from coverage. By default all code files are included. For more config options see
|
8
|
-
# https://github.com/colszowka/simplecov
|
9
|
-
add_filter File.expand_path('../../spec', __FILE__)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Modify load path so you can require 'ogstasher directly.
|
14
|
-
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
15
|
-
|
16
|
-
require 'rubygems'
|
17
|
-
# Loads bundler setup tasks. Now if I run spec without installing gems then it would say gem not installed and
|
18
|
-
# do bundle install instead of ugly load error on require.
|
19
|
-
require 'bundler/setup'
|
20
|
-
|
21
|
-
# This will require me all the gems automatically for the groups. If I do only .setup then I will have to require gems
|
22
|
-
# manually. Note that you have still have to require some gems if they are part of bigger gem like ActiveRecord which is
|
23
|
-
# part of Rails. You can say :require => false in gemfile to always use explicit requiring
|
24
|
-
Bundler.require(:default, :test)
|
25
|
-
|
26
|
-
Dir[File.join("./spec/support/**/*.rb")].each { |f| require f }
|
27
|
-
|
28
|
-
# Set Rails environment as test
|
29
|
-
ENV['RAILS_ENV'] = 'test'
|
30
|
-
|
31
|
-
require 'action_pack'
|
32
|
-
require 'action_controller'
|
33
|
-
require 'logstasher'
|
34
|
-
require 'active_support/notifications'
|
35
|
-
require 'active_support/core_ext/string'
|
36
|
-
require 'active_support/log_subscriber'
|
37
|
-
require 'action_controller/log_subscriber'
|
38
|
-
require 'action_view/log_subscriber'
|
39
|
-
require 'active_support/core_ext/hash/except'
|
40
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
41
|
-
require 'active_support/core_ext/hash/slice'
|
42
|
-
require 'active_support/core_ext/string'
|
43
|
-
require 'active_support/core_ext/time/zones'
|
44
|
-
require 'abstract_controller/base'
|
45
|
-
require 'action_mailer'
|
46
|
-
require 'logger'
|
47
|
-
require 'logstash-event'
|
48
|
-
|
49
|
-
RSpec.configure do |config|
|
50
|
-
config.run_all_when_everything_filtered = true
|
51
|
-
config.filter_run :focus
|
52
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'action_mailer'
|
2
|
-
|
3
|
-
class SampleMailer < ActionMailer::Base
|
4
|
-
def welcome
|
5
|
-
mail(from: 'some-dude@example.com', to: 'some-other-dude@example.com', subject: 'Hello, there') do |format|
|
6
|
-
format.text { render plain: 'OK' }
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
def receive(email)
|
11
|
-
end
|
12
|
-
|
13
|
-
def _render_template(_)
|
14
|
-
""
|
15
|
-
end
|
16
|
-
end
|