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 CHANGED
@@ -1,5 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
+ Copyright © Curt Micol <asenchi@asenchi.com> 2012,2013,2014
3
4
  Copyright © Heroku 2012
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining
data/README.md CHANGED
@@ -1,10 +1,6 @@
1
1
  # Scrolls
2
2
 
3
- Scrolls is a logging library that is focused on outputting logs in 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
- ## Usage
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
- A feature of Scrolls is setting contexts. Scrolls has two types of
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
- In our example above, the log message is rather generic, so in order
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
- ```ruby
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
- app=myapp deploy=production fn=trap signal=TERM at=exit status=0
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
- You can also dynamically add some data to the global context like this:
32
+ ## Usage
59
33
 
60
34
  ```ruby
61
- Scrolls.add_global_context(hostname: `hostname`)
62
- ```
35
+ require 'scrolls'
63
36
 
37
+ Scrolls.add_timestamp = true
38
+ Scrolls.global_context(:app => "scrolls", :deploy => ENV["DEPLOY"])
64
39
 
65
- If we were in a file and wanted to wrap a particular point of context
66
- we might also do something similar to:
40
+ Scrolls.log(:at => "test")
67
41
 
68
- ```ruby
69
- Scrolls.context(ns: "server") do
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
- As you can see we have some standard nomenclature around logging.
83
- Here's a cheat sheet for some of the methods we use:
84
-
85
- * `app`: Application
86
- * `lib`: Library
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
- Scrolls has a rich #parse method to handle a number of cases. Here is
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
- True/False:
128
-
129
- ```ruby
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
- ## Thanks
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
- log(logdata.merge(
145
- :at => "exception",
146
- :class => e.class,
147
- :message => e.message,
148
- :exception_id => e.object_id.abs
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
- e.backtrace.each do |line|
152
- log(logdata.merge(
153
- :at => "exception",
154
- :class => e.message,
155
- :exception_id => e.object_id.abs,
156
- :site => line.gsub(/[`'"]/, "")
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
@@ -1,3 +1,3 @@
1
1
  module Scrolls
2
- VERSION = "0.3.5"
2
+ VERSION = "0.3.6"
3
3
  end
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.5
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-17 00:00:00.000000000 Z
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