treequel 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +354 -0
- data/LICENSE +27 -0
- data/README +66 -0
- data/Rakefile +345 -0
- data/Rakefile.local +43 -0
- data/bin/treeirb +14 -0
- data/bin/treequel +229 -0
- data/examples/company-directory.rb +112 -0
- data/examples/ldap-monitor.rb +143 -0
- data/examples/ldap-monitor/public/css/master.css +328 -0
- data/examples/ldap-monitor/public/images/card_small.png +0 -0
- data/examples/ldap-monitor/public/images/chain_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small_green.png +0 -0
- data/examples/ldap-monitor/public/images/plug.png +0 -0
- data/examples/ldap-monitor/public/images/shadows/large-30-down.png +0 -0
- data/examples/ldap-monitor/public/images/tick.png +0 -0
- data/examples/ldap-monitor/public/images/tick_circle.png +0 -0
- data/examples/ldap-monitor/public/images/treequel-favicon.png +0 -0
- data/examples/ldap-monitor/views/backends.erb +41 -0
- data/examples/ldap-monitor/views/connections.erb +74 -0
- data/examples/ldap-monitor/views/databases.erb +39 -0
- data/examples/ldap-monitor/views/dump_subsystem.erb +14 -0
- data/examples/ldap-monitor/views/index.erb +14 -0
- data/examples/ldap-monitor/views/layout.erb +35 -0
- data/examples/ldap-monitor/views/listeners.erb +30 -0
- data/examples/ldap_state.rb +62 -0
- data/lib/treequel.rb +145 -0
- data/lib/treequel/branch.rb +589 -0
- data/lib/treequel/branchcollection.rb +204 -0
- data/lib/treequel/branchset.rb +360 -0
- data/lib/treequel/constants.rb +604 -0
- data/lib/treequel/directory.rb +541 -0
- data/lib/treequel/exceptions.rb +32 -0
- data/lib/treequel/filter.rb +704 -0
- data/lib/treequel/mixins.rb +325 -0
- data/lib/treequel/schema.rb +245 -0
- data/lib/treequel/schema/attributetype.rb +252 -0
- data/lib/treequel/schema/ldapsyntax.rb +96 -0
- data/lib/treequel/schema/matchingrule.rb +124 -0
- data/lib/treequel/schema/matchingruleuse.rb +124 -0
- data/lib/treequel/schema/objectclass.rb +289 -0
- data/lib/treequel/sequel_integration.rb +26 -0
- data/lib/treequel/utils.rb +169 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/helpers.rb +434 -0
- data/rake/hg.rb +261 -0
- data/rake/manual.rb +782 -0
- data/rake/packaging.rb +135 -0
- data/rake/publishing.rb +318 -0
- data/rake/rdoc.rb +30 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/rake/win32.rb +190 -0
- data/spec/lib/constants.rb +93 -0
- data/spec/lib/helpers.rb +100 -0
- data/spec/treequel/branch_spec.rb +569 -0
- data/spec/treequel/branchcollection_spec.rb +213 -0
- data/spec/treequel/branchset_spec.rb +376 -0
- data/spec/treequel/directory_spec.rb +487 -0
- data/spec/treequel/filter_spec.rb +482 -0
- data/spec/treequel/mixins_spec.rb +330 -0
- data/spec/treequel/schema/attributetype_spec.rb +237 -0
- data/spec/treequel/schema/ldapsyntax_spec.rb +83 -0
- data/spec/treequel/schema/matchingrule_spec.rb +158 -0
- data/spec/treequel/schema/matchingruleuse_spec.rb +137 -0
- data/spec/treequel/schema/objectclass_spec.rb +262 -0
- data/spec/treequel/schema_spec.rb +118 -0
- data/spec/treequel/utils_spec.rb +49 -0
- data/spec/treequel_spec.rb +179 -0
- metadata +169 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
require 'treequel'
|
6
|
+
require 'treequel/mixins'
|
7
|
+
require 'treequel/schema'
|
8
|
+
require 'treequel/exceptions'
|
9
|
+
|
10
|
+
|
11
|
+
# This is a class for representing matchingRuleUse declarations in a Treequel::Schema.
|
12
|
+
#
|
13
|
+
# == Authors
|
14
|
+
#
|
15
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
16
|
+
#
|
17
|
+
# :include: LICENSE
|
18
|
+
#
|
19
|
+
#--
|
20
|
+
#
|
21
|
+
# Please see the file LICENSE in the base directory for licensing details.
|
22
|
+
#
|
23
|
+
class Treequel::Schema::MatchingRuleUse
|
24
|
+
include Treequel::Loggable,
|
25
|
+
Treequel::Constants::Patterns
|
26
|
+
|
27
|
+
extend Treequel::AttributeDeclarations
|
28
|
+
|
29
|
+
|
30
|
+
#############################################################
|
31
|
+
### C L A S S M E T H O D S
|
32
|
+
#############################################################
|
33
|
+
|
34
|
+
### Parse an MatchingRuleUse entry from a matchingRuleUse description from a schema.
|
35
|
+
def self::parse( schema, description )
|
36
|
+
unless match = ( LDAP_MATCHING_RULE_USE_DESCRIPTION.match(description) )
|
37
|
+
raise Treequel::ParseError, "failed to parse matchingRuleUse from %p" % [ description ]
|
38
|
+
end
|
39
|
+
|
40
|
+
oid, names, desc, obsolete, attr_oids, extensions = match.captures
|
41
|
+
# Treequel.logger.debug " parsed matchingRuleUse: %p" % [ match.captures ]
|
42
|
+
|
43
|
+
# Normalize the attributes
|
44
|
+
names = Treequel::Schema.parse_names( names )
|
45
|
+
desc = Treequel::Schema.unquote_desc( desc )
|
46
|
+
attr_oids = Treequel::Schema.parse_oids( attr_oids )
|
47
|
+
|
48
|
+
return self.new( schema, oid, attr_oids, names, desc, obsolete, extensions )
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
#############################################################
|
53
|
+
### I N S T A N C E M E T H O D S
|
54
|
+
#############################################################
|
55
|
+
|
56
|
+
### Create a new MatchingRuleUse
|
57
|
+
def initialize( schema, oid, attr_oids, names=nil, desc=nil, obsolete=false, extensions=nil )
|
58
|
+
@schema = schema
|
59
|
+
|
60
|
+
@oid = oid
|
61
|
+
@names = names
|
62
|
+
@desc = desc
|
63
|
+
@obsolete = obsolete ? true : false
|
64
|
+
@attr_oids = attr_oids
|
65
|
+
|
66
|
+
@extensions = extensions
|
67
|
+
|
68
|
+
super()
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
######
|
73
|
+
public
|
74
|
+
######
|
75
|
+
|
76
|
+
# The schema the matchingRuleUse belongs to
|
77
|
+
attr_reader :schema
|
78
|
+
|
79
|
+
# The matchingRuleUse's oid
|
80
|
+
attr_reader :oid
|
81
|
+
|
82
|
+
# The Array of the matchingRuleUse's names
|
83
|
+
attr_reader :names
|
84
|
+
|
85
|
+
# The matchingRuleUse's description
|
86
|
+
attr_accessor :desc
|
87
|
+
|
88
|
+
# Is the matchingRuleUse obsolete?
|
89
|
+
predicate_attr :obsolete
|
90
|
+
|
91
|
+
# The OIDs of the attributes the matchingRuleUse applies to
|
92
|
+
attr_reader :attr_oids
|
93
|
+
|
94
|
+
# The matchingRuleUse's extensions (as a String)
|
95
|
+
attr_accessor :extensions
|
96
|
+
|
97
|
+
|
98
|
+
### Return the first of the matchingRuleUse's names, if it has any, or +nil+.
|
99
|
+
def name
|
100
|
+
return self.names.first
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
### Return a human-readable representation of the object suitable for debugging
|
105
|
+
def inspect
|
106
|
+
return "#<%s:0x%0x %s(%s) %p -> %p >" % [
|
107
|
+
self.class.name,
|
108
|
+
self.object_id / 2,
|
109
|
+
self.name,
|
110
|
+
self.oid,
|
111
|
+
self.desc,
|
112
|
+
self.attr_oids,
|
113
|
+
]
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
### Return Treequel::Schema::AttributeType objects for each of the types this MatchingRuleUse
|
118
|
+
### applies to.
|
119
|
+
def attribute_types
|
120
|
+
return self.attr_oids.collect {|oid| self.schema.attribute_types[oid] }
|
121
|
+
end
|
122
|
+
|
123
|
+
end # class Treequel::Schema::MatchingRuleUse
|
124
|
+
|
@@ -0,0 +1,289 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
require 'treequel'
|
6
|
+
require 'treequel/schema'
|
7
|
+
require 'treequel/exceptions'
|
8
|
+
|
9
|
+
|
10
|
+
# This is a collection of classes for representing objectClasses in a Treequel::Schema.
|
11
|
+
#
|
12
|
+
# == Authors
|
13
|
+
#
|
14
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
15
|
+
# * Mahlon E. Smith <mahlon@martini.nu>
|
16
|
+
#
|
17
|
+
# :include: LICENSE
|
18
|
+
#
|
19
|
+
#--
|
20
|
+
#
|
21
|
+
# Please see the file LICENSE in the base directory for licensing details.
|
22
|
+
#
|
23
|
+
class Treequel::Schema
|
24
|
+
|
25
|
+
# The types of objectClass as specified in the schema, along with which Ruby class
|
26
|
+
# corresponds to it. Each class registers itself as it's defined.
|
27
|
+
OBJECTCLASS_TYPES = {}
|
28
|
+
|
29
|
+
|
30
|
+
### objectClass entries in a Treequel::Schema.
|
31
|
+
class ObjectClass
|
32
|
+
include Treequel::Loggable,
|
33
|
+
Treequel::Constants::Patterns
|
34
|
+
|
35
|
+
extend Treequel::AttributeDeclarations
|
36
|
+
|
37
|
+
|
38
|
+
private_class_method :new
|
39
|
+
|
40
|
+
# The 'kind' of objectClasses which don't specify a 'kind' explicitly
|
41
|
+
DEFAULT_OBJECTCLASS_KIND = 'STRUCTURAL'
|
42
|
+
|
43
|
+
|
44
|
+
#############################################################
|
45
|
+
### C L A S S M E T H O D S
|
46
|
+
#############################################################
|
47
|
+
|
48
|
+
### Inheritance callback: Make the constructor method of all inheriting classes
|
49
|
+
### public.
|
50
|
+
def self::inherited( subclass )
|
51
|
+
subclass.instance_eval { public_class_method :new }
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
### Parse an ObjectClass entry from a objectClass description from a schema.
|
56
|
+
def self::parse( schema, description )
|
57
|
+
unless match = ( LDAP_OBJECTCLASS_DESCRIPTION.match(description) )
|
58
|
+
raise Treequel::ParseError, "failed to parse objectClass from %p" % [ description ]
|
59
|
+
end
|
60
|
+
|
61
|
+
oid, names, desc, obsolete, sup, kind, must, may, extensions = match.captures
|
62
|
+
|
63
|
+
# Normalize the attributes
|
64
|
+
must_oids = Treequel::Schema.parse_oids( must )
|
65
|
+
may_oids = Treequel::Schema.parse_oids( may )
|
66
|
+
names = Treequel::Schema.parse_names( names )
|
67
|
+
desc = Treequel::Schema.unquote_desc( desc )
|
68
|
+
|
69
|
+
# Default the 'kind' attribute
|
70
|
+
kind ||= DEFAULT_OBJECTCLASS_KIND
|
71
|
+
|
72
|
+
# Find the appropriate concrete class to instantiate
|
73
|
+
concrete_class = Treequel::Schema::OBJECTCLASS_TYPES[ kind ] or
|
74
|
+
raise Treequel::Error, "no such objectClass type %p: expected one of: %p" %
|
75
|
+
[ kind, Treequel::Schema::OBJECTCLASS_TYPES.keys ]
|
76
|
+
|
77
|
+
return concrete_class.new( schema, oid, names, desc, obsolete, sup,
|
78
|
+
must_oids, may_oids, extensions )
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
#############################################################
|
83
|
+
### I N S T A N C E M E T H O D S
|
84
|
+
#############################################################
|
85
|
+
|
86
|
+
### Create a new ObjectClass
|
87
|
+
def initialize( schema, oid, names=nil, desc=nil, obsolete=false, sup=nil, must_oids=[],
|
88
|
+
may_oids=[], extensions=nil )
|
89
|
+
@schema = schema
|
90
|
+
|
91
|
+
@oid = oid
|
92
|
+
@names = names
|
93
|
+
@desc = desc
|
94
|
+
@obsolete = obsolete ? true : false
|
95
|
+
@sup_name = sup
|
96
|
+
@must_oids = must_oids
|
97
|
+
@may_oids = may_oids
|
98
|
+
@extensions = extensions
|
99
|
+
|
100
|
+
super()
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
######
|
105
|
+
public
|
106
|
+
######
|
107
|
+
|
108
|
+
# The schema the objectClass belongs to
|
109
|
+
attr_reader :schema
|
110
|
+
|
111
|
+
# The objectClass's oid
|
112
|
+
attr_reader :oid
|
113
|
+
|
114
|
+
# The Array of the objectClass's names
|
115
|
+
attr_reader :names
|
116
|
+
|
117
|
+
# The objectClass's description
|
118
|
+
attr_accessor :desc
|
119
|
+
|
120
|
+
# Is the objectClass obsolete?
|
121
|
+
predicate_attr :obsolete
|
122
|
+
|
123
|
+
# The name of the objectClass's superior class (if specified)
|
124
|
+
attr_accessor :sup_name
|
125
|
+
|
126
|
+
# The Array of the objectClass's MUST OIDs
|
127
|
+
attr_reader :must_oids
|
128
|
+
|
129
|
+
# The Array of the objectClass's MAY OIDs
|
130
|
+
attr_reader :may_oids
|
131
|
+
|
132
|
+
# The objectClass's extensions (as a String)
|
133
|
+
attr_accessor :extensions
|
134
|
+
|
135
|
+
|
136
|
+
### Return the first of the objectClass's names, if it has any, or +nil+.
|
137
|
+
def name
|
138
|
+
return self.names.first
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
### Return Treequel::Schema::AttributeType objects for each of the objectClass's
|
143
|
+
### MUST attributes.
|
144
|
+
def must
|
145
|
+
self.must_oids.collect do |oid|
|
146
|
+
self.log.warn "No attribute type for OID %p (case bug?)" % [ oid ] unless
|
147
|
+
self.schema.attribute_types.key?( oid )
|
148
|
+
self.schema.attribute_types[oid]
|
149
|
+
end.compact
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
### Return Treequel::Schema::AttributeType objects for each of the objectClass's
|
154
|
+
### MAY attributes.
|
155
|
+
def may
|
156
|
+
self.may_oids.collect do |oid|
|
157
|
+
self.log.warn "No attribute type for OID %p (case bug?)" % [ oid ] unless
|
158
|
+
self.schema.attribute_types.key?( oid )
|
159
|
+
self.schema.attribute_types[oid]
|
160
|
+
end.compact
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
### Returns +true+ if this objectClass is STRUCTURAL. Defaults to +false+ and then
|
165
|
+
### overridden in StructuralObjectClass.
|
166
|
+
def structural?
|
167
|
+
return false
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
### Return a human-readable representation of the object suitable for debugging
|
172
|
+
def inspect
|
173
|
+
return %{#<%s:0x%0x %s(%s) < %s "%s" MUST: %p, MAY: %p>} % [
|
174
|
+
self.class.name,
|
175
|
+
self.object_id / 2,
|
176
|
+
self.name,
|
177
|
+
self.oid,
|
178
|
+
self.sup_name,
|
179
|
+
self.desc,
|
180
|
+
self.must_oids,
|
181
|
+
self.may_oids,
|
182
|
+
]
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
### Return the ObjectClass for the receiver's SUP. If this is called on
|
187
|
+
### 'top', returns nil.
|
188
|
+
def sup
|
189
|
+
unless name = self.sup_name
|
190
|
+
return nil if self.oid == Treequel::Constants::OIDS::TOP_OBJECTCLASS
|
191
|
+
return self.schema.object_classes[ :top ]
|
192
|
+
end
|
193
|
+
return self.schema.object_classes[ name.to_sym ]
|
194
|
+
end
|
195
|
+
|
196
|
+
end # class ObjectClass
|
197
|
+
|
198
|
+
|
199
|
+
### An LDAP objectClass of type 'ABSTRACT'. From RFC 4512:
|
200
|
+
###
|
201
|
+
### An abstract object class, as the name implies, provides a base of
|
202
|
+
### characteristics from which other object classes can be defined to
|
203
|
+
### inherit from. An entry cannot belong to an abstract object class
|
204
|
+
### unless it belongs to a structural or auxiliary class that inherits
|
205
|
+
### from that abstract class.
|
206
|
+
###
|
207
|
+
### Abstract object classes cannot derive from structural or auxiliary
|
208
|
+
### object classes.
|
209
|
+
###
|
210
|
+
### All structural object classes derive (directly or indirectly) from
|
211
|
+
### the 'top' abstract object class. Auxiliary object classes do not
|
212
|
+
### necessarily derive from 'top'.
|
213
|
+
###
|
214
|
+
class AbstractObjectClass < Treequel::Schema::ObjectClass
|
215
|
+
Treequel::Schema::OBJECTCLASS_TYPES[ 'ABSTRACT' ] = self
|
216
|
+
end # class AbstractObjectClass
|
217
|
+
|
218
|
+
|
219
|
+
### An LDAP objectClass of type 'AUXILIARY'. From FC4512:
|
220
|
+
###
|
221
|
+
### Auxiliary object classes are used to augment the characteristics of
|
222
|
+
### entries. They are commonly used to augment the sets of attributes
|
223
|
+
### required and allowed to be present in an entry. They can be used to
|
224
|
+
### describe entries or classes of entries.
|
225
|
+
###
|
226
|
+
### Auxiliary object classes cannot subclass structural object classes.
|
227
|
+
###
|
228
|
+
### An entry can belong to any subset of the set of auxiliary object
|
229
|
+
### classes allowed by the DIT content rule associated with the
|
230
|
+
### structural object class of the entry. If no DIT content rule is
|
231
|
+
### associated with the structural object class of the entry, the entry
|
232
|
+
### cannot belong to any auxiliary object class.
|
233
|
+
###
|
234
|
+
### The set of auxiliary object classes that an entry belongs to can
|
235
|
+
### change over time.
|
236
|
+
class AuxiliaryObjectClass < Treequel::Schema::ObjectClass
|
237
|
+
Treequel::Schema::OBJECTCLASS_TYPES[ 'AUXILIARY' ] = self
|
238
|
+
end # class AuxiliaryObjectClass
|
239
|
+
|
240
|
+
|
241
|
+
### An LDAP objectClass of type 'STRUCTURAL'. From RFC4512:
|
242
|
+
###
|
243
|
+
### An object class defined for use in the structural specification of
|
244
|
+
### the DIT is termed a structural object class. Structural object
|
245
|
+
### classes are used in the definition of the structure of the names
|
246
|
+
### of the objects for compliant entries.
|
247
|
+
###
|
248
|
+
### An object or alias entry is characterized by precisely one
|
249
|
+
### structural object class superclass chain which has a single
|
250
|
+
### structural object class as the most subordinate object class.
|
251
|
+
### This structural object class is referred to as the structural
|
252
|
+
### object class of the entry.
|
253
|
+
###
|
254
|
+
### Structural object classes are related to associated entries:
|
255
|
+
###
|
256
|
+
### - an entry conforming to a structural object class shall
|
257
|
+
### represent the real-world object constrained by the object
|
258
|
+
### class;
|
259
|
+
###
|
260
|
+
### - DIT structure rules only refer to structural object classes;
|
261
|
+
### the structural object class of an entry is used to specify the
|
262
|
+
### position of the entry in the DIT;
|
263
|
+
###
|
264
|
+
### - the structural object class of an entry is used, along with an
|
265
|
+
### associated DIT content rule, to control the content of an
|
266
|
+
### entry.
|
267
|
+
###
|
268
|
+
### The structural object class of an entry shall not be changed.
|
269
|
+
###
|
270
|
+
### Each structural object class is a (direct or indirect) subclass of
|
271
|
+
### the 'top' abstract object class.
|
272
|
+
###
|
273
|
+
### Structural object classes cannot subclass auxiliary object classes.
|
274
|
+
###
|
275
|
+
### Each entry is said to belong to its structural object class as well
|
276
|
+
### as all classes in its structural object class's superclass chain.
|
277
|
+
###
|
278
|
+
class StructuralObjectClass < Treequel::Schema::ObjectClass
|
279
|
+
Treequel::Schema::OBJECTCLASS_TYPES[ 'STRUCTURAL' ] = self
|
280
|
+
|
281
|
+
### Returns +true+, indicating that instances of this class are STRUCTURAL.
|
282
|
+
def structural?
|
283
|
+
return true
|
284
|
+
end
|
285
|
+
|
286
|
+
end # class StructuralObjectClass
|
287
|
+
|
288
|
+
end # class Treequel::Schema
|
289
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'treequel'
|
4
|
+
require 'treequel/filter'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'sequel'
|
8
|
+
rescue LoadError => err
|
9
|
+
Treequel.logger.info "Sequel library didn't load: %s: %s" % [ err.class.name, err.message ]
|
10
|
+
Treequel.logger.debug " " + err.backtrace.join( "\n " )
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
# Provide a dummy Sequel::SQL::Expression class for when the Sequel library
|
15
|
+
# isn't installed.
|
16
|
+
unless defined?( Sequel ) &&
|
17
|
+
Sequel.const_defined?( :SQL ) &&
|
18
|
+
Sequel::SQL.const_defined?( :Expression )
|
19
|
+
|
20
|
+
module Sequel # :nodoc: all
|
21
|
+
module SQL
|
22
|
+
class Expression; end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,169 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'erb'
|
5
|
+
require 'bigdecimal'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
require 'treequel'
|
9
|
+
# require 'treequel/constants'
|
10
|
+
|
11
|
+
|
12
|
+
module Treequel # :nodoc:
|
13
|
+
|
14
|
+
#
|
15
|
+
# A alternate formatter for Logger instances.
|
16
|
+
#
|
17
|
+
# == Usage
|
18
|
+
#
|
19
|
+
# require 'treequel/utils'
|
20
|
+
# Treequel.logger.formatter = Treequel::LogFormatter.new( Treequel.logger )
|
21
|
+
#
|
22
|
+
# == Version
|
23
|
+
#
|
24
|
+
# $Id$
|
25
|
+
#
|
26
|
+
# == Authors
|
27
|
+
#
|
28
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
29
|
+
#
|
30
|
+
# :include: LICENSE
|
31
|
+
#
|
32
|
+
#--
|
33
|
+
#
|
34
|
+
# Please see the file LICENSE in the 'docs' directory for licensing details.
|
35
|
+
#
|
36
|
+
class LogFormatter < Logger::Formatter
|
37
|
+
|
38
|
+
# The format to output unless debugging is turned on
|
39
|
+
DEFAULT_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"
|
40
|
+
|
41
|
+
# The format to output if debugging is turned on
|
42
|
+
DEFAULT_DEBUG_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"
|
43
|
+
|
44
|
+
|
45
|
+
### Initialize the formatter with a reference to the logger so it can check for log level.
|
46
|
+
def initialize( logger, format=DEFAULT_FORMAT, debug=DEFAULT_DEBUG_FORMAT ) # :notnew:
|
47
|
+
@logger = logger
|
48
|
+
@format = format
|
49
|
+
@debug_format = debug
|
50
|
+
|
51
|
+
super()
|
52
|
+
end
|
53
|
+
|
54
|
+
######
|
55
|
+
public
|
56
|
+
######
|
57
|
+
|
58
|
+
# The Logger object associated with the formatter
|
59
|
+
attr_accessor :logger
|
60
|
+
|
61
|
+
# The logging format string
|
62
|
+
attr_accessor :format
|
63
|
+
|
64
|
+
# The logging format string that's used when outputting in debug mode
|
65
|
+
attr_accessor :debug_format
|
66
|
+
|
67
|
+
|
68
|
+
### Log using either the DEBUG_FORMAT if the associated logger is at ::DEBUG level or
|
69
|
+
### using FORMAT if it's anything less verbose.
|
70
|
+
def call( severity, time, progname, msg )
|
71
|
+
args = [
|
72
|
+
time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
|
73
|
+
time.usec, # %2$d
|
74
|
+
Process.pid, # %3$d
|
75
|
+
Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
|
76
|
+
severity, # %5$s
|
77
|
+
progname, # %6$s
|
78
|
+
msg # %7$s
|
79
|
+
]
|
80
|
+
|
81
|
+
if @logger.level == Logger::DEBUG
|
82
|
+
return self.debug_format % args
|
83
|
+
else
|
84
|
+
return self.format % args
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end # class LogFormatter
|
88
|
+
|
89
|
+
|
90
|
+
#
|
91
|
+
# An alternate formatter for Logger instances that outputs +div+ HTML
|
92
|
+
# fragments.
|
93
|
+
#
|
94
|
+
# == Usage
|
95
|
+
#
|
96
|
+
# require 'treequel/utils'
|
97
|
+
# Treequel.logger.formatter = Treequel::HtmlLogFormatter.new( Treequel.logger )
|
98
|
+
#
|
99
|
+
# == Version
|
100
|
+
#
|
101
|
+
# $Id$
|
102
|
+
#
|
103
|
+
# == Authors
|
104
|
+
#
|
105
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
106
|
+
#
|
107
|
+
# :include: LICENSE
|
108
|
+
#
|
109
|
+
#--
|
110
|
+
#
|
111
|
+
# Please see the file LICENSE in the 'docs' directory for licensing details.
|
112
|
+
#
|
113
|
+
class HtmlLogFormatter < Logger::Formatter
|
114
|
+
include ERB::Util # for html_escape()
|
115
|
+
|
116
|
+
# The default HTML fragment that'll be used as the template for each log message.
|
117
|
+
HTML_LOG_FORMAT = %q{
|
118
|
+
<div class="log-message %5$s">
|
119
|
+
<span class="log-time">%1$s.%2$06d</span>
|
120
|
+
[
|
121
|
+
<span class="log-pid">%3$d</span>
|
122
|
+
/
|
123
|
+
<span class="log-tid">%4$s</span>
|
124
|
+
]
|
125
|
+
<span class="log-level">%5$s</span>
|
126
|
+
:
|
127
|
+
<span class="log-name">%6$s</span>
|
128
|
+
<span class="log-message-text">%7$s</span>
|
129
|
+
</div>
|
130
|
+
}
|
131
|
+
|
132
|
+
### Override the logging formats with ones that generate HTML fragments
|
133
|
+
def initialize( logger, format=HTML_LOG_FORMAT ) # :notnew:
|
134
|
+
@logger = logger
|
135
|
+
@format = format
|
136
|
+
super()
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
######
|
141
|
+
public
|
142
|
+
######
|
143
|
+
|
144
|
+
# The HTML fragment that will be used as a format() string for the log
|
145
|
+
attr_accessor :format
|
146
|
+
|
147
|
+
|
148
|
+
### Return a log message composed out of the arguments formatted using the
|
149
|
+
### formatter's format string
|
150
|
+
def call( severity, time, progname, msg )
|
151
|
+
args = [
|
152
|
+
time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
|
153
|
+
time.usec, # %2$d
|
154
|
+
Process.pid, # %3$d
|
155
|
+
Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
|
156
|
+
severity.downcase, # %5$s
|
157
|
+
progname, # %6$s
|
158
|
+
html_escape( msg ).gsub(/\n/, '<br />') # %7$s
|
159
|
+
]
|
160
|
+
|
161
|
+
return self.format % args
|
162
|
+
end
|
163
|
+
|
164
|
+
end # class HtmlLogFormatter
|
165
|
+
|
166
|
+
end # module Treequel
|
167
|
+
|
168
|
+
# vim: set nosta noet ts=4 sw=4:
|
169
|
+
|