sawmill 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.
Files changed (38) hide show
  1. data/History.rdoc +3 -0
  2. data/README.rdoc +81 -0
  3. data/Rakefile +147 -0
  4. data/lib/sawmill/entry.rb +307 -0
  5. data/lib/sawmill/entry_classifier.rb +75 -0
  6. data/lib/sawmill/entry_processor/build_records.rb +157 -0
  7. data/lib/sawmill/entry_processor/conditionals.rb +444 -0
  8. data/lib/sawmill/entry_processor/filter_basic_fields.rb +145 -0
  9. data/lib/sawmill/entry_processor/format.rb +228 -0
  10. data/lib/sawmill/entry_processor/simple_queue.rb +116 -0
  11. data/lib/sawmill/entry_processor.rb +158 -0
  12. data/lib/sawmill/errors.rb +66 -0
  13. data/lib/sawmill/level.rb +264 -0
  14. data/lib/sawmill/log_record_middleware.rb +93 -0
  15. data/lib/sawmill/logger.rb +373 -0
  16. data/lib/sawmill/parser.rb +181 -0
  17. data/lib/sawmill/record.rb +255 -0
  18. data/lib/sawmill/record_processor/conditionals.rb +330 -0
  19. data/lib/sawmill/record_processor/decompose.rb +75 -0
  20. data/lib/sawmill/record_processor/filter_by_attributes.rb +87 -0
  21. data/lib/sawmill/record_processor/filter_by_record_id.rb +77 -0
  22. data/lib/sawmill/record_processor/format.rb +88 -0
  23. data/lib/sawmill/record_processor/simple_queue.rb +117 -0
  24. data/lib/sawmill/record_processor.rb +137 -0
  25. data/lib/sawmill/rotater/base.rb +90 -0
  26. data/lib/sawmill/rotater/date_based_log_file.rb +145 -0
  27. data/lib/sawmill/rotater/shifting_log_file.rb +166 -0
  28. data/lib/sawmill/rotater.rb +236 -0
  29. data/lib/sawmill/util/queue.rb +138 -0
  30. data/lib/sawmill/version.rb +47 -0
  31. data/lib/sawmill.rb +78 -0
  32. data/tests/tc_entry_processors.rb +138 -0
  33. data/tests/tc_formatter_parser.rb +144 -0
  34. data/tests/tc_levels.rb +118 -0
  35. data/tests/tc_logger.rb +315 -0
  36. data/tests/tc_record_processors.rb +117 -0
  37. data/tests/tc_records.rb +206 -0
  38. metadata +116 -0
@@ -0,0 +1,66 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill error classes
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2009 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Sawmill
38
+
39
+
40
+ # This is a namespace for errors that can be thrown by Sawmill.
41
+
42
+ module Errors
43
+
44
+
45
+ # Base class for all Sawmill exceptions
46
+
47
+ class SawmillError < ::RuntimeError
48
+ end
49
+
50
+
51
+ # Tried to create an illegal record
52
+
53
+ class IllegalRecordError < SawmillError
54
+ end
55
+
56
+
57
+ # Tried to log an entry with an unknown level code
58
+
59
+ class UnknownLevelError < SawmillError
60
+ end
61
+
62
+
63
+ end
64
+
65
+
66
+ end
@@ -0,0 +1,264 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill level class
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2009 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Sawmill
38
+
39
+
40
+ # Level objects represent logging levels, sometimes known as severities.
41
+ #
42
+ # A level object has a name and a numeric value. The name controls how the
43
+ # level is represented in a logfile. The value indicates its severity rank
44
+ # compared to other levels.
45
+ #
46
+ # Levels are organized into groups. Levels are comparable with one another
47
+ # if they are part of the same group.
48
+
49
+ class Level
50
+
51
+
52
+ def initialize(group_, name_, value_) # :nodoc:
53
+ @group = group_
54
+ @name = name_
55
+ @value = value_
56
+ end
57
+
58
+
59
+ # The LevelGroup of which this Level is a member
60
+ attr_reader :group
61
+
62
+ # The name of the level, as a string.
63
+ attr_reader :name
64
+
65
+ # The numeric value of the level.
66
+ attr_reader :value
67
+
68
+
69
+ # Compare this level with another level of the same group.
70
+ def <=>(obj_)
71
+ if obj_.respond_to?(:value) && obj_.respond_to?(:group)
72
+ @group == obj_.group ? @value <=> obj_.value : nil
73
+ else
74
+ nil
75
+ end
76
+ end
77
+
78
+
79
+ # Returns the name.
80
+ def to_s
81
+ @name
82
+ end
83
+
84
+
85
+ def inspect # :nodoc:
86
+ "#<#{self.class}:0x#{object_id.to_s(16)} name=#{@name.inspect} value=#{@value}>"
87
+ end
88
+
89
+
90
+ include ::Comparable
91
+
92
+
93
+ end
94
+
95
+
96
+ # A level group is a group of related levels that can be ordered and used
97
+ # in a log. A given log is always associated with exactly one group, which
98
+ # controls what levels are available for log entries.
99
+ #
100
+ # Normally, you will use Sawmill::STANDARD_LEVELS, which defines levels
101
+ # corresponding to the ones available in the classic ruby logger class.
102
+ # However, this class is available to define custom level hierarchies.
103
+
104
+ class LevelGroup
105
+
106
+
107
+ # Create a level group.
108
+ # You must provide a block that calls methods of
109
+ # Sawmill::LevelGroup::Builder to define the levels in the group.
110
+
111
+ def initialize(&block_)
112
+ @level_order = []
113
+ @level_names = {}
114
+ @level_methods = {}
115
+ @default = nil
116
+ ::Blockenspiel.invoke(block_, Builder.new(self))
117
+ end
118
+
119
+
120
+ def inspect # :nodoc:
121
+ "#<#{self.class}:0x#{object_id.to_s(16)} levels=[#{@level_order.map{|lvl_| lvl_.name.inspect}.join(',')}]>"
122
+ end
123
+
124
+
125
+ # Return the default level, the one used when no level is specified.
126
+
127
+ def default
128
+ @default ||= highest
129
+ end
130
+
131
+
132
+ # Return the lowest level in the group.
133
+
134
+ def lowest
135
+ @level_order.first
136
+ end
137
+
138
+
139
+ # Return the highest level in the group.
140
+
141
+ def highest
142
+ @level_order.last
143
+ end
144
+
145
+
146
+ # Return the length of the longest name in the group.
147
+
148
+ def column_width
149
+ @level_order.inject(0) do |width_, level_|
150
+ w_ = level_.name.size
151
+ w_ > width_ ? w_ : width_
152
+ end
153
+ end
154
+
155
+
156
+ # Look up a level by a logger method name.
157
+
158
+ def lookup_method(method_name_)
159
+ @level_methods[method_name_.to_sym]
160
+ end
161
+
162
+
163
+ # Get a level in this group.
164
+ #
165
+ # You may pass either an integer value, a level name, a level object,
166
+ # or nil. If you pass nil, the default level is returned. Otherwise,
167
+ # the level corresponding to the given parameter is returned. If no
168
+ # level in this group corresponds to the parameter, nil is returned.
169
+
170
+ def get(name_)
171
+ case name_
172
+ when ::Integer
173
+ @level_order[name_]
174
+ when Level
175
+ @level_order[name_.value] == name_ ? name_ : nil
176
+ when ::Symbol, ::String
177
+ @level_names[name_.to_sym]
178
+ when nil
179
+ default
180
+ else
181
+ nil
182
+ end
183
+ end
184
+
185
+
186
+ def _add(name_, opts_={}) # :nodoc:
187
+ name_ = name_.to_sym
188
+ default_ = opts_[:default]
189
+ methods_ = opts_[:methods] || []
190
+ methods_ = [methods_] unless methods_.kind_of?(::Array)
191
+ if @level_names.include?(name_)
192
+ raise ::ArgumentError, "Name #{name_} already taken"
193
+ end
194
+ value_ = @level_order.size
195
+ level_ = Level.new(self, name_, value_)
196
+ if default_
197
+ if @default
198
+ raise ::ArgumentError, "A default level is already specified"
199
+ else
200
+ @default = level_
201
+ end
202
+ end
203
+ @level_order << level_
204
+ @level_names[name_] = level_
205
+ methods_.each do |method_|
206
+ method_ = method_.to_sym
207
+ if @level_methods.include?(method_)
208
+ raise ::ArgumentError, "Method #{method_} already taken"
209
+ else
210
+ @level_methods[method_] = level_
211
+ end
212
+ end
213
+ end
214
+
215
+
216
+ # You may call methods of this object in the block passed to
217
+ # Sawmill::LevelGroup#new.
218
+
219
+ class Builder
220
+
221
+ include ::Blockenspiel::DSL
222
+
223
+
224
+ def initialize(group_) # :nodoc:
225
+ @group = group_
226
+ end
227
+
228
+
229
+ # Add a level to this group. The level is assigned the next value in
230
+ # sequence, and the given name.
231
+ #
232
+ # You may also provide these options:
233
+ #
234
+ # <tt>:default</tt>::
235
+ # If set to true, this level is made the default.
236
+ # <tt>:methods</tt>::
237
+ # If set to an array of strings or methods, those method names are
238
+ # mapped to this level. You may then use those methods in the
239
+ # Sawmill::Logger class as a shortcut for creating log messages with
240
+ # this level.
241
+
242
+ def add(name_, opts_={})
243
+ @group._add(name_, opts_)
244
+ end
245
+
246
+
247
+ end
248
+
249
+ end
250
+
251
+
252
+ # A LevelGroup that corresponds to the classic ruby logger levels.
253
+
254
+ STANDARD_LEVELS = LevelGroup.new do
255
+ add(:DEBUG, :methods => 'debug')
256
+ add(:INFO, :methods => 'info', :default => true)
257
+ add(:WARN, :methods => 'warn')
258
+ add(:ERROR, :methods => 'error')
259
+ add(:FATAL, :methods => 'fatal')
260
+ add(:ANY, :methods => ['any', 'unknown'])
261
+ end
262
+
263
+
264
+ end
@@ -0,0 +1,93 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill logger class
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2009 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Sawmill
38
+
39
+
40
+ # A Rack middleware that starts and ends a log record.
41
+ # Insert this in your Rack stack to wrap requests in a log record.
42
+
43
+ class LogRecordMiddleware
44
+
45
+
46
+ # Create a middleware object for Rack.
47
+ #
48
+ # If you do not provide a logger object, one will be generated for you
49
+ # that simply logs to STDOUT.
50
+ #
51
+ # Recognized options include:
52
+ #
53
+ # <tt>:request_id_key</tt>::
54
+ # The name of a rack environment key where the record ID should be
55
+ # stored. If not specified, defaults to "sawmill.request_id".
56
+ # <tt>:start_time_attribute</tt>::
57
+ # If present, logs an attribute with this name with the starting
58
+ # timestamp for the request. If absent, does not log this attribute.
59
+ # <tt>:end_time_attribute</tt>::
60
+ # If present, logs an attribute with this name with the ending
61
+ # timestamp for the request. If absent, does not log this attribute.
62
+
63
+ def initialize(app_, logger_=nil, opts_={})
64
+ @app = app_
65
+ @logger = logger_ || Logger.new(:progname => 'rack', :processor => ::Sawmill::Formatter.new(STDOUT))
66
+ @request_id_key = opts_[:request_id_key] || 'sawmill.request_id'
67
+ @start_time_attribute = opts_[:start_time_attribute]
68
+ @end_time_attribute = opts_[:end_time_attribute]
69
+ end
70
+
71
+
72
+ def call(env_)
73
+ env_[@request_id_key] = @logger.begin_record
74
+ if @start_time_attribute
75
+ time_ = Time.now.utc
76
+ @logger.set_attribute(@start_time_attribute, time_.strftime('%Y-%m-%dT%H:%M:%S.') + ('%06d' % time_.usec) + 'Z')
77
+ end
78
+ begin
79
+ return @app.call(env_)
80
+ ensure
81
+ if @end_time_attribute
82
+ time_ = Time.now.utc
83
+ @logger.set_attribute(@end_time_attribute, time_.strftime('%Y-%m-%dT%H:%M:%S.') + ('%06d' % time_.usec) + 'Z')
84
+ end
85
+ @logger.end_record
86
+ end
87
+ end
88
+
89
+
90
+ end
91
+
92
+
93
+ end