semantic_logger 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +1 -1
- data/README.md +162 -159
- data/Rakefile +6 -5
- data/lib/semantic_logger.rb +1 -3
- data/lib/semantic_logger/appender/file.rb +9 -9
- data/lib/semantic_logger/appender/wrapper.rb +6 -6
- data/lib/semantic_logger/base.rb +13 -16
- data/lib/semantic_logger/loggable.rb +55 -3
- data/lib/semantic_logger/logger.rb +17 -47
- data/lib/semantic_logger/semantic_logger.rb +135 -0
- data/lib/semantic_logger/version.rb +1 -1
- data/test/loggable_test.rb +5 -5
- data/test/logger_test.rb +14 -13
- metadata +22 -52
- data/Gemfile.lock +0 -33
- data/nbproject/private/config.properties +0 -0
- data/nbproject/private/private.properties +0 -1
- data/nbproject/private/private.xml +0 -4
- data/nbproject/private/rake-d.txt +0 -4
- data/nbproject/project.properties +0 -7
- data/nbproject/project.xml +0 -16
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4f813c09eacb56b09335612d00c499738d0ee84c
|
4
|
+
data.tar.gz: ad074b21691cac740d8c0c6272d4263f4c41421a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1211db34d7bc22f0f6c319b636a67decd6a23717568778b7f77413826b4940a3e1c699685e0890cb64c54e5e65a9d677a7923e54935a5203de76ef671a9cb0bd
|
7
|
+
data.tar.gz: d940844e714486e76be5e5e6b839c3ccaedc66566781b2b8a9d51c09eb4b077652e7b2db0bce1004a3b41098143d9cd263aa6eb16b64a968b1278ef1455fb4d9
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Improved logging for Ruby
|
|
9
9
|
|
10
10
|
As of SemanticLogger V2.0 the Rails logging is no longer automatically replaced
|
11
11
|
when including SemanticLogger. Include the [rails_semantic_logger](http://github.com/ClarityServices/rails_semantic_logger)
|
12
|
-
to replace the Rails default logger with SemanticLogger
|
12
|
+
gem to replace the Rails default logger with SemanticLogger
|
13
13
|
|
14
14
|
### Overview
|
15
15
|
|
@@ -61,13 +61,6 @@ Drop-in Replacement
|
|
61
61
|
* Supports current common logging interface
|
62
62
|
* No changes to existing to code to use new logger ( other than replacing the logger )
|
63
63
|
|
64
|
-
Rails 2 & 3 Support
|
65
|
-
|
66
|
-
* Just include the semantic_logger gem into Rails and it will immediately
|
67
|
-
replace the existing loggers to improve performance and information
|
68
|
-
in the log files
|
69
|
-
* The Rails 3 Tagged logging feature is already available for Rails 2 by use Semantic Logger
|
70
|
-
|
71
64
|
Thread Aware
|
72
65
|
|
73
66
|
* Includes the process and thread id information in every log entry
|
@@ -172,7 +165,7 @@ similar text output.
|
|
172
165
|
This can be changed over time to:
|
173
166
|
|
174
167
|
```ruby
|
175
|
-
|
168
|
+
logger.info("Queried table",
|
176
169
|
:duration => duration,
|
177
170
|
:result => result,
|
178
171
|
:table => "users",
|
@@ -240,7 +233,7 @@ logger.debug { "A total of #{result.inject(0) {|sum, i| i+sum }} were processed"
|
|
240
233
|
|
241
234
|
### Exceptions
|
242
235
|
|
243
|
-
The Semantic Logger adds an
|
236
|
+
The Semantic Logger adds an optional parameter to the existing log methods so that
|
244
237
|
a corresponding Exception can be logged in a standard way
|
245
238
|
|
246
239
|
```ruby
|
@@ -350,7 +343,7 @@ loggers for Rails, ActiveRecord::Base, ActionController::Base, and ActiveResourc
|
|
350
343
|
with wrappers that set their Class name. For example in semantic_logger/railtie.rb:
|
351
344
|
|
352
345
|
```ruby
|
353
|
-
ActiveRecord::Base.logger = SemanticLogger
|
346
|
+
ActiveRecord::Base.logger = SemanticLogger[ActiveRecord]
|
354
347
|
```
|
355
348
|
|
356
349
|
By replacing their loggers we now get the class name in the text logging output:
|
@@ -382,29 +375,6 @@ This will result in the log output identifying the log entry as from the Externa
|
|
382
375
|
|
383
376
|
2012-08-30 15:37:29.474 I [48308:ScriptThreadProcess: script/rails] (5.2ms) ExternalSupplier -- Calling external interface
|
384
377
|
|
385
|
-
[SyncAttr](https://github.com/ClarityServices/sync_attr) is a gem that supports
|
386
|
-
lazy loading and thread-safe initialization of class attributes
|
387
|
-
|
388
|
-
Extract from a Rails log file after adding the semantic_logger gem:
|
389
|
-
|
390
|
-
```
|
391
|
-
2012-10-19 12:05:46.736 I [35940:JRubyWorker-10] Rails --
|
392
|
-
|
393
|
-
Started GET "/" for 127.0.0.1 at 2012-10-19 12:05:46 +0000
|
394
|
-
2012-10-19 12:05:47.318 I [35940:JRubyWorker-10] ActionController -- Processing by AdminController#index as HTML
|
395
|
-
2012-10-19 12:05:47.633 D [35940:JRubyWorker-10] ActiveRecord -- User Load (2.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
|
396
|
-
2012-10-19 12:05:49.833 D [35940:JRubyWorker-10] ActiveRecord -- Role Load (2.0ms) SELECT `roles`.* FROM `roles`
|
397
|
-
2012-10-19 12:05:49.868 D [35940:JRubyWorker-10] ActiveRecord -- Role Load (1.0ms) SELECT * FROM `roles` INNER JOIN `roles_users` ON `roles`.id = `roles_users`.role_id WHERE (`roles_users`.user_id = 1 )
|
398
|
-
2012-10-19 12:05:49.885 I [35940:JRubyWorker-10] ActionController -- Rendered menus/_control_system.html.erb (98.0ms)
|
399
|
-
2012-10-19 12:05:51.014 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_top_bar.html.erb (386.0ms)
|
400
|
-
2012-10-19 12:05:51.071 D [35940:JRubyWorker-10] ActiveRecord -- Announcement Load (20.0ms) SELECT `announcements`.* FROM `announcements` WHERE `announcements`.`active` = 1 ORDER BY created_at desc
|
401
|
-
2012-10-19 12:05:51.072 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_announcement.html.erb (26.0ms)
|
402
|
-
2012-10-19 12:05:51.083 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_flash.html.erb (4.0ms)
|
403
|
-
2012-10-19 12:05:51.109 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_footer.html.erb (16.0ms)
|
404
|
-
2012-10-19 12:05:51.109 I [35940:JRubyWorker-10] ActionController -- Rendered admin/index.html.erb within layouts/base (1329.0ms)
|
405
|
-
2012-10-19 12:05:51.113 I [35940:JRubyWorker-10] ActionController -- Completed 200 OK in 3795ms (Views: 1349.0ms | ActiveRecord: 88.0ms | Mongo: 0.0ms)
|
406
|
-
```
|
407
|
-
|
408
378
|
#### Tagged Logging
|
409
379
|
|
410
380
|
Semantic Logger allows any Ruby or Rails program to also include tagged logging.
|
@@ -439,76 +409,140 @@ logger.with_payload(:user => 'Jack', :zip_code => 12345) do
|
|
439
409
|
end
|
440
410
|
```
|
441
411
|
|
442
|
-
### Using SemanticLogger
|
412
|
+
### Using SemanticLogger
|
443
413
|
|
444
|
-
|
414
|
+
When using SemanticLogger inside of Rails all we need to do is include the
|
415
|
+
rails_semantic_logger gem and the default Rails logger will be replaced with
|
416
|
+
Semantic Logger.
|
445
417
|
|
418
|
+
In a stand-alone or non-rails environment we can easily log to a file called
|
419
|
+
'development.log' as follows:
|
446
420
|
```ruby
|
447
421
|
require 'semantic_logger'
|
422
|
+
SemanticLogger.add_appender('development.log')
|
448
423
|
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
# Add a file appender to log everything to a file
|
453
|
-
SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('dev.log')
|
424
|
+
logger = SemanticLogger['Example']
|
425
|
+
logger.info "Hello World"
|
426
|
+
```
|
454
427
|
|
455
|
-
|
456
|
-
|
428
|
+
By default it will only log :info and above, to log everything to the log file:
|
429
|
+
```ruby
|
430
|
+
require 'semantic_logger'
|
431
|
+
SemanticLogger.default_level = :trace
|
432
|
+
SemanticLogger.add_appender('development.log')
|
457
433
|
|
458
|
-
logger = SemanticLogger
|
434
|
+
logger = SemanticLogger['Example']
|
459
435
|
logger.info "Hello World"
|
436
|
+
logger.trace "Low level trace information"
|
460
437
|
```
|
461
438
|
|
462
|
-
|
439
|
+
By supplying multiple appenders Semantic Logger can write to multiple destinations
|
440
|
+
at the same time. For example, log to a file and the screen:
|
441
|
+
```ruby
|
442
|
+
require 'semantic_logger'
|
443
|
+
SemanticLogger.default_level = :trace
|
444
|
+
SemanticLogger.add_appender('development.log')
|
445
|
+
SemanticLogger.add_appender(STDOUT)
|
463
446
|
|
464
|
-
|
465
|
-
|
466
|
-
|
447
|
+
logger = SemanticLogger['Example']
|
448
|
+
logger.info "Hello World"
|
449
|
+
logger.trace "Low level trace information"
|
450
|
+
```
|
467
451
|
|
468
|
-
|
452
|
+
To reduce the log level of logging to STDOUT to just :info and above, add the
|
453
|
+
log_level such as :info as the second parameter when adding the appender:
|
454
|
+
```ruby
|
455
|
+
require 'semantic_logger'
|
456
|
+
SemanticLogger.default_level = :trace
|
457
|
+
SemanticLogger.add_appender('development.log')
|
458
|
+
SemanticLogger.add_appender(STDOUT, :info)
|
469
459
|
|
470
|
-
|
460
|
+
logger = SemanticLogger['Example']
|
461
|
+
logger.info "Hello World"
|
462
|
+
logger.trace "Low level trace information"
|
463
|
+
```
|
471
464
|
|
465
|
+
To log :debug and above to a log file, :error and above to $stderr, and :info
|
466
|
+
and above to MongoDB:
|
472
467
|
```ruby
|
473
|
-
|
474
|
-
|
468
|
+
require 'semantic_logger'
|
469
|
+
require 'mongo'
|
475
470
|
|
476
|
-
|
471
|
+
SemanticLogger.default_level = :debug
|
472
|
+
SemanticLogger.add_appender('development.log')
|
473
|
+
SemanticLogger.add_appender($stderr, :error)
|
477
474
|
|
478
|
-
|
479
|
-
|
475
|
+
mongo_appender = SemanticLogger::Appender::MongoDB.new(
|
476
|
+
:db => Mongodb::Connection.new['production_logging'],
|
477
|
+
:collection_size => 25.gigabytes
|
478
|
+
)
|
479
|
+
SemanticLogger.add_appender(mongo_appender, :info)
|
480
|
+
|
481
|
+
logger = SemanticLogger['Example']
|
482
|
+
logger.info "Hello World"
|
483
|
+
logger.trace "Low level trace information"
|
484
|
+
logger.error "Oops an error occurred"
|
485
|
+
logger.info("Login time", :user => 'Mary', :duration => 230, :ip_address=>'192.168.0.1')
|
480
486
|
```
|
481
487
|
|
482
|
-
|
488
|
+
When starting out with Semantic Logger it can be useful to gain all the benefits
|
489
|
+
of Semantic Logger and still continue to log to an existing logger:
|
490
|
+
```ruby
|
491
|
+
require 'logger'
|
492
|
+
require 'semantic_logger'
|
483
493
|
|
484
|
-
|
494
|
+
# Built-in Ruby logger
|
495
|
+
log = Logger.new(STDOUT)
|
496
|
+
log.level = Logger::DEBUG
|
485
497
|
|
486
|
-
|
487
|
-
|
498
|
+
SemanticLogger.default_level = :debug
|
499
|
+
SemanticLogger.add_appender(log)
|
488
500
|
|
489
|
-
|
490
|
-
|
491
|
-
|
501
|
+
logger = SemanticLogger['Example']
|
502
|
+
logger.info "Hello World"
|
503
|
+
logger.debug("Login time", :user => 'Joe', :duration => 100, :ip_address=>'127.0.0.1')
|
504
|
+
```
|
492
505
|
|
506
|
+
It is recommended that every class or module have it's own logging instance.
|
507
|
+
This can be achieved by including SemanticLogger::Loggable:
|
493
508
|
```ruby
|
494
|
-
|
495
|
-
|
509
|
+
require 'semantic_logger'
|
510
|
+
SemanticLogger.default_level = :trace
|
511
|
+
SemanticLogger.add_appender('development.log')
|
512
|
+
|
513
|
+
class ExternalSupplier
|
514
|
+
# Makes available a class and instance level logger
|
515
|
+
# ExternalSupplier.logger and ExternalSupplier#logger
|
516
|
+
include SemanticLogger::Loggable
|
496
517
|
|
497
|
-
|
498
|
-
|
518
|
+
# logger class method example
|
519
|
+
def self.hostname=(hostname)
|
520
|
+
logger.debug "Setting hostname to #{hostname}"
|
521
|
+
@@hostname = hostname
|
522
|
+
end
|
499
523
|
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
)
|
524
|
+
# logger instance method example
|
525
|
+
def call_supplier(amount, name)
|
526
|
+
logger.debug "Calculating with amount", { :amount => amount, :name => name }
|
527
|
+
|
528
|
+
# Measure and log on completion how long the call took to the external supplier
|
529
|
+
logger.benchmark_info "Calling external interface" do
|
530
|
+
# Code to call the external supplier ...
|
531
|
+
end
|
532
|
+
end
|
510
533
|
end
|
511
534
|
```
|
535
|
+
|
536
|
+
### Configuration
|
537
|
+
|
538
|
+
The Semantic Logger follows the principle where multiple appenders can be active
|
539
|
+
at the same time. For example, this allows one to log to MongoDB and the Rails
|
540
|
+
log file at the same time.
|
541
|
+
|
542
|
+
#### Rails Configuration
|
543
|
+
|
544
|
+
To automatically replace the Rails logger with Semantic Logger use the gem [rails_semantic_logger](http://github.com/ClarityServices/rails_semantic_logger)
|
545
|
+
|
512
546
|
### Log Struct
|
513
547
|
|
514
548
|
Internally all log messages are passed around in a Log Struct. In order
|
@@ -565,16 +599,14 @@ Example: Formatter that just returns the Log Struct
|
|
565
599
|
```ruby
|
566
600
|
require 'semantic_logger'
|
567
601
|
|
568
|
-
SemanticLogger
|
602
|
+
SemanticLogger.default_level = :trace
|
569
603
|
|
570
|
-
|
604
|
+
SemanticLogger.add_appender(STDOUT) do |log|
|
571
605
|
# This formatter just returns the log struct as a string
|
572
606
|
log.inspect
|
573
607
|
end
|
574
608
|
|
575
|
-
|
576
|
-
|
577
|
-
logger = SemanticLogger::Logger.new('Hello')
|
609
|
+
logger = SemanticLogger['Hello']
|
578
610
|
logger.info "Hello World"
|
579
611
|
```
|
580
612
|
Output:
|
@@ -582,58 +614,56 @@ Output:
|
|
582
614
|
#<struct SemanticLogger::Base::Log level=:info, thread_name=70167090649820, name="Hello", message="Hello World", payload=nil, time=2012-10-24 10:09:33 -0400, duration=nil, tags=nil, level_index=2>
|
583
615
|
|
584
616
|
|
585
|
-
Example: Replace the
|
617
|
+
Example: Replace the default log file formatter
|
586
618
|
|
587
619
|
```ruby
|
588
|
-
|
589
|
-
|
590
|
-
config.semantic_logger.appenders.first.formatter = Proc.new do |log|
|
591
|
-
tags = log.tags.collect { |tag| "[#{tag}]" }.join(" ") + " " if log.tags && (log.tags.size > 0)
|
620
|
+
require 'semantic_logger'
|
621
|
+
SemanticLogger.default_level = :trace
|
592
622
|
|
593
|
-
|
594
|
-
|
595
|
-
message << " -- " << "#{log.exception.class}: #{log.exception.message}\n#{(log.exception.backtrace || []).join("\n")}" if log.exception
|
623
|
+
SemanticLogger.add_appender('development.log') do |log|
|
624
|
+
tags = log.tags.collect { |tag| "[#{tag}]" }.join(" ") + " " if log.tags && (log.tags.size > 0)
|
596
625
|
|
597
|
-
|
626
|
+
message = log.message.to_s
|
627
|
+
message << " -- " << log.payload.inspect if log.payload
|
628
|
+
message << " -- " << "#{log.exception.class}: #{log.exception.message}\n#{(log.exception.backtrace || []).join("\n")}" if log.exception
|
598
629
|
|
599
|
-
|
600
|
-
|
601
|
-
|
630
|
+
duration_str = log.duration ? "(#{'%.1f' % log.duration}ms) " : ''
|
631
|
+
|
632
|
+
"#{SemanticLogger::Appender::Base.formatted_time(log.time)} #{log.level.to_s[0..0].upcase} [#{$$}:#{log.thread_name}] #{tags}#{duration_str}#{log.name} -- #{message}"
|
633
|
+
end
|
602
634
|
```
|
603
635
|
|
604
|
-
Example: Replace the MongoDB formatter
|
636
|
+
Example: Replace the default MongoDB formatter
|
605
637
|
|
606
638
|
```ruby
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
config.semantic_logger.appenders << mongodb_appender
|
636
|
-
end
|
639
|
+
# Log to MongoDB and supply a custom document formatter
|
640
|
+
mongodb_appender = SemanticLogger::Appender::MongoDB.new(
|
641
|
+
:db => Cache::Work.db,
|
642
|
+
:collection_size => 25.gigabytes
|
643
|
+
) do |log|
|
644
|
+
# Return a document (Hash) of the data to be saved to MongoDB
|
645
|
+
document = {
|
646
|
+
:time => log.time,
|
647
|
+
:host_name => SemanticLogger::Appender::MongoDB.host_name,
|
648
|
+
:pid => $PID,
|
649
|
+
:thread_name => log.thread_name,
|
650
|
+
:name => log.name,
|
651
|
+
:level => log.level,
|
652
|
+
:level_index => log.level_index,
|
653
|
+
}
|
654
|
+
document[:application] = 'MyApplication'
|
655
|
+
document[:message] = SemanticLogger::Appender::MongoDB.strip_colorizing(log.message) if log.message
|
656
|
+
document[:duration] = log.duration if log.duration
|
657
|
+
document[:tags] = log.tags if log.tags && (log.tags.size > 0)
|
658
|
+
document[:payload] = log.payload if log.payload
|
659
|
+
document[:exception] = {
|
660
|
+
:name => log.exception.class.name,
|
661
|
+
:message => log.exception.message,
|
662
|
+
:stack_trace => log.exception.backtrace
|
663
|
+
} if log.exception
|
664
|
+
document
|
665
|
+
end
|
666
|
+
SemanticLogger.add_appender(mongodb_appender)
|
637
667
|
```
|
638
668
|
|
639
669
|
### SysLog and other standard loggers
|
@@ -692,14 +722,11 @@ In this way formatting and disk or network write delays will not affect the
|
|
692
722
|
performance of the application. Also adding more than one appender does not affect
|
693
723
|
the runtime performance of the application.
|
694
724
|
|
695
|
-
The
|
696
|
-
terminates it will
|
697
|
-
the program exits.
|
725
|
+
The logging thread is automatically started on initialization. When the program
|
726
|
+
terminates it will call flush on each of the appenders.
|
698
727
|
|
699
728
|
Calling SemanticLogger::Logger#flush will wait until all outstanding log messages
|
700
729
|
have been written and flushed to their respective appenders before returning.
|
701
|
-
Since all logging is now from this thread calling flush is no longer thread
|
702
|
-
specific.
|
703
730
|
|
704
731
|
### Write your own Appender
|
705
732
|
|
@@ -739,13 +766,13 @@ end
|
|
739
766
|
|
740
767
|
Sample program calling the above appender:
|
741
768
|
```ruby
|
742
|
-
SemanticLogger
|
769
|
+
SemanticLogger.default_level = :trace
|
743
770
|
# Log to file dev.log
|
744
|
-
SemanticLogger
|
771
|
+
SemanticLogger.add_appender('dev.log')
|
745
772
|
# Also log the above sample appender
|
746
|
-
SemanticLogger
|
773
|
+
SemanticLogger.add_appender(SimpleAppender.new)
|
747
774
|
|
748
|
-
logger = SemanticLogger
|
775
|
+
logger = SemanticLogger['Hello']
|
749
776
|
logger.info "Hello World"
|
750
777
|
```
|
751
778
|
|
@@ -775,36 +802,12 @@ To log to MongoDB, it also needs the Ruby Mongo Driver
|
|
775
802
|
- Configuration file to support adding appenders
|
776
803
|
- Based on end-user demand add appenders for: Syslog, hadoop, redis, etc..
|
777
804
|
|
778
|
-
Development
|
779
|
-
-----------
|
780
|
-
|
781
|
-
Want to contribute to Semantic Logger?
|
782
|
-
|
783
|
-
First clone the repo and run the tests:
|
784
|
-
|
785
|
-
git clone git://github.com/ClarityServices/semantic_logger.git
|
786
|
-
cd semantic_logger
|
787
|
-
rake test
|
788
|
-
|
789
|
-
Feel free to ping the mailing list with any issues and we'll try to resolve it.
|
790
|
-
|
791
|
-
Contributing
|
792
|
-
------------
|
793
|
-
|
794
|
-
Once you've made your great commits:
|
795
|
-
|
796
|
-
1. [Fork](http://help.github.com/forking/) semantic_logger
|
797
|
-
2. Create a topic branch - `git checkout -b my_branch`
|
798
|
-
3. Push to your branch - `git push origin my_branch`
|
799
|
-
4. Create an [Issue](http://github.com/ClarityServices/semantic_logger/issues) with a link to your branch
|
800
|
-
5. That's it!
|
801
|
-
|
802
805
|
Meta
|
803
806
|
----
|
804
807
|
|
805
808
|
* Code: `git clone git://github.com/ClarityServices/semantic_logger.git`
|
806
809
|
* Home: <https://github.com/ClarityServices/semantic_logger>
|
807
|
-
* Bugs: <http://github.com/
|
810
|
+
* Bugs: <http://github.com/ClarityServices/semantic_logger/issues>
|
808
811
|
* Gems: <http://rubygems.org/gems/semantic_logger>
|
809
812
|
|
810
813
|
This project uses [Semantic Versioning](http://semver.org/).
|
@@ -817,7 +820,7 @@ Reid Morrison :: reidmo@gmail.com :: @reidmorrison
|
|
817
820
|
License
|
818
821
|
-------
|
819
822
|
|
820
|
-
Copyright 2012 Clarity Services, Inc.
|
823
|
+
Copyright 2012,2013 Clarity Services, Inc.
|
821
824
|
|
822
825
|
Licensed under the Apache License, Version 2.0 (the "License");
|
823
826
|
you may not use this file except in compliance with the License.
|