scrolls 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -0
- data/README.md +31 -103
- data/docs/syslog.md +17 -0
- data/lib/scrolls/log.rb +36 -13
- data/lib/scrolls/version.rb +1 -1
- data/lib/scrolls.rb +22 -0
- data/test/test_scrolls.rb +10 -0
- metadata +3 -2
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
# Scrolls
|
2
2
|
|
3
|
-
Scrolls is a
|
4
|
-
key=value structure. It's in use at Heroku where we use the event data
|
5
|
-
to drive metrics and monitoring services.
|
6
|
-
|
7
|
-
Scrolls is rather opinionated.
|
3
|
+
Scrolls is a library for generating logs of the structure `key=value`.
|
8
4
|
|
9
5
|
## Installation
|
10
6
|
|
@@ -20,115 +16,47 @@ Or install it yourself as:
|
|
20
16
|
|
21
17
|
$ gem install scrolls
|
22
18
|
|
23
|
-
##
|
24
|
-
|
25
|
-
At Heroku we are big believers in "logs as data". We log everything so
|
26
|
-
that we can act upon that event stream of logs. Internally we use logs
|
27
|
-
to produce metrics and monitoring data that we can alert on.
|
28
|
-
|
29
|
-
Here's an example of a log you might specify in your application:
|
30
|
-
|
31
|
-
```ruby
|
32
|
-
Scrolls.log(fn: "trap", signal: s, at: "exit", status: 0)
|
33
|
-
```
|
34
|
-
|
35
|
-
The output of which might be:
|
36
|
-
|
37
|
-
fn=trap signal=TERM at=exit status=0
|
38
|
-
|
39
|
-
This provides a rich set of data that we can parse and act upon.
|
19
|
+
## Philosophy
|
40
20
|
|
41
|
-
|
42
|
-
context. One is 'global_context' that prepends every log in your
|
43
|
-
application with that data and a local 'context' which can be used,
|
44
|
-
for example, to wrap requests with a request id.
|
21
|
+
Scrolls follows the belief that logs should be treated as data. One way to think of them is the blood of your infrastructure. Logs are a realtime view of what is happening on your systems.
|
45
22
|
|
46
|
-
|
47
|
-
to provide more context we might set a global context that links this
|
48
|
-
log data to our application and deployment:
|
23
|
+
## Documentation:
|
49
24
|
|
50
|
-
|
51
|
-
Scrolls.global_context(app: "myapp", deploy: ENV["DEPLOY"])
|
52
|
-
```
|
53
|
-
|
54
|
-
This would change our log output above to:
|
25
|
+
I apologize, some of these are a WIP.
|
55
26
|
|
56
|
-
|
27
|
+
* [Sending logs to syslog using Scrolls](https://github.com/asenchi/scrolls/tree/master/docs/syslog.md)
|
28
|
+
* Logging contexts
|
29
|
+
* Adding timestamps by default
|
30
|
+
* Misc Features
|
57
31
|
|
58
|
-
|
32
|
+
## Usage
|
59
33
|
|
60
34
|
```ruby
|
61
|
-
|
62
|
-
```
|
35
|
+
require 'scrolls'
|
63
36
|
|
37
|
+
Scrolls.add_timestamp = true
|
38
|
+
Scrolls.global_context(:app => "scrolls", :deploy => ENV["DEPLOY"])
|
64
39
|
|
65
|
-
|
66
|
-
we might also do something similar to:
|
40
|
+
Scrolls.log(:at => "test")
|
67
41
|
|
68
|
-
|
69
|
-
Scrolls.
|
70
|
-
Scrolls.log(fn: "trap", signal: s, at: "exit", status: 0)
|
42
|
+
Scrolls.context(:context => "block") do
|
43
|
+
Scrolls.log(:at => "exec")
|
71
44
|
end
|
72
|
-
```
|
73
|
-
|
74
|
-
This would be the output (taking into consideration our global context
|
75
|
-
above):
|
76
|
-
|
77
|
-
app=myapp deploy=production ns=server fn=trap signal=TERM at=exit status=0
|
78
|
-
|
79
|
-
This allows us to track this log to `Server#trap` and we received a
|
80
|
-
'TERM' signal and exited 0.
|
81
45
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
* `ns`: Namespace (Class, Module or files)
|
88
|
-
* `fn`: Function
|
89
|
-
* `at`: Execution point
|
90
|
-
* `deploy`: Our deployment (typically an environment variable i.e. `DEPLOY=staging`)
|
91
|
-
* `elapsed`: Measurements (Time)
|
92
|
-
* `count`: Measurements (Counters)
|
93
|
-
|
94
|
-
Scrolls makes it easy to measure the run time of a portion of code.
|
95
|
-
For example:
|
96
|
-
|
97
|
-
```ruby
|
98
|
-
Scrolls.log(fn: "test") do
|
99
|
-
Scrolls.log(status: "exec")
|
100
|
-
# Code here
|
101
|
-
end
|
102
|
-
```
|
103
|
-
|
104
|
-
This will output the following log:
|
105
|
-
|
106
|
-
fn=test at=start
|
107
|
-
status=exec
|
108
|
-
fn=test at=finish elapsed=0.300
|
109
|
-
|
110
|
-
You can change the time unit that Scrolls uses to "milliseconds" (the
|
111
|
-
default is "seconds"):
|
112
|
-
|
113
|
-
```ruby
|
114
|
-
Scrolls.time_unit = "ms"
|
46
|
+
begin
|
47
|
+
raise
|
48
|
+
rescue Exception => e
|
49
|
+
Scrolls.log_exception(:at => "raise", e)
|
50
|
+
end
|
115
51
|
```
|
116
52
|
|
117
|
-
|
118
|
-
a look at some of the ways Scrolls handles certain values.
|
119
|
-
|
120
|
-
Time and nil:
|
53
|
+
Produces:
|
121
54
|
|
122
|
-
```ruby
|
123
|
-
Scrolls.log(t: Time.at(1340118167), this: nil)
|
124
|
-
t=2012-06-19T11:02:47-0400 this=nil
|
125
55
|
```
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
Scrolls.log(that: false, this: true)
|
131
|
-
that=false this=true
|
56
|
+
now="2014-01-17T16:11:39Z" app=scrolls deploy=nil at=test
|
57
|
+
now="2014-01-17T16:11:39Z" app=scrolls deploy=nil context=block at=exec
|
58
|
+
now="2014-01-17T16:11:39Z" app=scrolls deploy=nil at=exception class=RuntimeError message= exception_id=70312608019740
|
59
|
+
now="2014-01-17T16:11:39Z" app=scrolls deploy=nil at=exception class= exception_id=70312608019740 site="./test.rb:16:in <main>"
|
132
60
|
```
|
133
61
|
|
134
62
|
## History
|
@@ -138,14 +66,14 @@ at Heroku. Starting at version 0.2.0 Scrolls was ripped apart and
|
|
138
66
|
restructured to provide a better foundation for the future. Tests and
|
139
67
|
documentation were add at that point as well.
|
140
68
|
|
141
|
-
|
142
|
-
|
143
|
-
Most of the ideas used in Scrolls are those of other engineers at
|
144
|
-
Heroku, I simply ripped them off to create a single library. Huge
|
145
|
-
thanks to:
|
69
|
+
Thanks to the following people for influencing this library.
|
146
70
|
|
147
71
|
* Mark McGranaghan
|
148
72
|
* Noah Zoschke
|
149
73
|
* Mark Fine
|
150
74
|
* Fabio Kung
|
151
75
|
* Ryan Smith
|
76
|
+
|
77
|
+
## LICENSE
|
78
|
+
|
79
|
+
MIT License
|
data/docs/syslog.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
## Scrolls: Sending data to syslog
|
2
|
+
|
3
|
+
By default Scrolls writes log messages to `STDOUT`. With the release of [v0.2.8](https://github.com/asenchi/scrolls/releases/tag/v0.2.8) it is now possible to write to the local system logger. To do so, set `#stream` to "syslog":
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
Scrolls.stream = "syslog"
|
7
|
+
```
|
8
|
+
|
9
|
+
This defaults to syslog facility USER and log level ERROR. You can adjust the log facility like so:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
Scrolls.facility = "local7"
|
13
|
+
```
|
14
|
+
|
15
|
+
Scrolls generally doesn't care about log levels. The library defaults to ERROR (or 3), but ultimately is of the opinion that levels are useless. The reasoning behind this is that applications should log useful data, all of the time. Debugging data is great for development, but should never be deployed. The richness of structured logging allows exceptions and error messages to sit along side the context of the data in which the error was thrown, there is no need to send to an "emergency" level.
|
16
|
+
|
17
|
+
With that said, if one wanted to adjust the log level, you can set an environment variable `LOG_LEVEL`. This allows this particular feature to be rather fluid throughout your application.
|
data/lib/scrolls/log.rb
CHANGED
@@ -85,6 +85,14 @@ module Scrolls
|
|
85
85
|
@add_timestamp || false
|
86
86
|
end
|
87
87
|
|
88
|
+
def single_line_exceptions=(b)
|
89
|
+
@single_line_exceptions = !!b
|
90
|
+
end
|
91
|
+
|
92
|
+
def single_line_exceptions?
|
93
|
+
@single_line_exceptions || false
|
94
|
+
end
|
95
|
+
|
88
96
|
def log(data, &blk)
|
89
97
|
# If we get a string lets bring it into our structure.
|
90
98
|
if data.kind_of? String
|
@@ -141,20 +149,35 @@ module Scrolls
|
|
141
149
|
logdata = gc.merge(rawhash)
|
142
150
|
end
|
143
151
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
152
|
+
excepdata = {
|
153
|
+
:at => "exception",
|
154
|
+
:class => e.class,
|
155
|
+
:message => e.message,
|
156
|
+
:exception_id => e.object_id.abs
|
157
|
+
}
|
158
|
+
|
150
159
|
if e.backtrace
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
160
|
+
if single_line_exceptions?
|
161
|
+
btlines = []
|
162
|
+
e.backtrace.each do |line|
|
163
|
+
btlines << line.gsub(/[`'"]/, "")
|
164
|
+
end
|
165
|
+
|
166
|
+
if btlines.length > 0
|
167
|
+
squish = { :site => btlines.join('\n') }
|
168
|
+
log(logdata.merge(excepdata.merge(squish)))
|
169
|
+
end
|
170
|
+
else
|
171
|
+
log(logdata.merge(excepdata))
|
172
|
+
|
173
|
+
e.backtrace.each do |line|
|
174
|
+
log(logdata.merge(excepdata).merge(
|
175
|
+
:at => "exception",
|
176
|
+
:class => e.class,
|
177
|
+
:exception_id => e.object_id.abs,
|
178
|
+
:site => line.gsub(/[`'"]/, "")
|
179
|
+
))
|
180
|
+
end
|
158
181
|
end
|
159
182
|
end
|
160
183
|
end
|
data/lib/scrolls/version.rb
CHANGED
data/lib/scrolls.rb
CHANGED
@@ -169,4 +169,26 @@ module Scrolls
|
|
169
169
|
Log.add_timestamp
|
170
170
|
end
|
171
171
|
|
172
|
+
# Public: Set whether exceptions should generate a single log
|
173
|
+
# message. (default: false)
|
174
|
+
#
|
175
|
+
# Examples
|
176
|
+
#
|
177
|
+
# Scrolls.single_line_exceptions = true
|
178
|
+
#
|
179
|
+
def single_line_exceptions=(boolean)
|
180
|
+
Log.single_line_exceptions = boolean
|
181
|
+
end
|
182
|
+
|
183
|
+
# Public: Return whether exceptions generate a single log message.
|
184
|
+
#
|
185
|
+
# Examples
|
186
|
+
#
|
187
|
+
# Scrolls.single_line_exceptions
|
188
|
+
# => true
|
189
|
+
#
|
190
|
+
def single_line_exceptions?
|
191
|
+
Log.single_line_exceptions
|
192
|
+
end
|
193
|
+
|
172
194
|
end
|
data/test/test_scrolls.rb
CHANGED
@@ -133,6 +133,16 @@ class TestScrolls < Test::Unit::TestCase
|
|
133
133
|
oneline_backtrace
|
134
134
|
end
|
135
135
|
|
136
|
+
def test_single_line_exceptions
|
137
|
+
Scrolls.single_line_exceptions = true
|
138
|
+
begin
|
139
|
+
raise Exception
|
140
|
+
rescue Exception => e
|
141
|
+
Scrolls.log_exception({:o => "o"}, e)
|
142
|
+
end
|
143
|
+
assert_equal 1, @out.string.scan(/.*site=.*/).size
|
144
|
+
end
|
145
|
+
|
136
146
|
def test_syslog_integration
|
137
147
|
Scrolls.stream = 'syslog'
|
138
148
|
assert_equal Scrolls::SyslogLogger, Scrolls.stream.class
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scrolls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-01-
|
12
|
+
date: 2014-01-23 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Logging, easier, more consistent.
|
15
15
|
email:
|
@@ -23,6 +23,7 @@ files:
|
|
23
23
|
- LICENSE
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
|
+
- docs/syslog.md
|
26
27
|
- lib/scrolls.rb
|
27
28
|
- lib/scrolls/atomic.rb
|
28
29
|
- lib/scrolls/log.rb
|