transaction_logger 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 +14 -0
- data/.yardopts +10 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/LICENSE.txt +22 -0
- data/README.md +108 -0
- data/Rakefile +2 -0
- data/lib/transaction_logger/transaction.rb +131 -0
- data/lib/transaction_logger/version.rb +3 -0
- data/lib/transaction_logger.rb +85 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/debugging.rb +1 -0
- data/spec/transaction_logger_spec.rb +248 -0
- data/transaction_logger.gemspec +34 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 544d8e3034117695aa67e4d1fa207bb87e060dcf
|
4
|
+
data.tar.gz: bb1e5adbb2abfa94408b9c91fe5e401ec742affb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 18e1641a904647a7385544cf2077d38e547d876b5a517a858f685d711e43bcf6b76db33aabb41089bec3c27f0a7c29b89193c061914cf3c05da85bb35877d98d
|
7
|
+
data.tar.gz: d58c1a65794727de53cf7e03fd94acfc3a75c9f2f38f047e0fd9a3cff3bcc45ab5229923efdf1d3f4b2a04988c5ccd7415e83dbf573a9c164f5f208732c1e18e
|
data/.gitignore
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Blinkist
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Sebastian Schleicher
|
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,108 @@
|
|
1
|
+
# Blinkist TransactionLogger
|
2
|
+
[ ](https://codeship.com/projects/84119) [](https://codeclimate.com/github/blinkist/transaction_logger)
|
3
|
+
|
4
|
+
Business Transactions Logger for Ruby that compiles contextual logging information and can send it to a configured logging service such as Logger or Loggly in a nested hash.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "transaction_logger"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install transaction_logger
|
21
|
+
|
22
|
+
## Output
|
23
|
+
|
24
|
+
Given a root transaction, the TransactionLogger is expected to print out every log that occurred under this root transaction, and each sub-transaction's local information.
|
25
|
+
|
26
|
+
When a transaction raises an error, it will log the *error message*, *error class*, and *10 lines* of the backtrace by default. This will be logged at the level of the transaction that raised the error.
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
Configure the logger by calling TransactionLogger.logger, such as with Ruby's Logger:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
logger = Logger.new STDOUT # Ruby default logger setup
|
34
|
+
TransactionLogger.logger = logger
|
35
|
+
```
|
36
|
+
|
37
|
+
Wrap a business transaction method with a TransactionLogger lambda:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
def some_method
|
41
|
+
TransactionLogger.start -> (t) do
|
42
|
+
# your code.
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
From within this lambda, you may call upon t to add a custom name, context and log your messages, like so:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
t.name = "YourClass.some_method"
|
51
|
+
t.context = { specific: "context: #{value}" }
|
52
|
+
t.log "A message you want logged"
|
53
|
+
```
|
54
|
+
|
55
|
+
### Example
|
56
|
+
|
57
|
+
Here is a transaction that raises an error:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
class ExampleClass
|
61
|
+
def some_method
|
62
|
+
TransactionLogger.start -> (t) do
|
63
|
+
t.name = "ExampleClass.some_method"
|
64
|
+
t.context = { some_id: 12 }
|
65
|
+
|
66
|
+
t.log "Trying something complex"
|
67
|
+
raise RuntimeError, "Error"
|
68
|
+
|
69
|
+
result
|
70
|
+
t.log "Success"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
The expected output is:
|
77
|
+
|
78
|
+
```json
|
79
|
+
{
|
80
|
+
"transaction_name": "ExampleClass.some_method",
|
81
|
+
"transaction_context": {
|
82
|
+
"some_id": 12
|
83
|
+
},
|
84
|
+
"transaction_duration": 0.112,
|
85
|
+
"transaction_history": [{
|
86
|
+
"transaction_info": "Trying something complex"
|
87
|
+
}, {
|
88
|
+
"transaction_error_message": "Error",
|
89
|
+
"transaction_error_class": "RuntimeError",
|
90
|
+
"transaction_error_backtrace": [
|
91
|
+
"example.rb:84:in `block in nested_method'",
|
92
|
+
".../TransactionLogger_Example/transaction_logger.rb:26:in `call'",
|
93
|
+
".../TransactionLogger_Example/transaction_logger.rb:26:in `run'",
|
94
|
+
".../TransactionLogger_Example/transaction_logger.rb:111:in `start'",
|
95
|
+
"example.rb:79:in `nested_method'"
|
96
|
+
]
|
97
|
+
|
98
|
+
}]
|
99
|
+
}
|
100
|
+
```
|
101
|
+
|
102
|
+
## Contributing
|
103
|
+
|
104
|
+
1. Fork it ( https://github.com/blinkist/transaction_logger/fork )
|
105
|
+
2. Create your feature branch (`git checkout -b feature/your_feature`)
|
106
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
107
|
+
4. Push to the branch (`git push origin feature/your_feature`)
|
108
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
|
2
|
+
class TransactionLogger::Transaction
|
3
|
+
attr_reader :parent
|
4
|
+
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :context
|
7
|
+
|
8
|
+
# @param parent [TransactionLogger::Transaction] Parent of transaction
|
9
|
+
# @param lmbda [Proc] The surrounded block
|
10
|
+
#
|
11
|
+
def initialize(parent=nil, lmbda)
|
12
|
+
@parent = parent
|
13
|
+
@parent.log self if @parent
|
14
|
+
|
15
|
+
@lmbda = lmbda
|
16
|
+
|
17
|
+
@name = "undefined"
|
18
|
+
@context = {}
|
19
|
+
@log_queue = Array.new
|
20
|
+
@start = Time.now
|
21
|
+
@error_printed = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# @private
|
25
|
+
# Runs the lines of code from within the lambda. FOR INTERNAL USE ONLY.
|
26
|
+
#
|
27
|
+
def run
|
28
|
+
begin
|
29
|
+
result = @lmbda.call self
|
30
|
+
rescue => error
|
31
|
+
|
32
|
+
e_message_key = "#{TransactionLogger.log_prefix}error_message"
|
33
|
+
e_class_key = "#{TransactionLogger.log_prefix}error_class"
|
34
|
+
e_backtrace_key = "#{TransactionLogger.log_prefix}error_backtrace"
|
35
|
+
|
36
|
+
log({
|
37
|
+
e_message_key => error.message,
|
38
|
+
e_class_key => error.class.name,
|
39
|
+
e_backtrace_key => error.backtrace.take(5)
|
40
|
+
})
|
41
|
+
|
42
|
+
failure error, self
|
43
|
+
else
|
44
|
+
success
|
45
|
+
end
|
46
|
+
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
# Pushes a message into the log queue. Logs are stored in order
|
51
|
+
# of time logged. Note that this method will not output a log, but just
|
52
|
+
# stores it in the queue to be outputted if an error is raised in a
|
53
|
+
# transaction.
|
54
|
+
#
|
55
|
+
# @param message [#to_s] Any String or Object that responds to to_s
|
56
|
+
# that you want to be stored in the log queue.
|
57
|
+
#
|
58
|
+
def log(message)
|
59
|
+
if message.is_a? String
|
60
|
+
message_key = "#{TransactionLogger.log_prefix}info"
|
61
|
+
message = { message_key => message }
|
62
|
+
@log_queue.push message
|
63
|
+
else
|
64
|
+
@log_queue.push message
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @private
|
69
|
+
# Logs the error and raises error to the parent process
|
70
|
+
def failure(error, transaction)
|
71
|
+
calc_duration
|
72
|
+
|
73
|
+
if @parent
|
74
|
+
@parent.failure error, transaction
|
75
|
+
else
|
76
|
+
unless @error_printed
|
77
|
+
print_transactions
|
78
|
+
@error_printed = true
|
79
|
+
end
|
80
|
+
|
81
|
+
raise error
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @private
|
86
|
+
# Converts a Transaction and it's children into a single nested hash
|
87
|
+
def to_hash
|
88
|
+
name_key = "#{TransactionLogger.log_prefix}name"
|
89
|
+
context_key = "#{TransactionLogger.log_prefix}context"
|
90
|
+
duration_key = "#{TransactionLogger.log_prefix}duration"
|
91
|
+
history_key = "#{TransactionLogger.log_prefix}history"
|
92
|
+
|
93
|
+
output = {
|
94
|
+
name_key => @name,
|
95
|
+
context_key => @context,
|
96
|
+
duration_key => @duration,
|
97
|
+
history_key => []
|
98
|
+
}
|
99
|
+
|
100
|
+
@log_queue.each {|entry|
|
101
|
+
if entry.is_a? TransactionLogger::Transaction
|
102
|
+
output[history_key] << entry.to_hash
|
103
|
+
elsif entry.is_a? Hash
|
104
|
+
output[history_key] << entry
|
105
|
+
else
|
106
|
+
output[history_key] << entry
|
107
|
+
end
|
108
|
+
}
|
109
|
+
|
110
|
+
output
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# Calculates the duration upon the success of a transaction
|
117
|
+
def success
|
118
|
+
calc_duration
|
119
|
+
end
|
120
|
+
|
121
|
+
# Calculates the number of milliseconds that the Transaction has taken
|
122
|
+
def calc_duration
|
123
|
+
@duration = (Time.now - @start) * 1000.0
|
124
|
+
end
|
125
|
+
|
126
|
+
# Sends the transaction context and log to an instance of logger
|
127
|
+
def print_transactions(transaction=nil)
|
128
|
+
TransactionLogger.logger.error to_hash
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "transaction_logger/version"
|
2
|
+
require "transaction_logger/transaction"
|
3
|
+
|
4
|
+
class TransactionLogger
|
5
|
+
|
6
|
+
@@prefix = ""
|
7
|
+
@@current_transactions = {}
|
8
|
+
|
9
|
+
# Marks the beginning of a "Transaction lambda," which will log an error if the
|
10
|
+
# containing code raises an error. A lambda instance variable let's you call
|
11
|
+
# the .log method and access the ".name" and ".context" variables. The start
|
12
|
+
# method must take a lambda as an argument.
|
13
|
+
#
|
14
|
+
# Whatever the outer method is, if a value is returned within the Transaction
|
15
|
+
# lambda it will be returned to the outer method as well.
|
16
|
+
#
|
17
|
+
# The start method does not catch errors, so if an error is raised, it will simply
|
18
|
+
# envoke a logging message to be outputted and then raise the error.
|
19
|
+
#
|
20
|
+
# This also checks which thread is envoking the method in order to make sure the
|
21
|
+
# logs are thread-safe.
|
22
|
+
#
|
23
|
+
# @param lmbda [Proc]
|
24
|
+
#
|
25
|
+
def self.start(lmbda)
|
26
|
+
|
27
|
+
active_transaction = get_active_transaction
|
28
|
+
|
29
|
+
transaction = TransactionLogger::Transaction.new active_transaction, lmbda
|
30
|
+
active_transaction = transaction
|
31
|
+
|
32
|
+
set_active_transaction active_transaction
|
33
|
+
|
34
|
+
begin
|
35
|
+
transaction.run
|
36
|
+
rescue Exception => e
|
37
|
+
raise e
|
38
|
+
ensure
|
39
|
+
set_active_transaction transaction.parent
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sets the TransactionLogger's output to a specific instance of Logger.
|
44
|
+
#
|
45
|
+
# @param logger [Logger] Any instace of ruby Logger
|
46
|
+
#
|
47
|
+
def self.logger=(logger)
|
48
|
+
@@logger = logger
|
49
|
+
end
|
50
|
+
|
51
|
+
# Sets the TransactionLogger's output to a new instance of Logger
|
52
|
+
#
|
53
|
+
def self.logger
|
54
|
+
@@logger ||= Logger.new(STDOUT)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
#
|
59
|
+
def self.log_prefix=(prefix)
|
60
|
+
@@prefix = "#{prefix}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.log_prefix
|
64
|
+
@@prefix
|
65
|
+
end
|
66
|
+
|
67
|
+
# @private
|
68
|
+
# Returns the current parent of a thread of Transactions.
|
69
|
+
#
|
70
|
+
# @return [TransactionLogger::Transaction] The current parent given a Thread
|
71
|
+
#
|
72
|
+
def self.get_active_transaction
|
73
|
+
if @@current_transactions.has_key?(Thread.current.object_id)
|
74
|
+
@@current_transactions[Thread.current.object_id]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @private
|
79
|
+
# Sets the current parent of a thread of Transactions.
|
80
|
+
#
|
81
|
+
def self.set_active_transaction(transaction)
|
82
|
+
@@current_transactions[Thread.current.object_id] = transaction
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "byebug"
|
@@ -0,0 +1,248 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "logger"
|
3
|
+
|
4
|
+
describe TransactionLogger do
|
5
|
+
|
6
|
+
let (:test_lmbda) {
|
7
|
+
-> (t) do
|
8
|
+
end
|
9
|
+
}
|
10
|
+
|
11
|
+
subject { TransactionLogger::Transaction.new nil, test_lmbda }
|
12
|
+
|
13
|
+
it "initializes with a nil parent" do
|
14
|
+
expect(subject.parent).to be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it "responds to .start" do
|
18
|
+
expect(described_class).to receive(:start)
|
19
|
+
described_class.start -> (t) do end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when there is a parent" do
|
23
|
+
|
24
|
+
let (:test_parent) { subject }
|
25
|
+
let (:child) { child = TransactionLogger::Transaction.new test_parent, test_lmbda }
|
26
|
+
let (:test_parent_log_queue) { test_parent.instance_variable_get(:@log_queue) }
|
27
|
+
|
28
|
+
it "has a parent" do
|
29
|
+
expect(child).to have_attributes(:parent => test_parent)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "places itself into the log of the parent" do
|
33
|
+
expect(test_parent_log_queue).to include(child)
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when there is an error" do
|
37
|
+
|
38
|
+
it "raises the error to the parent" do
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when in 3-level nested transactions" do
|
47
|
+
it "raises an error" do
|
48
|
+
expect {
|
49
|
+
described_class.start -> (t) do
|
50
|
+
t.context = {user_id: 01, information: "contextual info"}
|
51
|
+
t.log "First Message"
|
52
|
+
|
53
|
+
described_class.start -> (t2) do
|
54
|
+
t2.context = {user_id: 01, information: "contextual info"}
|
55
|
+
t2.log "Second Message"
|
56
|
+
t2.log "Third Message"
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
t.log "Fourth Message"
|
61
|
+
|
62
|
+
described_class.start -> (t3) do
|
63
|
+
t3.context = {user_id: 01, information: "contextual info"}
|
64
|
+
t3.log "Fifth Message"
|
65
|
+
|
66
|
+
described_class.start -> (t4) do
|
67
|
+
t4.context = {user_id: 01, information: "contextual info"}
|
68
|
+
t4.log "Sixth Message"
|
69
|
+
t4.log "Seventh Message"
|
70
|
+
|
71
|
+
fail RuntimeError, "test error"
|
72
|
+
end
|
73
|
+
|
74
|
+
t3.log "Eighth Message"
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
}.to raise_error RuntimeError
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe ".start" do
|
83
|
+
let (:test_lmbda) {
|
84
|
+
described_class.start -> (t) do
|
85
|
+
t.log ""
|
86
|
+
end
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
describe ".log_prefix" do
|
91
|
+
|
92
|
+
context "when there is no prefix" do
|
93
|
+
it "does not change the output" do
|
94
|
+
expect(subject.to_hash).to include("name" => "undefined")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when a prefix is defined" do
|
99
|
+
let (:prefix) { "bta_" }
|
100
|
+
|
101
|
+
before :example do
|
102
|
+
described_class.log_prefix = prefix
|
103
|
+
end
|
104
|
+
|
105
|
+
after :example do
|
106
|
+
described_class.log_prefix = ""
|
107
|
+
end
|
108
|
+
|
109
|
+
it "adds the prefix to every key" do
|
110
|
+
expect(subject.to_hash).to include("bta_name" => "undefined")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "#run" do
|
117
|
+
|
118
|
+
context "when no exception is raised" do
|
119
|
+
|
120
|
+
let (:test_lmbda) {
|
121
|
+
-> (t) do
|
122
|
+
"result"
|
123
|
+
end
|
124
|
+
}
|
125
|
+
|
126
|
+
let (:result) { subject.run }
|
127
|
+
|
128
|
+
it "returns lmda" do
|
129
|
+
expect(result).to eq "result"
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when an exception is raised" do
|
135
|
+
|
136
|
+
let (:test_lmbda) {
|
137
|
+
-> (t) do
|
138
|
+
fail RuntimeError, "test error"
|
139
|
+
end
|
140
|
+
}
|
141
|
+
|
142
|
+
let (:result) { subject.run }
|
143
|
+
|
144
|
+
it "raises an exception" do
|
145
|
+
expect{result}.to raise_error "test error"
|
146
|
+
end
|
147
|
+
|
148
|
+
it "calls failure" do
|
149
|
+
expect(subject).to receive(:failure)
|
150
|
+
result
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
# Try to think of ways to refactor this
|
158
|
+
# given that I can test certain specific behaviors
|
159
|
+
# first, and then use those tests to know the bigger
|
160
|
+
# picture is working...
|
161
|
+
describe "Logger" do
|
162
|
+
|
163
|
+
subject {
|
164
|
+
Logger.new STDOUT
|
165
|
+
}
|
166
|
+
|
167
|
+
before :each do
|
168
|
+
described_class.logger = subject
|
169
|
+
end
|
170
|
+
|
171
|
+
context "when there is one transaction" do
|
172
|
+
|
173
|
+
it "recieves nothing" do
|
174
|
+
expect(subject).to_not receive(:error)
|
175
|
+
|
176
|
+
described_class.start -> (t) do
|
177
|
+
t.context = {user_id: 01, information: "contextual info"}
|
178
|
+
t.log "First Message"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it "recieves error if an exception occurs" do
|
183
|
+
expect(subject).to receive(:error)
|
184
|
+
expect {
|
185
|
+
described_class.start -> (t) do
|
186
|
+
t.context = {user_id: 01, information: "contextual info"}
|
187
|
+
t.log "First Message"
|
188
|
+
fail RuntimeError, "test error"
|
189
|
+
end
|
190
|
+
}.to raise_error(RuntimeError)
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
context "when there is a nested transaction with two levels" do
|
196
|
+
|
197
|
+
it "recieves error if an exception occurs" do
|
198
|
+
expect(subject).to receive(:error) do |options|
|
199
|
+
expect(options["history"]).to include( {"info" => "First Message"} )
|
200
|
+
expect(options["history"].last["history"]).to include({"info" => "Second Message"})
|
201
|
+
expect(options["history"].last["history"].last["error_message"]).to eq("test error")
|
202
|
+
expect(options["history"].last["history"].last["error_class"]).to eq("RuntimeError")
|
203
|
+
end
|
204
|
+
|
205
|
+
expect {
|
206
|
+
described_class.start -> (t) do
|
207
|
+
t.context = {user_id: 01, information: "contextual info"}
|
208
|
+
t.log "First Message"
|
209
|
+
described_class.start -> (t2) do
|
210
|
+
t2.log "Second Message"
|
211
|
+
fail RuntimeError, "test error"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
}.to raise_error RuntimeError
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
context "when there are two nested transactions, two-levels deep" do
|
220
|
+
|
221
|
+
it "recieves error if an exception occurs" do
|
222
|
+
|
223
|
+
expect(subject).to receive("error") do |options|
|
224
|
+
expect(options["history"].first["history"]).to include({"info" => "First Message"})
|
225
|
+
expect(options["history"].last["history"]).to include({"info" => "Second Message"})
|
226
|
+
expect(options["history"].last["history"].last["error_message"]).to eq("test error")
|
227
|
+
expect(options["history"].last["history"].last["error_class"]).to eq("RuntimeError")
|
228
|
+
end
|
229
|
+
|
230
|
+
expect {
|
231
|
+
described_class.start -> (t) do
|
232
|
+
t.context = {user_id: 01, information: "contextual info"}
|
233
|
+
described_class.start -> (t2) do
|
234
|
+
t2.log "First Message"
|
235
|
+
end
|
236
|
+
described_class.start -> (t2) do
|
237
|
+
t2.log "Second Message"
|
238
|
+
fail RuntimeError, "test error"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
}.to raise_error RuntimeError
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'transaction_logger/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "transaction_logger"
|
8
|
+
spec.version = TransactionLogger::VERSION
|
9
|
+
spec.authors = ["John Donner", "Sebastian Schleicher"]
|
10
|
+
spec.email = ["johnbdonner@gmail.com", "sebastian.julius@gmail.com"]
|
11
|
+
spec.summary = %q{Contextual Business Transaction Logger for Ruby}
|
12
|
+
spec.description = %q{A logger that silently collects information in the \
|
13
|
+
background and when an error is raised, logs a hash either \
|
14
|
+
out to the System or pushes the log to a service such as \
|
15
|
+
Loggly. The log hash contains information such as the \
|
16
|
+
backtrace, any logs from calling classes and methods, \
|
17
|
+
and configurable contextual information.}
|
18
|
+
spec.homepage = "https://github.com/blinkist/transaction_logger"
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0")
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
spec.required_ruby_version = Gem::Requirement.new ">= 2.1.0"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
28
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.2.0"
|
30
|
+
spec.add_development_dependency "byebug"
|
31
|
+
spec.add_development_dependency "yard"
|
32
|
+
spec.add_development_dependency "redcarpet"
|
33
|
+
spec.add_development_dependency "github-markdown"
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: transaction_logger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Donner
|
8
|
+
- Sebastian Schleicher
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-07-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.7'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.7'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '10.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '10.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 3.2.0
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 3.2.0
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: byebug
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: yard
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: redcarpet
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: github-markdown
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
description: |-
|
113
|
+
A logger that silently collects information in the \
|
114
|
+
background and when an error is raised, logs a hash either \
|
115
|
+
out to the System or pushes the log to a service such as \
|
116
|
+
Loggly. The log hash contains information such as the \
|
117
|
+
backtrace, any logs from calling classes and methods, \
|
118
|
+
and configurable contextual information.
|
119
|
+
email:
|
120
|
+
- johnbdonner@gmail.com
|
121
|
+
- sebastian.julius@gmail.com
|
122
|
+
executables: []
|
123
|
+
extensions: []
|
124
|
+
extra_rdoc_files: []
|
125
|
+
files:
|
126
|
+
- ".gitignore"
|
127
|
+
- ".yardopts"
|
128
|
+
- Gemfile
|
129
|
+
- LICENSE
|
130
|
+
- LICENSE.txt
|
131
|
+
- README.md
|
132
|
+
- Rakefile
|
133
|
+
- lib/transaction_logger.rb
|
134
|
+
- lib/transaction_logger/transaction.rb
|
135
|
+
- lib/transaction_logger/version.rb
|
136
|
+
- spec/spec_helper.rb
|
137
|
+
- spec/support/debugging.rb
|
138
|
+
- spec/transaction_logger_spec.rb
|
139
|
+
- transaction_logger.gemspec
|
140
|
+
homepage: https://github.com/blinkist/transaction_logger
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
metadata: {}
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 2.1.0
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
requirements: []
|
159
|
+
rubyforge_project:
|
160
|
+
rubygems_version: 2.4.5
|
161
|
+
signing_key:
|
162
|
+
specification_version: 4
|
163
|
+
summary: Contextual Business Transaction Logger for Ruby
|
164
|
+
test_files:
|
165
|
+
- spec/spec_helper.rb
|
166
|
+
- spec/support/debugging.rb
|
167
|
+
- spec/transaction_logger_spec.rb
|
168
|
+
has_rdoc:
|