logging_elf 0.0.1
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 +7 -0
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +9 -0
- data/Guardfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +6 -0
- data/lib/logging_elf.rb +16 -0
- data/lib/logging_elf/config.rb +14 -0
- data/lib/logging_elf/gelf_appender.rb +22 -0
- data/lib/logging_elf/gelf_data.rb +85 -0
- data/lib/logging_elf/lograge_formatter.rb +8 -0
- data/lib/logging_elf/tracing_logger.rb +80 -0
- data/lib/logging_elf/uncaught_exceptions_middleware.rb +26 -0
- data/lib/logging_elf/version.rb +3 -0
- data/logging_elf.gemspec +30 -0
- data/spec/integrations/entire_flow_spec.rb +66 -0
- data/spec/logging_elf/gelf_data_spec.rb +146 -0
- data/spec/logging_elf/tracing_logger_spec.rb +95 -0
- data/spec/logging_elf/uncaught_exceptions_middleware_spec.rb +64 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/config.rb +4 -0
- data/spec/support/fake_logger.rb +15 -0
- metadata +174 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: edd72f1b9a67df249d70aa481c0ddb1eb8e77674
|
4
|
+
data.tar.gz: bdb49524283475272dc2fc46b3a039cda6ae802e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4dfd2ae5addd66e46cdc1d769a93fbe77b098acef96e9e8e64763c8ffc309feb5689a08d9d8fbb7fd159d05f656e98bb1aace67633df7578ae5c2c3565b1cf32
|
7
|
+
data.tar.gz: 4aca640abc72f3754bf12182dccc7429833b8be8ab5afb2f0781d6906eb8164bc18b6dc16b2173be1f7da7486abbeec209c421312f61412cdca45df2ce86970a
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec do
|
5
|
+
watch(%r{^lib/(.+)\.rb$}) do |m|
|
6
|
+
["spec/#{m[1]}_spec.rb", "spec/integrations/entire_flow_spec.rb"]
|
7
|
+
end
|
8
|
+
watch(%r{^spec/.+_spec\.rb$})
|
9
|
+
watch('spec/spec_helper.rb') { "spec" }
|
10
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jeff Deville
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# LoggingElf
|
2
|
+
[](https://travis-ci.org/promptworks/logging_elf)
|
3
|
+
|
4
|
+
TODO: Write a gem description
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'logging_elf'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install logging_elf
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
TODO: Write usage instructions here
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
|
26
|
+
1. Fork it ( https://github.com/[my-github-username]/logging_elf/fork )
|
27
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
28
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
29
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
30
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/logging_elf.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
require 'virtus'
|
4
|
+
require 'logging'
|
5
|
+
require 'gelf'
|
6
|
+
|
7
|
+
require "logging_elf/version"
|
8
|
+
require "logging_elf/config"
|
9
|
+
require "logging_elf/gelf_data"
|
10
|
+
require "logging_elf/gelf_appender"
|
11
|
+
require "logging_elf/tracing_logger"
|
12
|
+
require "logging_elf/lograge_formatter"
|
13
|
+
require "logging_elf/uncaught_exceptions_middleware"
|
14
|
+
|
15
|
+
module LoggingElf
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Logging::Appenders
|
2
|
+
def self.gelf(*args)
|
3
|
+
LoggingElf::GelfAppender.new(*args)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
module LoggingElf
|
8
|
+
class GelfAppender < ::Logging::Appender
|
9
|
+
attr_accessor :logger
|
10
|
+
def initialize(opts = {})
|
11
|
+
super "gelf", opts
|
12
|
+
@logger = GELF::Logger.new(
|
13
|
+
opts[:graylog_host], opts[:graylog_port], "WAN")
|
14
|
+
end
|
15
|
+
|
16
|
+
def write(event)
|
17
|
+
return if event.data.is_a?(String) && event.data.blank?
|
18
|
+
message = GelfData.from_log_event event
|
19
|
+
@logger.notify! message.to_gelf
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# http://graylog2.org/gelf#specs
|
2
|
+
# Some appenders can output to different formats, but this isn't
|
3
|
+
# one of them, so it's simplified as a result.
|
4
|
+
|
5
|
+
module LoggingElf
|
6
|
+
class GelfData
|
7
|
+
include Virtus.model
|
8
|
+
include ActiveModel::Validations
|
9
|
+
|
10
|
+
attribute :host, String
|
11
|
+
attribute :version, String, default: "1.0"
|
12
|
+
attribute :short_message, String
|
13
|
+
attribute :full_message, String
|
14
|
+
# UNIX microsecond timestamp, should be set by client!
|
15
|
+
attribute :timestamp, Integer
|
16
|
+
attribute :level, Integer
|
17
|
+
# Have to set this way even though facility is deprecated
|
18
|
+
# because gelf-rb will overwrite it otherwise
|
19
|
+
attribute :facility, String
|
20
|
+
attr_accessor :additional_fields
|
21
|
+
validates :host, :version, :short_message, presence: true
|
22
|
+
|
23
|
+
def initialize(gelf_data = {})
|
24
|
+
super
|
25
|
+
self.additional_fields ||= {}
|
26
|
+
self.host ||= LoggingElf.config.host if LoggingElf.config
|
27
|
+
return if gelf_data.nil?
|
28
|
+
add_fields(gelf_data)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_gelf
|
32
|
+
required_gelf_attributes.merge additional_fields
|
33
|
+
end
|
34
|
+
|
35
|
+
def required_gelf_attributes
|
36
|
+
attributes
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.from_log_event(log_event)
|
40
|
+
gd = GelfData.new(level: log_event.level, facility: log_event.logger)
|
41
|
+
case log_event.data
|
42
|
+
when String then gd.short_message = log_event.data
|
43
|
+
when Hash then add_hash_data(gd, log_event.data)
|
44
|
+
when Exception then add_exception_details gd, log_event.data
|
45
|
+
end
|
46
|
+
set_backtrace_data gd, log_event
|
47
|
+
gd
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.add_hash_data(gelf_data, data)
|
51
|
+
gelf_data.add_fields(data)
|
52
|
+
|
53
|
+
unless gelf_data.short_message
|
54
|
+
gelf_data.short_message = data[:message] || data["message"]
|
55
|
+
if gelf_data.short_message.blank?
|
56
|
+
gelf_data.short_message = data.map { |k, v| "#{k}='#{v}'" }.join(" ")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_fields(params_hash)
|
62
|
+
params_hash.each do |key, value|
|
63
|
+
if required_gelf_attributes.keys.include? key
|
64
|
+
send("#{key}=", value)
|
65
|
+
else
|
66
|
+
additional_fields["_#{key}".to_sym] = value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.add_exception_details(gelf_data, error)
|
72
|
+
gelf_data.full_message = gelf_data.short_message =
|
73
|
+
"<#{error.class.name}> #{error.message}"
|
74
|
+
if error.backtrace
|
75
|
+
gelf_data.full_message << "\n\t" << error.backtrace.join("\n\t")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.set_backtrace_data(gelf_data, event)
|
80
|
+
gelf_data.add_fields(file: event.file) if event.file
|
81
|
+
gelf_data.add_fields(file: event.line) if event.line
|
82
|
+
gelf_data.add_fields(file: event.method) if event.method
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module LoggingElf
|
2
|
+
class TracingLogger
|
3
|
+
extend Forwardable
|
4
|
+
def_delegators :@logger, :<<, :<=>, :_dump_configuration, :_meta_eval,
|
5
|
+
:add, :add_appenders, :additive, :additive=, :appenders, :appenders=,
|
6
|
+
:clear_appenders, :inspect, :level, :level=, :name, :parent, :_setup,
|
7
|
+
:remove_appenders, :trace, :trace=, :write, :formatter, :root, :config
|
8
|
+
|
9
|
+
Logging.init
|
10
|
+
|
11
|
+
def_delegators :@logger,
|
12
|
+
*Logging::LEVELS.map { |name, _| "#{name}?".to_sym }
|
13
|
+
|
14
|
+
Logging::LEVELS.each do |name, _|
|
15
|
+
define_method name.to_sym do |data = nil|
|
16
|
+
begin
|
17
|
+
# data = yield if block_given?
|
18
|
+
return if data.nil?
|
19
|
+
data = append_trace_info(data)
|
20
|
+
@logger.send(name.to_sym, data)
|
21
|
+
rescue => err
|
22
|
+
p err
|
23
|
+
pp err.backtrace
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(logger, &trace_hash)
|
29
|
+
@logger = Logging::Logger.new logger if logger.is_a? String
|
30
|
+
self.trace_hash = if block_given?
|
31
|
+
trace_hash
|
32
|
+
elsif LoggingElf.config.trace_hash
|
33
|
+
LoggingElf.config.trace_hash
|
34
|
+
else
|
35
|
+
fail "TracingLogger cannot be created with no" \
|
36
|
+
" mechanism for appending trace data"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_writer :trace_hash
|
41
|
+
def trace_hash
|
42
|
+
hash = if @trace_hash.respond_to?(:call)
|
43
|
+
@trace_hash.call
|
44
|
+
else
|
45
|
+
@trace_hash
|
46
|
+
end
|
47
|
+
|
48
|
+
hash || {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def exception_data(data)
|
52
|
+
{
|
53
|
+
error_object: data,
|
54
|
+
backtrace: data.backtrace,
|
55
|
+
short_message: "Exception: #{data.message}",
|
56
|
+
message: data.message,
|
57
|
+
is_exception: true
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def default_data(data)
|
62
|
+
{
|
63
|
+
short_message: "Unknown thing to log",
|
64
|
+
message: data.inspect
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def append_trace_info(data)
|
69
|
+
data = case data
|
70
|
+
when Hash then data
|
71
|
+
when Exception then exception_data(data)
|
72
|
+
when String then { message: data }
|
73
|
+
when nil then return
|
74
|
+
else
|
75
|
+
default_data(data)
|
76
|
+
end
|
77
|
+
data.merge(trace_hash)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module LoggingElf
|
2
|
+
class UncaughtExceptionsMiddleware
|
3
|
+
attr_accessor :logger
|
4
|
+
def initialize(app, args = {})
|
5
|
+
self.logger = args[:logger]
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
begin
|
11
|
+
response = @app.call env
|
12
|
+
rescue => err
|
13
|
+
logger.error err
|
14
|
+
raise err
|
15
|
+
end
|
16
|
+
log_rack_exceptions(env)
|
17
|
+
response
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def log_rack_exceptions(env)
|
23
|
+
logger.error env['rack.exception'] if env['rack.exception']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/logging_elf.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# rubocop:disable RegexpLiteral
|
2
|
+
# coding: utf-8
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'logging_elf/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "logging_elf"
|
9
|
+
spec.version = LoggingElf::VERSION
|
10
|
+
spec.authors = ["Jeff Deville"]
|
11
|
+
spec.email = ["jeffdeville@gmail.com"]
|
12
|
+
spec.summary = "Logging, Tracing, and Gelf Logging for rails"
|
13
|
+
spec.description = "Logging, Tracing, and Gelf Logging for rails"
|
14
|
+
spec.homepage = ""
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "logging", "~> 1.8"
|
23
|
+
spec.add_dependency "virtus", "~> 1.0"
|
24
|
+
spec.add_dependency "activemodel"
|
25
|
+
spec.add_dependency "gelf"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
28
|
+
spec.add_development_dependency 'rake'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 2.0'
|
30
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class FakeGelfNotifier
|
4
|
+
attr_accessor :logs
|
5
|
+
def initialize
|
6
|
+
self.logs = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def notify!(data)
|
10
|
+
logs << data
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Tracing all the way through" do
|
15
|
+
let(:notifier) do
|
16
|
+
# Lets us look at what was sent to the appenders
|
17
|
+
FakeGelfNotifier.new
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:trace_hash) { { browser_id: "browser_id" } }
|
21
|
+
|
22
|
+
let(:gelf_data_hash) { notifier.logs.last }
|
23
|
+
|
24
|
+
before do
|
25
|
+
LoggingElf.configure do |config|
|
26
|
+
config.trace_hash = -> { trace_hash }
|
27
|
+
config.host = "host"
|
28
|
+
end
|
29
|
+
|
30
|
+
logger = LoggingElf::TracingLogger.new("test")
|
31
|
+
logger.class.name.should eq "LoggingElf::TracingLogger"
|
32
|
+
appender = Logging::Appenders.gelf
|
33
|
+
appender.logger = notifier
|
34
|
+
logger.add_appenders(appender)
|
35
|
+
logger.info log_subject
|
36
|
+
end
|
37
|
+
|
38
|
+
shared_examples_for "gelf data output" do
|
39
|
+
let(:reconstituted_gelf_data) do
|
40
|
+
gelf_data_hash.select { |k, _| k.to_s.start_with?("_") }.each do |k, v|
|
41
|
+
gelf_data_hash["#{k.slice(1..-1)}"] = gelf_data_hash.delete k
|
42
|
+
end
|
43
|
+
LoggingElf::GelfData.new gelf_data_hash
|
44
|
+
end
|
45
|
+
|
46
|
+
specify { expect(reconstituted_gelf_data).to be_valid }
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "logging a string" do
|
50
|
+
let(:log_subject) { "string message" }
|
51
|
+
it_should_behave_like "gelf data output"
|
52
|
+
specify { expect(gelf_data_hash[:short_message]).to eq "string message" }
|
53
|
+
specify { expect(gelf_data_hash[:_browser_id]).to eq "browser_id" }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "logging a hash" do
|
57
|
+
let(:log_subject) { { foo: 'bar' } }
|
58
|
+
it_should_behave_like "gelf data output"
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "logging an exception" do
|
62
|
+
let(:log_subject) { RuntimeError.new "Boom" }
|
63
|
+
it_should_behave_like "gelf data output"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include Logging
|
3
|
+
include LoggingElf
|
4
|
+
|
5
|
+
describe GelfData do
|
6
|
+
describe ".valid?" do
|
7
|
+
it "should ensure validity of the data object" do
|
8
|
+
gd = GelfData.new
|
9
|
+
gd.version = nil
|
10
|
+
gd.should_not be_valid
|
11
|
+
gd.errors.count.should eq 3
|
12
|
+
|
13
|
+
gd.host = "host"
|
14
|
+
gd.should_not be_valid
|
15
|
+
gd.errors.count.should eq 2
|
16
|
+
|
17
|
+
gd.version = "12"
|
18
|
+
gd.should_not be_valid
|
19
|
+
gd.errors.count.should eq 1
|
20
|
+
|
21
|
+
gd.short_message = "short message"
|
22
|
+
gd.should be_valid
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should pull the host from the LoggingElf.config if not specified" do
|
26
|
+
LoggingElf.configure do |config|
|
27
|
+
config.host = "host"
|
28
|
+
end
|
29
|
+
gd = GelfData.new
|
30
|
+
gd.host.should == "host"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#add_fields" do
|
35
|
+
let(:gd) { GelfData.new }
|
36
|
+
|
37
|
+
it "sets a required attribute" do
|
38
|
+
gd.add_fields(host: "localhost")
|
39
|
+
|
40
|
+
gd.host.should eq "localhost"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "adds non-required fields to the additional_fields hash" do
|
44
|
+
gd.add_fields(extra_field: "extra value")
|
45
|
+
|
46
|
+
gd.additional_fields[:_extra_field].should eq "extra value"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "initialize" do
|
51
|
+
it "should set standard params via constructor" do
|
52
|
+
gd = GelfData.new(
|
53
|
+
host: "host",
|
54
|
+
version: "123",
|
55
|
+
short_message: "short_message",
|
56
|
+
full_message: "full_message",
|
57
|
+
timestamp: 123,
|
58
|
+
level: 1
|
59
|
+
)
|
60
|
+
gd.host.should eq "host"
|
61
|
+
gd.version.should eq '123'
|
62
|
+
gd.short_message.should eq 'short_message'
|
63
|
+
gd.full_message.should eq 'full_message'
|
64
|
+
gd.timestamp.should eq 123
|
65
|
+
gd.level.should eq 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "from_log_event" do
|
70
|
+
let(:event) { LogEvent.new("testing", 3, data, trace) }
|
71
|
+
let(:trace) { nil }
|
72
|
+
subject { GelfData.from_log_event event }
|
73
|
+
|
74
|
+
shared_examples_for "all gelf data" do
|
75
|
+
specify { expect(subject.short_message).to_not be_blank }
|
76
|
+
end
|
77
|
+
|
78
|
+
context "with a hash" do
|
79
|
+
let(:data) do
|
80
|
+
{ extra_field: "extra value", facility: "facility" }.merge(message)
|
81
|
+
end
|
82
|
+
%w[message short_message].each do |field_name|
|
83
|
+
%i[to_s to_sym].each do |field_name_format|
|
84
|
+
context "with a #{field_name} #{field_name_format}" do
|
85
|
+
let(:message) do
|
86
|
+
{ field_name.send(field_name_format) => "message" }
|
87
|
+
end
|
88
|
+
specify do
|
89
|
+
subject.additional_fields[:_extra_field].should eq "extra value"
|
90
|
+
end
|
91
|
+
it_should_behave_like "all gelf data"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with no discernible message" do
|
97
|
+
let(:message) { {} }
|
98
|
+
specify do
|
99
|
+
expect(subject.short_message).to eq(
|
100
|
+
"extra_field='extra value' facility='facility'")
|
101
|
+
end
|
102
|
+
it_should_behave_like "all gelf data"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "with a string" do
|
107
|
+
let(:data) { "I am a string" }
|
108
|
+
specify { expect(subject.short_message).to eq data }
|
109
|
+
end
|
110
|
+
|
111
|
+
context "with an exception" do
|
112
|
+
let(:data) { { error_object: RuntimeError.new("hi") } }
|
113
|
+
it_should_behave_like "all gelf data"
|
114
|
+
|
115
|
+
context "and a trace" do
|
116
|
+
let(:trace) { caller }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "to_gelf" do
|
122
|
+
let(:gd) do
|
123
|
+
GelfData.new(
|
124
|
+
host: "host",
|
125
|
+
short_message: "short_message",
|
126
|
+
full_message: "full_message",
|
127
|
+
timestamp: 123,
|
128
|
+
level: 1,
|
129
|
+
line: 12,
|
130
|
+
file: "file",
|
131
|
+
facility: "facility",
|
132
|
+
other_data: "other_data"
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "adds a version" do
|
137
|
+
gd.to_gelf.keys.should include(:version)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "prepends an underscore to some key names" do
|
141
|
+
keys = gd.to_gelf.keys
|
142
|
+
keys.should include(:_line, :_file, :_other_data)
|
143
|
+
keys.should_not include(:line, :file, :other_data)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include Logging
|
3
|
+
include LoggingElf
|
4
|
+
|
5
|
+
describe LoggingElf::TracingLogger do
|
6
|
+
let(:fake_appender) do
|
7
|
+
# Lets us look at what was sent to the appenders
|
8
|
+
class FakeAppender < ::Logging::Appender
|
9
|
+
attr_accessor :logs
|
10
|
+
def initialize(name, opts)
|
11
|
+
super(name, opts)
|
12
|
+
self.logs = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def write(data)
|
16
|
+
logs << data
|
17
|
+
end
|
18
|
+
end
|
19
|
+
FakeAppender.new("test", level: 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:trace_hash) do
|
23
|
+
{
|
24
|
+
browser_id: "browser_id",
|
25
|
+
session_id: "session_id",
|
26
|
+
request_method: "request.method",
|
27
|
+
path: "request.path"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
let!(:result) do
|
32
|
+
subject.info data
|
33
|
+
recent_event = fake_appender.logs.last
|
34
|
+
recent_event.nil? ? nil : recent_event.data
|
35
|
+
end
|
36
|
+
|
37
|
+
shared_examples_for "log info should include trace data" do
|
38
|
+
it "should include the trace hash" do
|
39
|
+
result[:browser_id].should eq trace_hash[:browser_id]
|
40
|
+
result[:session_id].should eq trace_hash[:session_id]
|
41
|
+
result[:request_method].should eq trace_hash[:request_method]
|
42
|
+
result[:path].should eq trace_hash[:path]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
subject do
|
47
|
+
logger = TracingLogger.new("test") { trace_hash }
|
48
|
+
logger.appenders = fake_appender
|
49
|
+
logger
|
50
|
+
end
|
51
|
+
|
52
|
+
context "logging nil" do
|
53
|
+
let(:data) { nil }
|
54
|
+
specify { expect(result).to be_nil }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "logging a hash" do
|
58
|
+
let(:data) do
|
59
|
+
{
|
60
|
+
field1: "field1",
|
61
|
+
field2: "field2"
|
62
|
+
}
|
63
|
+
end
|
64
|
+
it_should_behave_like "log info should include trace data"
|
65
|
+
it "should include the original data as well" do
|
66
|
+
result[:field1].should eq data[:field1]
|
67
|
+
result[:field2].should eq data[:field2]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "logging a string" do
|
72
|
+
let(:data) { "I am a Log Event" }
|
73
|
+
specify { expect(result[:message]).to eq data }
|
74
|
+
it_should_behave_like "log info should include trace data"
|
75
|
+
end
|
76
|
+
|
77
|
+
context "logging an exception" do
|
78
|
+
let(:data) { RuntimeError.new "Hi" }
|
79
|
+
it_should_behave_like "log info should include trace data"
|
80
|
+
specify { result[:is_exception].should be_truthy }
|
81
|
+
specify { result[:error_object].should eq data }
|
82
|
+
specify { result[:backtrace].should eq data.backtrace }
|
83
|
+
specify { result[:message].should eq "Hi" }
|
84
|
+
specify { result[:short_message].should eq "Exception: Hi" }
|
85
|
+
end
|
86
|
+
|
87
|
+
context "logging an unknown type" do
|
88
|
+
let(:data) { OpenStruct.new(jeff: "was here ") }
|
89
|
+
it_should_behave_like "log info should include trace data"
|
90
|
+
it "should still log something" do
|
91
|
+
result[:message].should eq data.inspect
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LoggingElf::UncaughtExceptionsMiddleware do
|
4
|
+
describe "call" do
|
5
|
+
let(:logger) { FakeLogger.new }
|
6
|
+
let(:last_msg) { logger.logs.last }
|
7
|
+
let(:app) { double }
|
8
|
+
let(:env) { { test: "test" } }
|
9
|
+
let(:response) { "I am the response" }
|
10
|
+
subject do
|
11
|
+
LoggingElf::UncaughtExceptionsMiddleware.new app, logger: logger
|
12
|
+
end
|
13
|
+
|
14
|
+
def act
|
15
|
+
@returned_response = subject.call env
|
16
|
+
end
|
17
|
+
|
18
|
+
context "no errors occurred" do
|
19
|
+
before do
|
20
|
+
app.stub(:call).with(env).and_return response
|
21
|
+
act
|
22
|
+
end
|
23
|
+
it 'should not have logged anything' do
|
24
|
+
logger.logs.count.should eq 0
|
25
|
+
end
|
26
|
+
specify { @returned_response.should_not be_nil }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "an uncaught exception is raised" do
|
30
|
+
before do
|
31
|
+
app.stub(:call).with(env).and_raise(StandardError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should have logged the error' do
|
35
|
+
begin
|
36
|
+
act
|
37
|
+
# rubocop:disable HandleExceptions
|
38
|
+
rescue
|
39
|
+
# rubocop:enable HandleExceptions
|
40
|
+
ensure
|
41
|
+
logger.logs.count.should eq 1
|
42
|
+
last_msg.should be_a StandardError
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 're-raises the exception' do
|
47
|
+
expect { act }.to raise_error StandardError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "an error is added to env['rack.exception']" do
|
52
|
+
before do
|
53
|
+
env['rack.exception'] = "I am a sad sad exception"
|
54
|
+
app.stub(:call).with(env).and_return response
|
55
|
+
act
|
56
|
+
end
|
57
|
+
it 'should have logged the error' do
|
58
|
+
logger.logs.count.should eq 1
|
59
|
+
last_msg.should eq env['rack.exception']
|
60
|
+
end
|
61
|
+
specify { @returned_response.should_not be_nil }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
ENV["RAILS_ENV"] ||= 'test'
|
2
|
+
|
3
|
+
require 'logging_elf'
|
4
|
+
support_files = Dir[File.join(
|
5
|
+
File.expand_path("../../spec/support/**/*.rb", __FILE__)
|
6
|
+
)]
|
7
|
+
support_files.each { |f| require f }
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
config.run_all_when_everything_filtered = true
|
12
|
+
config.filter_run :focus
|
13
|
+
config.order = :random
|
14
|
+
|
15
|
+
config.before(:each) do
|
16
|
+
LoggingElf.config = nil
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logging_elf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Deville
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: logging
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: virtus
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activemodel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: gelf
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.6'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.6'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.0'
|
111
|
+
description: Logging, Tracing, and Gelf Logging for rails
|
112
|
+
email:
|
113
|
+
- jeffdeville@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .rspec
|
120
|
+
- .travis.yml
|
121
|
+
- Gemfile
|
122
|
+
- Guardfile
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- lib/logging_elf.rb
|
127
|
+
- lib/logging_elf/config.rb
|
128
|
+
- lib/logging_elf/gelf_appender.rb
|
129
|
+
- lib/logging_elf/gelf_data.rb
|
130
|
+
- lib/logging_elf/lograge_formatter.rb
|
131
|
+
- lib/logging_elf/tracing_logger.rb
|
132
|
+
- lib/logging_elf/uncaught_exceptions_middleware.rb
|
133
|
+
- lib/logging_elf/version.rb
|
134
|
+
- logging_elf.gemspec
|
135
|
+
- spec/integrations/entire_flow_spec.rb
|
136
|
+
- spec/logging_elf/gelf_data_spec.rb
|
137
|
+
- spec/logging_elf/tracing_logger_spec.rb
|
138
|
+
- spec/logging_elf/uncaught_exceptions_middleware_spec.rb
|
139
|
+
- spec/spec_helper.rb
|
140
|
+
- spec/support/config.rb
|
141
|
+
- spec/support/fake_logger.rb
|
142
|
+
homepage: ''
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
metadata: {}
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - '>='
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 2.0.14
|
163
|
+
signing_key:
|
164
|
+
specification_version: 4
|
165
|
+
summary: Logging, Tracing, and Gelf Logging for rails
|
166
|
+
test_files:
|
167
|
+
- spec/integrations/entire_flow_spec.rb
|
168
|
+
- spec/logging_elf/gelf_data_spec.rb
|
169
|
+
- spec/logging_elf/tracing_logger_spec.rb
|
170
|
+
- spec/logging_elf/uncaught_exceptions_middleware_spec.rb
|
171
|
+
- spec/spec_helper.rb
|
172
|
+
- spec/support/config.rb
|
173
|
+
- spec/support/fake_logger.rb
|
174
|
+
has_rdoc:
|