treequel 1.0.0
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.
- 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
|
+
|