sawmill 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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