copland 0.8.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/manual-html/chapter-1.html +227 -36
- data/doc/manual-html/chapter-10.html +155 -82
- data/doc/manual-html/chapter-11.html +90 -267
- data/doc/manual-html/chapter-12.html +289 -71
- data/doc/manual-html/chapter-13.html +430 -0
- data/doc/manual-html/chapter-2.html +45 -21
- data/doc/manual-html/chapter-3.html +45 -21
- data/doc/manual-html/chapter-4.html +45 -21
- data/doc/manual-html/chapter-5.html +45 -21
- data/doc/manual-html/chapter-6.html +49 -21
- data/doc/manual-html/chapter-7.html +45 -21
- data/doc/manual-html/chapter-8.html +66 -26
- data/doc/manual-html/chapter-9.html +48 -24
- data/doc/manual-html/index.html +54 -22
- data/doc/manual-html/manual.css +12 -0
- data/doc/manual-html/tutorial-1.html +45 -21
- data/doc/manual-html/tutorial-2.html +45 -21
- data/doc/manual-html/tutorial-3.html +45 -21
- data/doc/manual-html/tutorial-4.html +45 -21
- data/doc/manual-html/tutorial-5.html +45 -21
- data/doc/manual/manual.css +12 -0
- data/doc/manual/manual.rb +1 -1
- data/doc/manual/manual.yml +426 -20
- data/doc/packages/copland.html +41 -9
- data/doc/packages/copland.lib.html +36 -8
- data/doc/packages/copland.remote.html +46 -10
- data/doc/packages/copland.webrick.html +16 -65
- data/doc/packages/index.html +1 -1
- data/doc/presentation/copland.mgp +1083 -0
- data/doc/presentation/to_html.rb +52 -0
- data/lib/copland/configuration-point/common.rb +32 -1
- data/lib/copland/configuration/yaml/service-point.rb +10 -1
- data/lib/copland/log-factory.rb +28 -12
- data/lib/copland/logger.rb +155 -0
- data/lib/copland/models/singleton.rb +8 -2
- data/lib/copland/package.rb +32 -14
- data/lib/copland/service-point.rb +7 -0
- data/lib/copland/thread.rb +104 -0
- data/lib/copland/utils.rb +10 -3
- data/lib/copland/version.rb +2 -2
- data/test/configuration/yaml/tc_service-point-processor.rb +8 -0
- data/test/custom-logger.yml +2 -1
- data/test/impl/tc_logging-interceptor.rb +12 -12
- data/test/logger.yml +1 -1
- data/test/mock.rb +2 -0
- data/test/tc_logger.rb +19 -6
- data/test/tc_package.rb +25 -0
- data/test/tc_queryable-mutex.rb +75 -0
- data/test/tc_registry.rb +8 -4
- metadata +9 -2
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Copland Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-
|
17
|
+
Copland Version: <strong>1.0.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-12 02:22 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -39,13 +39,21 @@
|
|
39
39
|
|
40
40
|
<li><a href="chapter-1.html#s1">What is Copland?</a></li>
|
41
41
|
|
42
|
-
<li><a href="chapter-1.html#s2">
|
42
|
+
<li><a href="chapter-1.html#s2">What Can Copland Do For Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Copland <em>sans</em> Buzzwords</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">Copland <em>avec</em> Buzzwords</a></li>
|
47
47
|
|
48
|
-
<li><a href="chapter-1.html#s5">
|
48
|
+
<li><a href="chapter-1.html#s5">The Buzzwords Themselves</a></li>
|
49
|
+
|
50
|
+
<li><a href="chapter-1.html#s6">Features</a></li>
|
51
|
+
|
52
|
+
<li><a href="chapter-1.html#s7">Getting Copland</a></li>
|
53
|
+
|
54
|
+
<li><a href="chapter-1.html#s8">License Information</a></li>
|
55
|
+
|
56
|
+
<li><a href="chapter-1.html#s9">Support</a></li>
|
49
57
|
|
50
58
|
</ol>
|
51
59
|
</li>
|
@@ -149,7 +157,9 @@
|
|
149
157
|
|
150
158
|
<li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
|
151
159
|
|
152
|
-
<li><a href="chapter-8.html#s2">
|
160
|
+
<li><a href="chapter-8.html#s2">FactoryDefaults</a></li>
|
161
|
+
|
162
|
+
<li><a href="chapter-8.html#s3">ApplicationDefaults</a></li>
|
153
163
|
|
154
164
|
</ol>
|
155
165
|
</li>
|
@@ -166,54 +176,68 @@
|
|
166
176
|
|
167
177
|
<li>
|
168
178
|
<a href="chapter-10.html">
|
179
|
+
Logging
|
180
|
+
</a>
|
181
|
+
|
182
|
+
<ol type="1">
|
183
|
+
|
184
|
+
<li><a href="chapter-10.html#s1">Log Factory</a></li>
|
185
|
+
|
186
|
+
<li><a href="chapter-10.html#s2">Configuration</a></li>
|
187
|
+
|
188
|
+
</ol>
|
189
|
+
</li>
|
190
|
+
|
191
|
+
<li>
|
192
|
+
<a href="chapter-11.html">
|
169
193
|
Service Factories
|
170
194
|
</a>
|
171
195
|
|
172
196
|
<ol type="1">
|
173
197
|
|
174
|
-
<li><a href="chapter-
|
198
|
+
<li><a href="chapter-11.html#s1">Schemas</a></li>
|
175
199
|
|
176
|
-
<li><a href="chapter-
|
200
|
+
<li><a href="chapter-11.html#s2">How do they work?</a></li>
|
177
201
|
|
178
|
-
<li><a href="chapter-
|
202
|
+
<li><a href="chapter-11.html#s3">BuilderFactory</a></li>
|
179
203
|
|
180
204
|
</ol>
|
181
205
|
</li>
|
182
206
|
|
183
207
|
<li>
|
184
|
-
<a href="chapter-
|
208
|
+
<a href="chapter-12.html">
|
185
209
|
Schemas
|
186
210
|
</a>
|
187
211
|
|
188
212
|
<ol type="1">
|
189
213
|
|
190
|
-
<li><a href="chapter-
|
214
|
+
<li><a href="chapter-12.html#s1">Basic Format</a></li>
|
191
215
|
|
192
|
-
<li><a href="chapter-
|
216
|
+
<li><a href="chapter-12.html#s2">Subschemas</a></li>
|
193
217
|
|
194
|
-
<li><a href="chapter-
|
218
|
+
<li><a href="chapter-12.html#s3">Arrays</a></li>
|
195
219
|
|
196
|
-
<li><a href="chapter-
|
220
|
+
<li><a href="chapter-12.html#s4">Named vs. Anonymous Schemas</a></li>
|
197
221
|
|
198
|
-
<li><a href="chapter-
|
222
|
+
<li><a href="chapter-12.html#s5">Extending Schemas</a></li>
|
199
223
|
|
200
|
-
<li><a href="chapter-
|
224
|
+
<li><a href="chapter-12.html#s6">Limitations</a></li>
|
201
225
|
|
202
226
|
</ol>
|
203
227
|
</li>
|
204
228
|
|
205
229
|
<li>
|
206
|
-
<a href="chapter-
|
230
|
+
<a href="chapter-13.html">
|
207
231
|
Listeners and Event Producers
|
208
232
|
</a>
|
209
233
|
|
210
234
|
<ol type="1">
|
211
235
|
|
212
|
-
<li><a href="chapter-
|
236
|
+
<li><a href="chapter-13.html#s1">Event Producers</a></li>
|
213
237
|
|
214
|
-
<li><a href="chapter-
|
238
|
+
<li><a href="chapter-13.html#s2">Listeners</a></li>
|
215
239
|
|
216
|
-
<li><a href="chapter-
|
240
|
+
<li><a href="chapter-13.html#s3">The Registry as an Event Producer</a></li>
|
217
241
|
|
218
242
|
</ol>
|
219
243
|
</li>
|
@@ -303,11 +327,160 @@
|
|
303
327
|
|
304
328
|
|
305
329
|
<div class="section">
|
306
|
-
<p>Copland is an <em>Inversion of Control</em> (IoC) container, written in <a href="http://www.ruby-lang.org">Ruby</a>, for use in Ruby programs.
|
330
|
+
<p>Copland is an <em>Inversion of Control</em> (IoC) container, written in <a href="http://www.ruby-lang.org">Ruby</a>, for use in Ruby programs. In a nutshell, it allows you to simplify the instantiation and initialization of your classes.<br />
|
331
|
+
</p>
|
332
|
+
</div>
|
333
|
+
|
334
|
+
|
335
|
+
|
336
|
+
<h2>
|
337
|
+
<a name="s2"></a>
|
338
|
+
1.2. What Can Copland Do For Me?
|
339
|
+
</h2>
|
340
|
+
|
341
|
+
|
342
|
+
|
343
|
+
<div class="section">
|
344
|
+
<p>So, what can Copland do for you? Ultimately, it can reduce the amount of code that you have to write, simplifying many common programming tasks for you. This has the two-fold benefit of both decreasing application development time, and of decreasing the effort needed to maintain your application.</p>
|
345
|
+
|
346
|
+
<p>But what, <em>specifically</em>, can Copland do for you?</p>
|
347
|
+
|
348
|
+
<p>Try these on for size:</p>
|
349
|
+
|
350
|
+
<ul>
|
351
|
+
<li><a href="#logmethods">Log Method Execution</a></li>
|
352
|
+
<li><a href="#refsvc">Reference Another Service</a></li>
|
353
|
+
<li><a href="#svcconfig">Service Configuration</a></li>
|
354
|
+
<li><a href="#unittest">Unit Testing</a></li>
|
355
|
+
<li><a href="#lifecycle">Lifecycle Management</a></li>
|
356
|
+
</ul>
|
357
|
+
|
358
|
+
<p>(Thanks to Howard Lewis Ship for his <a href="http://jakarta.apache.org/hivemind">HiveMind</a> documentation, from which most of the above bullet points were adapted.)</p>
|
359
|
+
|
360
|
+
<h3>A. Log Method Execution <a name="logmethods"></a></h3>
|
361
|
+
|
362
|
+
<p>Copland has an integrated logging framework, and the ability to log execution trace information <em>without modifying a single line of your code</em>. This means that you can easily see what methods get called, with what arguments, and what the return values are, all without having to add a single line of logging code to your classes.</p>
|
363
|
+
|
364
|
+
<p>Consider the following code, demonstrating how this would be done <em>without</em> Copland:</p>
|
365
|
+
|
366
|
+
<pre>
|
367
|
+
def foo( arg1, arg2 )
|
368
|
+
@log.debug( "in foo with #{arg1} and #{arg2}" ) if @log.debug?
|
369
|
+
...
|
370
|
+
result = the_result_of_the_method
|
371
|
+
@log.debug( "finishing foo with #{result}" ) if @log.debug
|
372
|
+
return result
|
373
|
+
rescue Exception => e
|
374
|
+
@log.debug( "foo raised exception #{e.message} (#{e.class})" ) if @log.debug?
|
375
|
+
raise
|
376
|
+
end
|
377
|
+
</pre>
|
378
|
+
|
379
|
+
<p>Now, multiply that by the number of methods in your class… the logging messages quickly overpower the rest of the code, and detract from the flow of your program. This makes your program harder to debug, test, and maintain.</p>
|
380
|
+
|
381
|
+
<p>Now, consider the same method using Copland’s integrated logging framework…</p>
|
382
|
+
|
383
|
+
<pre>
|
384
|
+
def foo( arg1, arg2 )
|
385
|
+
...
|
386
|
+
return the_result_of_the_method
|
387
|
+
end
|
388
|
+
</pre>
|
389
|
+
|
390
|
+
<p>Uh, huh. That’s right. <em>There’s no explicit logging code in there.</em> Instead, you just tell Copland that the methods of the class should be logged, and away it goes. This has the added benefit of allowing your objects to be unit tested, without spewing log messages everywhere. (Look for the tutorial about “Logging Interceptors” for an actual demonstration of how to do this.)</p>
|
391
|
+
|
392
|
+
<h3>B. Reference Another Service <a name="refsvc"></a></h3>
|
393
|
+
|
394
|
+
<p>Invariably in a large application services will reference other services. This is typically accomplished through something like this:</p>
|
395
|
+
|
396
|
+
<pre>
|
397
|
+
def foo( parms )
|
398
|
+
@service ||= lookup_service
|
399
|
+
@service.do_something( parms )
|
400
|
+
end
|
401
|
+
</pre>
|
402
|
+
|
403
|
+
<p>Whether the lookup is done lazily, as shown above, or when the class is first instantiated is irrelevant. The point is that you either have to implement a bunch of code to look up a service based on some criteria, or you hard code the class of the service (which creates tight coupling and makes things like unit testing harder).</p>
|
404
|
+
|
405
|
+
<p>With Copland, you just declare a setter for the service, and then tell Copland that the class depends on the other service:</p>
|
406
|
+
|
407
|
+
<pre>
|
408
|
+
attr_writer :service
|
409
|
+
|
410
|
+
def foo( parms )
|
411
|
+
@service.do_something( parms )
|
412
|
+
end
|
413
|
+
</pre>
|
414
|
+
|
415
|
+
<p>Then, when your service is instantiated, Copland will automatically look for, instantiate, and set the dependencies for you. This makes for cleaner code, and looser coupling between services.</p>
|
416
|
+
|
417
|
+
<h3>C. Service Configuration <a name="svcconfig"></a></h3>
|
418
|
+
|
419
|
+
<p>Often, a large application or library will need some way to allow different classes to be configured at runtime. Whether you have a factory class that requires the available producable classes to register themselves with it, or whether you just want to allow third-parties to be able to extend your application, you wind up implementing some form of decentralized configuration.</p>
|
420
|
+
|
421
|
+
<p>Copland allows you to define <em>configuration points</em>, which any package may then contribute values to. Furthermore, just as services can reference other services, services can reference configuration points, and Copland will manage them just like any other dependency.</p>
|
422
|
+
|
423
|
+
<p>See the tutorial about “Configuration Points” for an example of this feature.</p>
|
424
|
+
|
425
|
+
<h3>D. Unit Testing <a name="unittest"></a></h3>
|
426
|
+
|
427
|
+
<p>Large applications can prove troublesome to unit test exhaustively, especially if there is any kind of tight coupling between components. Such coupling of components can make it difficult to test them separately.</p>
|
428
|
+
|
429
|
+
<p>Copland, by its very nature, encourages loose coupling of components. Also, because dependencies are never instantiated in code, but are instead accepted via setters or constructor arguments, it is trivial to replace those dependencies with mock objects at unit test time.</p>
|
430
|
+
|
431
|
+
<p>Consider this tightly coupled example:</p>
|
432
|
+
|
433
|
+
<pre>
|
434
|
+
def foo( args )
|
435
|
+
@some_dependency ||= MyNewDependency.new
|
436
|
+
@some_dependency.do_something(args)
|
437
|
+
end
|
438
|
+
</pre>
|
439
|
+
|
440
|
+
<p>It is impossible to test the method <code>#foo</code> without also testing the MyNewDependency class. However, if the <code>@some_dependency</code> object is made a property that is set externally, you can replace it at test time with a blank:</p>
|
441
|
+
|
442
|
+
<pre>
|
443
|
+
attr_writer :some_dependency
|
444
|
+
|
445
|
+
def foo( args )
|
446
|
+
@some_dependency.do_something( args )
|
447
|
+
end
|
448
|
+
</pre>
|
449
|
+
|
450
|
+
<p>The unit test would become something like this:</p>
|
451
|
+
|
452
|
+
<pre>
|
453
|
+
def test_foo
|
454
|
+
@obj.some_dependecy = MyMockDependency.new
|
455
|
+
@obj.foo( args )
|
456
|
+
assert @obj.is_in_some_state
|
457
|
+
end
|
458
|
+
</pre>
|
459
|
+
|
460
|
+
<h3>E. Lifecycle Management <a name="lifecycle"></a></h3>
|
307
461
|
|
308
|
-
<
|
462
|
+
<p>Singleton objects are a fact of life in complex systems. The singleton design pattern is powerful and useful. However, using the Singleton mixin, or declaring methods at the class level, can make your code difficult to unit test since the state of such objects cannot be easily reset.</p>
|
309
463
|
|
310
|
-
<p>
|
464
|
+
<p>Copland has a solution. You can tell Copland to treat a service as either a <em>prototype</em> service (meaning it will be instantiated every time you ask for it, like calling <code>#new</code>), or a <em>singleton</em> service (meaning it will only be instantiated once, and the same instance will be returned for subsequent requests).</p>
|
465
|
+
|
466
|
+
<p>Your object is still just a plain ol’ ordinary Ruby object, but Copland has effectively transformed it into a singleton. This means you can unit test it as if it were nothing special, but when it is used in your application it will act like a singleton.</p>
|
467
|
+
|
468
|
+
<p>Lifecycle management also means that you can control <em>when</em> a service is instantiated. The <em>prototype</em> and <em>singleton</em> models will always be instantiated as soon as they are requested. Sometimes, though, you don’t want that—you’d like the instantiation to be deferred as long as possible.</p>
|
469
|
+
|
470
|
+
<p>With Copland, you can indicate that a service should use deferred instantiation. This will cause the service to not actually be instantiated until a method is actually invoked on it. Using this model, you can have services depend on themselves, or other forms of cyclical dependencies.</p>
|
471
|
+
</div>
|
472
|
+
|
473
|
+
|
474
|
+
|
475
|
+
<h2>
|
476
|
+
<a name="s3"></a>
|
477
|
+
1.3. Copland <em>sans</em> Buzzwords
|
478
|
+
</h2>
|
479
|
+
|
480
|
+
|
481
|
+
|
482
|
+
<div class="section">
|
483
|
+
<p>Imagine being able to take all the various pieces of your program and implement them in a vacuum. You just assume that all dependencies will be satisfied at runtime, by properties being set, or parameters being passed to each object’s constructor. Nowhere in your code do you specify the instantiation of another application component.</p>
|
311
484
|
|
312
485
|
<p>However, those dependencies and relationships between objects <em>still exist</em>; you’ve just written your code without any explicit knowledge of them. Somehow, you still need to be able to wire the pieces all together so they work as required in tandem. To put it another way, you need to be able to take your classes and <em>compose</em> them into something greater.</p>
|
313
486
|
|
@@ -321,10 +494,19 @@
|
|
321
494
|
<li>It helps you to focus on the implementation of a single class by allowing you to ignore the implementation details of the dependencies of the current class.</li>
|
322
495
|
<li>It helps you to focus on the relationships between classes by allowing you to specify those relationships and dependencies as run-time configuration options.</li>
|
323
496
|
</ol>
|
497
|
+
</div>
|
324
498
|
|
325
|
-
<h3>Copland <em>avec</em> Buzzwords</h3>
|
326
499
|
|
327
|
-
|
500
|
+
|
501
|
+
<h2>
|
502
|
+
<a name="s4"></a>
|
503
|
+
1.4. Copland <em>avec</em> Buzzwords
|
504
|
+
</h2>
|
505
|
+
|
506
|
+
|
507
|
+
|
508
|
+
<div class="section">
|
509
|
+
<p>If you are already familiar with IoC, then you either love it or hate it. In the first case, you probably only want to know what features Copland has compared to other IoC containers you’ve used. In the second case, there’s probably not much I can say to change your opinion, so I won’t try.</p>
|
328
510
|
|
329
511
|
<p>I’ll save all the meaty discussions for the chapter on Copland’s design, but here’s the rundown:</p>
|
330
512
|
|
@@ -333,10 +515,19 @@
|
|
333
515
|
<li>Copland allows you to define <em>service points</em>, <em>configuration points</em>, contribute to <em>configuration points</em>, add <em>interceptors</em> to services, add <em>listeners</em> to services, define <em>multicast</em> services, and even make your services web-enabled by using the built-in <span class="caps">SOAP</span> or dRuby interfaces.</li>
|
334
516
|
<li>Copland uses <a href="http://www.yaml.org">YAML</a> for its configuration files, instead of <span class="caps">XML</span>. If you’ve never used <span class="caps">YAML</span>, you’ll find it surprisingly easy to pick up.</li>
|
335
517
|
</ul>
|
518
|
+
</div>
|
519
|
+
|
520
|
+
|
521
|
+
|
522
|
+
<h2>
|
523
|
+
<a name="s5"></a>
|
524
|
+
1.5. The Buzzwords Themselves
|
525
|
+
</h2>
|
336
526
|
|
337
|
-
|
527
|
+
|
338
528
|
|
339
|
-
|
529
|
+
<div class="section">
|
530
|
+
<p>As <a href="http://www.martinfowler.com">Martin Fowler</a> <a href="http://martinfowler.com/articles/injection.html">points out</a>, the term “Inversion of Control” is a poorly-chosen one. Still, it is the one that most people know the concept by, so I’ll use it throughout this document.</p>
|
340
531
|
|
341
532
|
<p>For more info about IoC, you might try reading the following articles:</p>
|
342
533
|
|
@@ -350,8 +541,8 @@
|
|
350
541
|
|
351
542
|
|
352
543
|
<h2>
|
353
|
-
<a name="
|
354
|
-
1.
|
544
|
+
<a name="s6"></a>
|
545
|
+
1.6. Features
|
355
546
|
</h2>
|
356
547
|
|
357
548
|
|
@@ -375,8 +566,8 @@
|
|
375
566
|
|
376
567
|
|
377
568
|
<h2>
|
378
|
-
<a name="
|
379
|
-
1.
|
569
|
+
<a name="s7"></a>
|
570
|
+
1.7. Getting Copland
|
380
571
|
</h2>
|
381
572
|
|
382
573
|
|
@@ -416,8 +607,8 @@
|
|
416
607
|
|
417
608
|
|
418
609
|
<h2>
|
419
|
-
<a name="
|
420
|
-
1.
|
610
|
+
<a name="s8"></a>
|
611
|
+
1.8. License Information
|
421
612
|
</h2>
|
422
613
|
|
423
614
|
|
@@ -432,8 +623,8 @@
|
|
432
623
|
|
433
624
|
|
434
625
|
<h2>
|
435
|
-
<a name="
|
436
|
-
1.
|
626
|
+
<a name="s9"></a>
|
627
|
+
1.9. Support
|
437
628
|
</h2>
|
438
629
|
|
439
630
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<html>
|
2
2
|
<head>
|
3
|
-
<title>Copland Manual :: Chapter 10:
|
3
|
+
<title>Copland Manual :: Chapter 10: Logging</title>
|
4
4
|
<link type="text/css" rel="stylesheet" href="manual.css" />
|
5
5
|
</head>
|
6
6
|
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Copland Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-
|
17
|
+
Copland Version: <strong>1.0.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-12 02:22 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -39,13 +39,21 @@
|
|
39
39
|
|
40
40
|
<li><a href="chapter-1.html#s1">What is Copland?</a></li>
|
41
41
|
|
42
|
-
<li><a href="chapter-1.html#s2">
|
42
|
+
<li><a href="chapter-1.html#s2">What Can Copland Do For Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Copland <em>sans</em> Buzzwords</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">Copland <em>avec</em> Buzzwords</a></li>
|
47
47
|
|
48
|
-
<li><a href="chapter-1.html#s5">
|
48
|
+
<li><a href="chapter-1.html#s5">The Buzzwords Themselves</a></li>
|
49
|
+
|
50
|
+
<li><a href="chapter-1.html#s6">Features</a></li>
|
51
|
+
|
52
|
+
<li><a href="chapter-1.html#s7">Getting Copland</a></li>
|
53
|
+
|
54
|
+
<li><a href="chapter-1.html#s8">License Information</a></li>
|
55
|
+
|
56
|
+
<li><a href="chapter-1.html#s9">Support</a></li>
|
49
57
|
|
50
58
|
</ol>
|
51
59
|
</li>
|
@@ -149,7 +157,9 @@
|
|
149
157
|
|
150
158
|
<li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
|
151
159
|
|
152
|
-
<li><a href="chapter-8.html#s2">
|
160
|
+
<li><a href="chapter-8.html#s2">FactoryDefaults</a></li>
|
161
|
+
|
162
|
+
<li><a href="chapter-8.html#s3">ApplicationDefaults</a></li>
|
153
163
|
|
154
164
|
</ol>
|
155
165
|
</li>
|
@@ -166,54 +176,68 @@
|
|
166
176
|
|
167
177
|
<li><strong>
|
168
178
|
<a href="chapter-10.html">
|
169
|
-
|
179
|
+
Logging
|
170
180
|
</a>
|
171
181
|
</strong> <big>←</big>
|
172
182
|
<ol type="1">
|
173
183
|
|
174
|
-
<li><a href="chapter-10.html#s1">
|
184
|
+
<li><a href="chapter-10.html#s1">Log Factory</a></li>
|
175
185
|
|
176
|
-
<li><a href="chapter-10.html#s2">
|
177
|
-
|
178
|
-
<li><a href="chapter-10.html#s3">BuilderFactory</a></li>
|
186
|
+
<li><a href="chapter-10.html#s2">Configuration</a></li>
|
179
187
|
|
180
188
|
</ol>
|
181
189
|
</li>
|
182
190
|
|
183
191
|
<li>
|
184
192
|
<a href="chapter-11.html">
|
193
|
+
Service Factories
|
194
|
+
</a>
|
195
|
+
|
196
|
+
<ol type="1">
|
197
|
+
|
198
|
+
<li><a href="chapter-11.html#s1">Schemas</a></li>
|
199
|
+
|
200
|
+
<li><a href="chapter-11.html#s2">How do they work?</a></li>
|
201
|
+
|
202
|
+
<li><a href="chapter-11.html#s3">BuilderFactory</a></li>
|
203
|
+
|
204
|
+
</ol>
|
205
|
+
</li>
|
206
|
+
|
207
|
+
<li>
|
208
|
+
<a href="chapter-12.html">
|
185
209
|
Schemas
|
186
210
|
</a>
|
187
211
|
|
188
212
|
<ol type="1">
|
189
213
|
|
190
|
-
<li><a href="chapter-
|
214
|
+
<li><a href="chapter-12.html#s1">Basic Format</a></li>
|
191
215
|
|
192
|
-
<li><a href="chapter-
|
216
|
+
<li><a href="chapter-12.html#s2">Subschemas</a></li>
|
193
217
|
|
194
|
-
<li><a href="chapter-
|
218
|
+
<li><a href="chapter-12.html#s3">Arrays</a></li>
|
195
219
|
|
196
|
-
<li><a href="chapter-
|
220
|
+
<li><a href="chapter-12.html#s4">Named vs. Anonymous Schemas</a></li>
|
197
221
|
|
198
|
-
<li><a href="chapter-
|
222
|
+
<li><a href="chapter-12.html#s5">Extending Schemas</a></li>
|
199
223
|
|
200
|
-
<li><a href="chapter-
|
224
|
+
<li><a href="chapter-12.html#s6">Limitations</a></li>
|
201
225
|
|
202
226
|
</ol>
|
203
227
|
</li>
|
204
228
|
|
205
229
|
<li>
|
206
|
-
<a href="chapter-
|
230
|
+
<a href="chapter-13.html">
|
207
231
|
Listeners and Event Producers
|
208
232
|
</a>
|
209
233
|
|
210
234
|
<ol type="1">
|
211
235
|
|
212
|
-
<li><a href="chapter-
|
236
|
+
<li><a href="chapter-13.html#s1">Event Producers</a></li>
|
213
237
|
|
214
|
-
<li><a href="chapter-
|
238
|
+
<li><a href="chapter-13.html#s2">Listeners</a></li>
|
215
239
|
|
216
|
-
<li><a href="chapter-
|
240
|
+
<li><a href="chapter-13.html#s3">The Registry as an Event Producer</a></li>
|
217
241
|
|
218
242
|
</ol>
|
219
243
|
</li>
|
@@ -291,101 +315,150 @@
|
|
291
315
|
|
292
316
|
<div id="content">
|
293
317
|
|
294
|
-
<h1>10.
|
318
|
+
<h1>10. Logging</h1>
|
295
319
|
|
296
320
|
|
297
321
|
|
298
322
|
<div class="section">
|
299
|
-
<p>
|
300
|
-
|
301
|
-
<p>A service factory is just a regular service as far as Copland is concerned. It is declared in the usual way. However, a service that will be used as a service factory must implement at least one method: <code>#create_instance</code>. This method should accept two parameters, the <em>service point</em> to instantiate, and the <em>parameters</em> associated with this instantiation. (The <code>parameters</code> parameter will always be a hash.)</p>
|
302
|
-
|
303
|
-
<p>Here is an example that implements a trivial service factory:</p>
|
304
|
-
|
305
|
-
<pre>
|
306
|
-
class ExampleServiceFactory
|
307
|
-
|
308
|
-
def create_instance( point, parms )
|
309
|
-
return { :point => point,
|
310
|
-
:parms => parms }
|
311
|
-
end
|
312
|
-
|
313
|
-
end
|
314
|
-
</pre>
|
323
|
+
<p>Copland has an integrated logging system based on a slight variation of Ruby’s own “logger” library. In addition to the features of that library, Copland’s logging system provides:</p>
|
315
324
|
|
316
|
-
<
|
325
|
+
<ul>
|
326
|
+
<li>A logger factory for creating shared logger instances</li>
|
327
|
+
<li><span class="caps">YAML</span>-based configuration of the factory</li>
|
328
|
+
<li>Customizable message formatting</li>
|
329
|
+
</ul>
|
330
|
+
</div>
|
317
331
|
|
318
|
-
<pre>
|
319
|
-
---
|
320
|
-
id: example
|
321
332
|
|
322
|
-
service-points:
|
323
333
|
|
324
|
-
|
325
|
-
|
326
|
-
|
334
|
+
<h2>
|
335
|
+
<a name="s1"></a>
|
336
|
+
10.1. Log Factory
|
337
|
+
</h2>
|
327
338
|
|
328
|
-
|
339
|
+
|
329
340
|
|
330
|
-
<
|
331
|
-
|
332
|
-
id: demo
|
341
|
+
<div class="section">
|
342
|
+
<p>Each registry instance has its own instance of <code>Copland::LogFactory</code>. This provides a way to map a name to a logger instance, and allows each service point (for example) to have its own logger instance. This allows various logger settings to be tweaked <em>per service-point</em>.</p>
|
333
343
|
|
334
|
-
|
344
|
+
<p>For example, if I want debugging information to be logged for one service point, but not for another, I can specify the logging priority level for the one service point to include debug messages, and have such messages excluded for the other service point.</p>
|
335
345
|
|
336
|
-
|
337
|
-
implementor:
|
338
|
-
factory: example.ExampleServiceFactory
|
339
|
-
</pre>
|
346
|
+
<p>The log factory allows default values to be set for the priority level, date format string, and message format string, which will be applied to any logger that does not have a specific value set for those values. The log factory also allows configuration of the IO device to log to, the filename to log to, and various other (Logger-specific) data items (see the <span class="caps">API</span> documentation for <code>Copland::LogFactory</code> for more information).</p>
|
340
347
|
|
341
|
-
<p>
|
348
|
+
<p>If you ever need to access the current log factory instance, you can get it from the registry as the <code>copland.LogFactory</code> service.<br />
|
342
349
|
</p>
|
343
350
|
</div>
|
344
351
|
|
345
352
|
|
346
353
|
|
347
354
|
<h2>
|
348
|
-
<a name="
|
349
|
-
10.
|
355
|
+
<a name="s2"></a>
|
356
|
+
10.2. Configuration
|
350
357
|
</h2>
|
351
358
|
|
352
359
|
|
353
360
|
|
354
361
|
<div class="section">
|
355
|
-
<p>
|
356
|
-
</p>
|
357
|
-
</div>
|
362
|
+
<p>There are three ways to configure loggers. The first is programmatically, manually tweaking each log instance directly. The second is to pass configuration options to the registry itself when it is built, and the third is to use a configuration file.</p>
|
358
363
|
|
364
|
+
<h3>Programmatic Configuration</h3>
|
359
365
|
|
366
|
+
<p>To programmatically configure a logger, just obtain a handle to a logger instance and then tweak it via the accessor methods of the logger:</p>
|
360
367
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
</h2>
|
368
|
+
<pre>
|
369
|
+
factory = registry.service( "copland.LogFactory" )
|
370
|
+
log = factory.get( "some.log.name" )
|
365
371
|
|
366
|
-
|
372
|
+
# Standard Logger attributes
|
373
|
+
log.level = Logger::INFO
|
374
|
+
log.progname = "different.log.name"
|
375
|
+
log.datetime_format = "%Y%m%d"
|
367
376
|
|
368
|
-
|
369
|
-
|
377
|
+
# Extended Logger attributes (provided by Copland)
|
378
|
+
log.message_format = "[%-5p] %d %c: %m"
|
379
|
+
</pre>
|
370
380
|
|
371
|
-
<p>
|
372
|
-
</p>
|
373
|
-
</div>
|
381
|
+
<p><em>Note:</em> programmatically changing the logger <code>progname</code> does not change the name by which the logger is known to the factory!</p>
|
374
382
|
|
383
|
+
<p>In general, programmatic tweaking of the logger attributes as demonstrated above is not going to be the best way to do it. First of all, it is tedious, and bug prone. Secondly, it is difficult to know where the best place to do such work is, since you need to set those attributes before any other service tries to access that log.</p>
|
375
384
|
|
385
|
+
<h3>Configuration via <code>Registry.build</code></h3>
|
376
386
|
|
377
|
-
|
378
|
-
<a name="s3"></a>
|
379
|
-
10.3. BuilderFactory
|
380
|
-
</h2>
|
387
|
+
<p>The second approach is to pass logger configuration options to <code>Registry.build</code>, when you create a registry instance:</p>
|
381
388
|
|
382
|
-
|
389
|
+
<pre>
|
390
|
+
registry = Copland::Registry.build(
|
391
|
+
:log_device => STDOUT,
|
392
|
+
:log_default_level => Logger::INFO,
|
393
|
+
...
|
394
|
+
)
|
395
|
+
</pre>
|
383
396
|
|
384
|
-
|
385
|
-
|
397
|
+
<p>This gives you much greater flexibility than the previous approach, since it allows you to specify a greater array of options. The allowed options are:</p>
|
398
|
+
|
399
|
+
<table class="list">
|
400
|
+
<tr>
|
401
|
+
<td style="vertical-align:top;"><code>:log_config_file</code></td>
|
402
|
+
<td>This is the name of the configuration file to use to configure the log factory. It defaults to “logger.yml”. (See the next section for more information.)</td>
|
403
|
+
</tr>
|
404
|
+
<tr>
|
405
|
+
<td style="vertical-align:top;"><code>:log_device</code></td>
|
406
|
+
<td>This is the <span class="caps">IO </span>(or pseudo-IO) object to write log messages to. If this option is specified, <code>:log_filename</code> must not be specified (and vice versa). This allows you to log messages to arbitrary IO streams.</td>
|
407
|
+
</tr>
|
408
|
+
<tr>
|
409
|
+
<td style="vertical-align:top;"><code>:log_filename</code></td>
|
410
|
+
<td>This is the name of the file to write log messages to. If this option is specified, <code>:log_device</code> must not be specified (and vice versa). This defaults to ”./copland.log”.</td>
|
411
|
+
</tr>
|
412
|
+
<tr>
|
413
|
+
<td style="vertical-align:top;"><code>:log_roll_age</code></td>
|
414
|
+
<td>This specifies the number of days before the log should be rolled. (This option is only useful when used with <code>:log_filename</code>.)</td>
|
415
|
+
</tr>
|
416
|
+
<tr>
|
417
|
+
<td style="vertical-align:top;"><code>:log_roll_frequency</code></td>
|
418
|
+
<td>This should be either <code>nil</code>, “daily”, “weekly”, or “monthly”, and specifies how frequently the log should be rolled. This option cannot be used with <code>:log_roll_age</code>.</td>
|
419
|
+
</tr>
|
420
|
+
<tr>
|
421
|
+
<td style="vertical-align:top;"><code>:log_roll_size</code></td>
|
422
|
+
<td>This specifies the maximum size of a log file. Once the log file gets larger than this value, the log will be rolled. (This option is only useful when used with <code>:log_filename</code>.)</td>
|
423
|
+
</tr>
|
424
|
+
<tr>
|
425
|
+
<td style="vertical-align:top;"><code>:log_default_date_format</code></td>
|
426
|
+
<td>This is the default date format string to use for the loggers that are created. It may be any string that is understood by <code>Time#strftime</code>. If <code>nil</code> (the default), then the default Logger date format string will be used.</td>
|
427
|
+
</tr>
|
428
|
+
<tr>
|
429
|
+
<td style="vertical-align:top;"><code>:log_default_message_format</code></td>
|
430
|
+
<td>This is the default message format string to use for the loggers that are created. It is a printf-styled string with special format specifiers—see the <span class="caps">API</span> documentation for <code>Copland::Logger#message_format=</code> for the available specifiers.</td>
|
431
|
+
</tr>
|
432
|
+
<tr>
|
433
|
+
<td style="vertical-align:top;"><code>:log_default_level</code></td>
|
434
|
+
<td>This is the default level for each logger. Messages that are logged below this level (also “priority” or “severity”) will not be logged. By default, all messages are logged.</td>
|
435
|
+
</tr>
|
436
|
+
<tr>
|
437
|
+
<td style="vertical-align:top;"><code>:log_levels</code></td>
|
438
|
+
<td>This is a hash. Each key should be a string containing a regular expression. For every logger whose name matches one of these patterns, the corresponding value will be used to define specific values for that logger. The value for each key must either be a string (in which case it is the name of the severity level to use), or a hash (containing any of the keys “level”, “date-format”, or “message-format”).</td>
|
439
|
+
</tr>
|
440
|
+
</table>
|
441
|
+
|
442
|
+
<h3>Configuration via <span class="caps">YAML</span></h3>
|
443
|
+
|
444
|
+
<p>The third option (and the most flexible) is to use a <span class="caps">YAML</span> configuration file to define the parameters of the log factory and its loggers. By default, this file is called “logger.yml”, but you can specify a different logger configuration file via the <code>:log_config_file</code> option to <code>Copland::Registry.build</code>. By default, the configuration file must reside in current working directory, but you can specify an explicit path in the string you give to <code>:log_config_file</code>.</p>
|
445
|
+
|
446
|
+
<p>The file has options that correspond to the configuration parameters described above:</p>
|
386
447
|
|
387
|
-
|
388
|
-
|
448
|
+
<pre>
|
449
|
+
---
|
450
|
+
filename: log/filename.log
|
451
|
+
roll-age: 5
|
452
|
+
default-date-format: %Y%m%d%H%M%S
|
453
|
+
default-message-format: %p %d %t %C: %m (%l)
|
454
|
+
default-level: DEBUG
|
455
|
+
levels:
|
456
|
+
copland.*: WARN
|
457
|
+
project.*:
|
458
|
+
level: INFO
|
459
|
+
date-format: %Y%m%d::%H%M%S
|
460
|
+
message-format: %p %d: %m
|
461
|
+
</pre>
|
389
462
|
</div>
|
390
463
|
|
391
464
|
|