semantic_logger 2.3.1 → 2.4.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.
- checksums.yaml +4 -4
- data/README.md +50 -42
- data/lib/semantic_logger.rb +1 -0
- data/lib/semantic_logger/appender/file.rb +18 -7
- data/lib/semantic_logger/appender/syslog.rb +249 -0
- data/lib/semantic_logger/semantic_logger.rb +8 -0
- data/lib/semantic_logger/version.rb +1 -1
- data/test/appender_syslog_test.rb +50 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 986fd023dd3d5b61817027e25aeae6b6919f65f2
|
4
|
+
data.tar.gz: 7c94accd89688c3ee66fb05c1f17eaba10183abb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48eeadcce9890d4d8adb53c8a76c98b259a230f8c7c0c41f3d2ae62ce94bfc850a51c7e6a143064590960aac5e0b12759ec01a396ff9bad93459ecfc81b48778
|
7
|
+
data.tar.gz: ce6a05fe76874b04e2a28bfaf0a09aeb790c9fdc119744dd0b975e22286402a0c62909d67f04fe6d885ed1873397e9b31614528ea285ec696d30a69ab852bafd
|
data/README.md
CHANGED
@@ -5,13 +5,13 @@ Improved logging for Ruby
|
|
5
5
|
|
6
6
|
* http://github.com/ClarityServices/semantic_logger
|
7
7
|
|
8
|
-
|
8
|
+
## Note:
|
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
12
|
gem to replace the Rails default logger with SemanticLogger
|
13
13
|
|
14
|
-
|
14
|
+
## Overview
|
15
15
|
|
16
16
|
Semantic Logger takes logging in Ruby to a new level by adding several new
|
17
17
|
capabilities to the commonly used Logging API:
|
@@ -132,7 +132,7 @@ Thread Safe
|
|
132
132
|
* Tagged logging keeps any tagging data on a per-thread basis to ensure that
|
133
133
|
tags from different threads are not inter-mingled
|
134
134
|
|
135
|
-
|
135
|
+
## Introduction
|
136
136
|
|
137
137
|
Semantic Logger is a Logger that supports logging of meta-data, along with text messages
|
138
138
|
to multiple appenders
|
@@ -183,9 +183,9 @@ Since Semantic Logger can call existing Loggers, it does not force end-users
|
|
183
183
|
to have to adopt a Semantic aware adapter. Although, such adapters create
|
184
184
|
tremendous value in the problem monitoring and determination processes.
|
185
185
|
|
186
|
-
|
186
|
+
## Logging API
|
187
187
|
|
188
|
-
|
188
|
+
### Standard Logging methods
|
189
189
|
|
190
190
|
The Semantic Logger logging API supports the existing logging interface for
|
191
191
|
the Rails and Ruby Loggers. For example:
|
@@ -231,7 +231,7 @@ logger.debug("Calling Supplier", :request => 'update', :user => 'Jack')
|
|
231
231
|
logger.debug { "A total of #{result.inject(0) {|sum, i| i+sum }} were processed" }
|
232
232
|
```
|
233
233
|
|
234
|
-
|
234
|
+
## Exceptions
|
235
235
|
|
236
236
|
The Semantic Logger adds an optional parameter to the existing log methods so that
|
237
237
|
a corresponding Exception can be logged in a standard way
|
@@ -246,7 +246,7 @@ rescue Exception => exception
|
|
246
246
|
end
|
247
247
|
```
|
248
248
|
|
249
|
-
|
249
|
+
### Payload
|
250
250
|
|
251
251
|
The Semantic Logger adds an extra parameter to the existing log methods so that
|
252
252
|
additional payload can be logged, such as a Hash or a Ruby Exception object.
|
@@ -260,7 +260,7 @@ regular expressions so that a program can analyze log output. With the MongoDB
|
|
260
260
|
appender the payload is written directly to MongoDB as part of the document and
|
261
261
|
is therefore fully searchable
|
262
262
|
|
263
|
-
|
263
|
+
### Benchmarking
|
264
264
|
|
265
265
|
Another common logging requirement is to measure the time it takes to execute a block
|
266
266
|
of code based on the log level. For example:
|
@@ -317,7 +317,7 @@ Parameters
|
|
317
317
|
Optional, Ruby Exception object to log along with the duration of the supplied block
|
318
318
|
```
|
319
319
|
|
320
|
-
|
320
|
+
### Logging levels
|
321
321
|
|
322
322
|
The following logging levels are available through Semantic Logger
|
323
323
|
|
@@ -336,7 +336,7 @@ in the development environment for low level trace logging of methods calls etc.
|
|
336
336
|
If only the rails logger is being used, then :trace level calls will be logged
|
337
337
|
as debug calls only if the log level is set to trace
|
338
338
|
|
339
|
-
|
339
|
+
### Changing the Class name for Log Entries
|
340
340
|
|
341
341
|
When Semantic Logger is included in a Rails project it automatically replaces the
|
342
342
|
loggers for Rails, ActiveRecord::Base, ActionController::Base, and ActiveResource::Base
|
@@ -375,7 +375,7 @@ This will result in the log output identifying the log entry as from the Externa
|
|
375
375
|
|
376
376
|
2012-08-30 15:37:29.474 I [48308:ScriptThreadProcess: script/rails] (5.2ms) ExternalSupplier -- Calling external interface
|
377
377
|
|
378
|
-
|
378
|
+
### Tagged Logging
|
379
379
|
|
380
380
|
Semantic Logger allows any Ruby or Rails program to also include tagged logging.
|
381
381
|
|
@@ -393,7 +393,7 @@ logger.tagged(tracking_number) do
|
|
393
393
|
end
|
394
394
|
```
|
395
395
|
|
396
|
-
|
396
|
+
### Beyond Tagged Logging
|
397
397
|
|
398
398
|
Blocks of code can be tagged with not only values, but can be tagged with
|
399
399
|
entire hashes of data. The additional hash of data will be merged into
|
@@ -409,7 +409,7 @@ logger.with_payload(:user => 'Jack', :zip_code => 12345) do
|
|
409
409
|
end
|
410
410
|
```
|
411
411
|
|
412
|
-
|
412
|
+
## Standalone SemanticLogger
|
413
413
|
|
414
414
|
When using SemanticLogger inside of Rails all we need to do is include the
|
415
415
|
rails_semantic_logger gem and the default Rails logger will be replaced with
|
@@ -533,17 +533,34 @@ class ExternalSupplier
|
|
533
533
|
end
|
534
534
|
```
|
535
535
|
|
536
|
-
###
|
536
|
+
### Logging to Syslog
|
537
|
+
|
538
|
+
Log to a local Syslog:
|
539
|
+
```ruby
|
540
|
+
require 'semantic_logger'
|
541
|
+
SemanticLogger.default_level = :trace
|
542
|
+
SemanticLogger.add_appender(SemanticLogger::Appender::Syslog.new)
|
543
|
+
```
|
544
|
+
|
545
|
+
Log to a local file and to a remote Syslog server such as syslog-ng over TCP:
|
546
|
+
```ruby
|
547
|
+
require 'semantic_logger'
|
548
|
+
SemanticLogger.default_level = :trace
|
549
|
+
SemanticLogger.add_appender('development.log')
|
550
|
+
SemanticLogger.add_appender(SemanticLogger::Appender::Syslog.new(:server => 'tcp://myloghost:514'))
|
551
|
+
```
|
552
|
+
|
553
|
+
## Configuration
|
537
554
|
|
538
555
|
The Semantic Logger follows the principle where multiple appenders can be active
|
539
556
|
at the same time. For example, this allows one to log to MongoDB and the Rails
|
540
557
|
log file at the same time.
|
541
558
|
|
542
|
-
|
559
|
+
### Rails Configuration
|
543
560
|
|
544
561
|
To automatically replace the Rails logger with Semantic Logger use the gem [rails_semantic_logger](http://github.com/ClarityServices/rails_semantic_logger)
|
545
562
|
|
546
|
-
|
563
|
+
## Log Struct
|
547
564
|
|
548
565
|
Internally all log messages are passed around in a Log Struct. In order
|
549
566
|
to write your own custom formatter or log appender it is necessary to understand
|
@@ -589,7 +606,7 @@ level_index [Integer]
|
|
589
606
|
|
590
607
|
* Internal use only. Index of the log level
|
591
608
|
|
592
|
-
|
609
|
+
### Mixing Logging Levels
|
593
610
|
|
594
611
|
It is sometimes useful to log a subset of the log messages to a separate file
|
595
612
|
or appender. For example, log :error and :fatal level messages to a special
|
@@ -627,7 +644,7 @@ The output is as follows:
|
|
627
644
|
2013-08-02 14:15:56.735273 W [35669:70176909690580] MyClass -- This is a warning message
|
628
645
|
```
|
629
646
|
|
630
|
-
|
647
|
+
### Custom Formatters
|
631
648
|
|
632
649
|
The formatting for each appender can be replaced with custom code. To replace the
|
633
650
|
existing formatter supply a block of code when creating the appender.
|
@@ -704,21 +721,7 @@ end
|
|
704
721
|
SemanticLogger.add_appender(mongodb_appender)
|
705
722
|
```
|
706
723
|
|
707
|
-
|
708
|
-
|
709
|
-
To write log entries to a Syslog logger or any other logger of your choice,
|
710
|
-
that conforms the standard Ruby Logger API, Semantic Logger has an Appender to
|
711
|
-
use that logger.
|
712
|
-
|
713
|
-
For example to configure rails to also log to the Syslogger gem:
|
714
|
-
```ruby
|
715
|
-
config.after_initialize do
|
716
|
-
# Besides logging to the local file also log to Syslogger
|
717
|
-
config.semantic_logger.appenders << SemanticLogger::Appender::Wrapper.new(Syslogger.new("yourappname"))
|
718
|
-
end
|
719
|
-
```
|
720
|
-
|
721
|
-
### Performance
|
724
|
+
## Performance
|
722
725
|
|
723
726
|
The traditional logging implementations write their log information to file in the
|
724
727
|
same thread of execution as the program itself. This means that for every log entry
|
@@ -731,12 +734,12 @@ Also, since the logging is in this separate thread there is no impact to program
|
|
731
734
|
execution if we decided to add another appender.
|
732
735
|
For example, log to both a file and a MongoDB collection.
|
733
736
|
|
734
|
-
|
737
|
+
## Log Rotation
|
735
738
|
|
736
739
|
Since the log file is not re-opened with every call, when the log file needs
|
737
740
|
to be rotated, use a copy-truncate operation over deleting the file.
|
738
741
|
|
739
|
-
|
742
|
+
## Why Semantic logging?
|
740
743
|
|
741
744
|
Just as there is the initiative to add Semantic information to data on the web
|
742
745
|
so that computers can directly understand the content without having to resort
|
@@ -750,7 +753,7 @@ Once the logging data is in the NOSQL data store it can be queried quickly and
|
|
750
753
|
efficiently. Some SQL data stores also allow complex data types that could be used
|
751
754
|
for storing and querying the logging data
|
752
755
|
|
753
|
-
|
756
|
+
## Architecture & Performance
|
754
757
|
|
755
758
|
In order to ensure that logging does not hinder the performance of the application
|
756
759
|
all log entries are written to thread-safe Queue. A separate thread is responsible
|
@@ -766,7 +769,7 @@ terminates it will call flush on each of the appenders.
|
|
766
769
|
Calling SemanticLogger::Logger#flush will wait until all outstanding log messages
|
767
770
|
have been written and flushed to their respective appenders before returning.
|
768
771
|
|
769
|
-
|
772
|
+
## Write your own Appender
|
770
773
|
|
771
774
|
To write your own appender it should meet the following requirements:
|
772
775
|
|
@@ -821,12 +824,12 @@ instructions below.
|
|
821
824
|
Very Important: New appenders will not be accepted without complete working tests.
|
822
825
|
See the [MongoDB Appender Test](https://github.com/ClarityServices/semantic_logger/blob/master/test/appender_mongodb_test.rb) for an example.
|
823
826
|
|
824
|
-
|
827
|
+
## Dependencies
|
825
828
|
|
826
829
|
- Ruby MRI 1.8.7, 1.9.3 (or above) Or, JRuby 1.6.3 (or above)
|
827
830
|
- Optional: To log to MongoDB, Mongo Ruby Driver 1.5.2 or above
|
828
831
|
|
829
|
-
|
832
|
+
## Install
|
830
833
|
|
831
834
|
gem install semantic_logger
|
832
835
|
|
@@ -834,7 +837,7 @@ To log to MongoDB, it also needs the Ruby Mongo Driver
|
|
834
837
|
|
835
838
|
gem install mongo
|
836
839
|
|
837
|
-
|
840
|
+
## Future
|
838
841
|
|
839
842
|
- Add support for a configuration file that can set log level by class name
|
840
843
|
- Configuration file to support adding appenders
|
@@ -850,15 +853,20 @@ Meta
|
|
850
853
|
|
851
854
|
This project uses [Semantic Versioning](http://semver.org/).
|
852
855
|
|
853
|
-
|
856
|
+
Author
|
854
857
|
-------
|
855
858
|
|
856
859
|
Reid Morrison :: reidmo@gmail.com :: @reidmorrison
|
857
860
|
|
861
|
+
Contributors
|
862
|
+
------------
|
863
|
+
|
864
|
+
Marc Bellingrath :: marrrc.b@gmail.com
|
865
|
+
|
858
866
|
License
|
859
867
|
-------
|
860
868
|
|
861
|
-
Copyright 2012,2013
|
869
|
+
Copyright 2012,2013 Reid Morrison
|
862
870
|
|
863
871
|
Licensed under the Apache License, Version 2.0 (the "License");
|
864
872
|
you may not use this file except in compliance with the License.
|
data/lib/semantic_logger.rb
CHANGED
@@ -41,22 +41,33 @@ module SemanticLogger
|
|
41
41
|
#
|
42
42
|
def initialize(filename, level=nil, &block)
|
43
43
|
raise "filename cannot be null when initializing the SemanticLogging::Appender::File" unless filename
|
44
|
-
@filename = filename
|
45
44
|
@log = if filename.respond_to?(:write) and filename.respond_to?(:close)
|
46
45
|
filename
|
47
46
|
else
|
48
|
-
@
|
49
|
-
|
50
|
-
# Allows multiple processes to write to the same log file simultaneously
|
51
|
-
@log.sync = true
|
52
|
-
@log.set_encoding(Encoding::BINARY) if @log.respond_to?(:set_encoding)
|
53
|
-
@log
|
47
|
+
@filename = filename
|
48
|
+
reopen
|
54
49
|
end
|
55
50
|
|
56
51
|
# Set the log level and formatter if supplied
|
57
52
|
super(level, &block)
|
58
53
|
end
|
59
54
|
|
55
|
+
# After forking an active process call #reopen to re-open
|
56
|
+
# open the file handles etc to resources
|
57
|
+
#
|
58
|
+
# Note: This method will only work if a String filename was supplied
|
59
|
+
# on the initializer.
|
60
|
+
def reopen
|
61
|
+
return unless @filename
|
62
|
+
|
63
|
+
@log = open(@filename, (::File::WRONLY | ::File::APPEND | ::File::CREAT))
|
64
|
+
# Force all log entries to write immediately without buffering
|
65
|
+
# Allows multiple processes to write to the same log file simultaneously
|
66
|
+
@log.sync = true
|
67
|
+
@log.set_encoding(Encoding::BINARY) if @log.respond_to?(:set_encoding)
|
68
|
+
@log
|
69
|
+
end
|
70
|
+
|
60
71
|
# Pass log calls to the underlying Rails, log4j or Ruby logger
|
61
72
|
# trace entries are mapped to debug since :trace is not supported by the
|
62
73
|
# Ruby or Rails Loggers
|
@@ -0,0 +1,249 @@
|
|
1
|
+
# syslog appender for SemanticLogger - Supports local and remote syslog (over TCP or UDP)
|
2
|
+
#
|
3
|
+
# Example 1
|
4
|
+
# Log to the local syslog.
|
5
|
+
#
|
6
|
+
# require 'semantic_logger'
|
7
|
+
# SemanticLogger.default_level = :trace
|
8
|
+
#
|
9
|
+
# syslog_appender = SemanticLogger::Appender::Syslog.new
|
10
|
+
# SemanticLogger.add_appender(syslog_appender)
|
11
|
+
#
|
12
|
+
# logger = SemanticLogger['SyslogAppenderExample']
|
13
|
+
# logger.info "Info Hello! - This message should appear in the local syslog!"
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# Example 2
|
17
|
+
# Send to a remote syslog appender - myloghost - over TCP on port 514.
|
18
|
+
# Tested with syslog-ng as part of an ELSA installation.
|
19
|
+
# https://code.google.com/p/enterprise-log-search-and-archive/
|
20
|
+
#
|
21
|
+
# require 'semantic_logger'
|
22
|
+
# # Only log warn and above messages to the remote syslog.
|
23
|
+
# syslog_appender = SemanticLogger::Appender::Syslog.new(level: :warn, server: 'tcp://myloghost:514')
|
24
|
+
# SemanticLogger.add_appender(syslog_appender)
|
25
|
+
#
|
26
|
+
# logger = SemanticLogger['SyslogAppenderExample']
|
27
|
+
# logger.info "Info Hello! - The log level is too low and will not be logged."
|
28
|
+
# logger.error "Error! Error! - This message should appear in the remote syslog!"
|
29
|
+
#
|
30
|
+
require 'syslog'
|
31
|
+
require 'uri'
|
32
|
+
require 'socket'
|
33
|
+
|
34
|
+
module SemanticLogger
|
35
|
+
module Appender
|
36
|
+
class Syslog < SemanticLogger::Appender::Base
|
37
|
+
|
38
|
+
attr_reader :remote_syslog, :server, :host, :port, :protocol, :facility, :local_hostname
|
39
|
+
|
40
|
+
# Default mapping of ruby log levels to syslog log levels
|
41
|
+
#
|
42
|
+
# ::Syslog::LOG_EMERG - "System is unusable"
|
43
|
+
# ::Syslog::LOG_ALERT - "Action needs to be taken immediately"
|
44
|
+
# ::Syslog::LOG_CRIT - "A critical condition has occurred"
|
45
|
+
# ::Syslog::LOG_ERR - "An error occurred"
|
46
|
+
# ::Syslog::LOG_WARNING - "Warning of a possible problem"
|
47
|
+
# ::Syslog::LOG_NOTICE - "A normal but significant condition occurred"
|
48
|
+
# ::Syslog::LOG_INFO - "Informational message"
|
49
|
+
# ::Syslog::LOG_DEBUG - "Debugging information"
|
50
|
+
DEFAULT_LEVEL_MAP = {
|
51
|
+
:fatal => ::Syslog::LOG_CRIT,
|
52
|
+
:error => ::Syslog::LOG_ERR,
|
53
|
+
:warn => ::Syslog::LOG_WARNING,
|
54
|
+
:info => ::Syslog::LOG_NOTICE,
|
55
|
+
:debug => ::Syslog::LOG_INFO,
|
56
|
+
:trace => ::Syslog::LOG_DEBUG
|
57
|
+
}
|
58
|
+
|
59
|
+
# For more information on the Syslog constants used below see http://ruby-doc.org/stdlib-2.0.0/libdoc/syslog/rdoc/Syslog.html
|
60
|
+
# Parameters
|
61
|
+
#
|
62
|
+
# :ident [String]
|
63
|
+
# Identity of the program
|
64
|
+
# Default: 'ruby'
|
65
|
+
#
|
66
|
+
# :options [Integer]
|
67
|
+
# Default: ::Syslog::LOG_PID | ::Syslog::LOG_CONS
|
68
|
+
# Any of the following (options can be logically OR'd together)
|
69
|
+
# ::Syslog::LOG_CONS
|
70
|
+
# ::Syslog::LOG_NDELAY
|
71
|
+
# ::Syslog::LOG_NOWAIT
|
72
|
+
# ::Syslog::LOG_ODELAY
|
73
|
+
# ::Syslog::LOG_PERROR
|
74
|
+
# ::Syslog::LOG_PID
|
75
|
+
#
|
76
|
+
# :facility [Integer]
|
77
|
+
# Default: ::Syslog::LOG_USER
|
78
|
+
# Type of program (can be logically OR'd together)
|
79
|
+
# ::Syslog::LOG_AUTH
|
80
|
+
# ::Syslog::LOG_AUTHPRIV
|
81
|
+
# ::Syslog::LOG_CONSOLE
|
82
|
+
# ::Syslog::LOG_CRON
|
83
|
+
# ::Syslog::LOG_DAEMON
|
84
|
+
# ::Syslog::LOG_FTP
|
85
|
+
# ::Syslog::LOG_KERN
|
86
|
+
# ::Syslog::LOG_LRP
|
87
|
+
# ::Syslog::LOG_MAIL
|
88
|
+
# ::Syslog::LOG_NEWS
|
89
|
+
# ::Syslog::LOG_NTP
|
90
|
+
# ::Syslog::LOG_SECURITY
|
91
|
+
# ::Syslog::LOG_SYSLOG
|
92
|
+
# ::Syslog::LOG_USER
|
93
|
+
# ::Syslog::LOG_UUCP
|
94
|
+
# ::Syslog::LOG_LOCAL0
|
95
|
+
# ::Syslog::LOG_LOCAL1
|
96
|
+
# ::Syslog::LOG_LOCAL2
|
97
|
+
# ::Syslog::LOG_LOCAL3
|
98
|
+
# ::Syslog::LOG_LOCAL4
|
99
|
+
# ::Syslog::LOG_LOCAL5
|
100
|
+
# ::Syslog::LOG_LOCAL6
|
101
|
+
# ::Syslog::LOG_LOCAL7
|
102
|
+
#
|
103
|
+
# :level [Symbol]
|
104
|
+
# Default: SemanticLogger's log level.
|
105
|
+
# The minimum level at which this appender will write logs. Any log messages below this level will be ignored.
|
106
|
+
#
|
107
|
+
# :level_map [Hash]
|
108
|
+
# Supply a custom map of SemanticLogger levels to syslog levels.
|
109
|
+
# For example, passing in { :warn => ::Syslog::LOG_NOTICE }
|
110
|
+
# would result in a log mapping that matches the default level map,
|
111
|
+
# except for :warn, which ends up with a LOG_NOTICE level instead of a
|
112
|
+
# LOG_WARNING one.
|
113
|
+
# Without overriding any parameters, the level map will be
|
114
|
+
# LEVEL_MAP = {
|
115
|
+
# :fatal => ::Syslog::LOG_CRIT,
|
116
|
+
# :error => ::Syslog::LOG_ERR,
|
117
|
+
# :warn => ::Syslog::LOG_WARNING,
|
118
|
+
# :info => ::Syslog::LOG_NOTICE,
|
119
|
+
# :debug => ::Syslog::LOG_INFO,
|
120
|
+
# :trace => ::Syslog::LOG_DEBUG
|
121
|
+
# }
|
122
|
+
#
|
123
|
+
# :local_hostname [String]
|
124
|
+
# Default: Socket.gethostname || `hostname`.strip
|
125
|
+
# Hostname to provide to the remote syslog.
|
126
|
+
#
|
127
|
+
# :server [String]
|
128
|
+
# Default: 'syslog://localhost'
|
129
|
+
# For writing logs to a remote syslog server
|
130
|
+
# URI of server: protocol://host:port
|
131
|
+
# Uses port 514 by default for TCP and UDP.
|
132
|
+
# local syslog example: 'syslog://localhost'
|
133
|
+
# TCP example with default port: 'tcp://logger'
|
134
|
+
# TCP example with custom port: 'tcp://logger:8514'
|
135
|
+
# UDP example with default port: 'udp://logger'
|
136
|
+
# UDP example with custom port: 'udp://logger:8514'
|
137
|
+
# When using the :syslog protocol, logs will always be sent to the localhost syslog
|
138
|
+
#
|
139
|
+
# :tcp_client [Hash]
|
140
|
+
# Default: {}
|
141
|
+
# Only used with the TCP protocol.
|
142
|
+
# Specify custom parameters to pass into ResilientSocket.TCPClient.new
|
143
|
+
# For a list of options see the resilient_socket documentation:
|
144
|
+
# https://github.com/reidmorrison/resilient_socket/blob/master/lib/resilient_socket/tcp_client.rb
|
145
|
+
def initialize(params = {}, &block)
|
146
|
+
params = params.dup
|
147
|
+
@ident = params.delete(:ident) || 'ruby'
|
148
|
+
options = params.delete(:options) || (::Syslog::LOG_PID | ::Syslog::LOG_CONS)
|
149
|
+
@facility = params.delete(:facility) || ::Syslog::LOG_USER
|
150
|
+
level = params.delete(:level)
|
151
|
+
level_map = params.delete(:level_map)
|
152
|
+
@level_map = DEFAULT_LEVEL_MAP.dup
|
153
|
+
@level_map.update(level_map) if level_map
|
154
|
+
@server = params.delete(:server) || 'syslog://localhost'
|
155
|
+
uri = URI(@server)
|
156
|
+
@host = uri.host || 'localhost'
|
157
|
+
@protocol = (uri.scheme || :syslog).to_sym
|
158
|
+
raise "Unknown protocol #{@protocol}!" unless [:syslog, :tcp, :udp].include?(@protocol)
|
159
|
+
@host = 'localhost' if @protocol == :syslog
|
160
|
+
@port = URI(@server).port || 514
|
161
|
+
@local_hostname = params.delete(:local_hostname) || Socket.gethostname || `hostname`.strip
|
162
|
+
tcp_client_options = params.delete(:tcp_client)
|
163
|
+
|
164
|
+
# Warn about any unknown configuration options.
|
165
|
+
params.each_pair { |key,val| SemanticLogger::Logger.logger.warn "Ignoring unknown configuration option: #{key.inspect} => #{val.inspect}" }
|
166
|
+
|
167
|
+
# The syslog_protocol gem is required when logging over TCP or UDP.
|
168
|
+
if [:tcp, :udp].include?(@protocol)
|
169
|
+
begin
|
170
|
+
require 'syslog_protocol'
|
171
|
+
rescue LoadError
|
172
|
+
raise 'Missing gem: syslog_protocol. This gem is required when logging over TCP or UDP. To fix this error: gem install syslog_protocol'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
case @protocol
|
177
|
+
when :syslog
|
178
|
+
::Syslog.open(@ident, options, @facility)
|
179
|
+
when :tcp
|
180
|
+
# The resilient_socket gem is required when logging over TCP.
|
181
|
+
begin
|
182
|
+
require 'resilient_socket'
|
183
|
+
rescue LoadError
|
184
|
+
raise 'Missing gem: resilient_socket. This gem is required when logging over TCP. To fix this error: gem install resilient_socket'
|
185
|
+
end
|
186
|
+
options = tcp_client_options || {}
|
187
|
+
options[:server] = "#{@host}:#{@port}"
|
188
|
+
@remote_syslog = ResilientSocket::TCPClient.new(options)
|
189
|
+
# Use the local logger for @remote_syslog so errors with the remote logger can be recorded locally.
|
190
|
+
@remote_syslog.logger = SemanticLogger::Logger.logger
|
191
|
+
when :udp
|
192
|
+
@remote_syslog = UDPSocket.new
|
193
|
+
else
|
194
|
+
raise "Unsupported protocol: #{protocol}"
|
195
|
+
end
|
196
|
+
|
197
|
+
super(level, &block)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Write the log using the specified protocol and host.
|
201
|
+
def log(log)
|
202
|
+
if level_index <= (log.level_index || 0)
|
203
|
+
case @protocol
|
204
|
+
when :syslog
|
205
|
+
::Syslog.log @level_map[log.level], formatter.call(log)
|
206
|
+
when :tcp
|
207
|
+
@remote_syslog.retry_on_connection_failure { @remote_syslog.write("#{syslog_packet_formatter(log)}\r\n") }
|
208
|
+
when :udp
|
209
|
+
@remote_syslog.send syslog_packet_formatter(log), 0, @host, @port
|
210
|
+
else
|
211
|
+
raise "Unsupported protocol: #{protocol}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Flush is called by the semantic_logger during shutdown.
|
217
|
+
def flush
|
218
|
+
# TODO Add flush for :tcp.
|
219
|
+
end
|
220
|
+
|
221
|
+
# Custom log formatter for syslog
|
222
|
+
def default_formatter
|
223
|
+
Proc.new do |log|
|
224
|
+
tags = log.tags.collect { |tag| "[#{tag}]" }.join(" ") + " " if log.tags && (log.tags.size > 0)
|
225
|
+
|
226
|
+
message = log.message.to_s
|
227
|
+
message << " -- " << log.payload.inspect if log.payload
|
228
|
+
message << " -- " << "#{log.exception.class}: #{log.exception.message}\n#{(log.exception.backtrace || []).join("\n")}" if log.exception
|
229
|
+
|
230
|
+
duration_str = log.duration ? "(#{'%.1f' % log.duration}ms) " : ''
|
231
|
+
|
232
|
+
"#{log.level.to_s[0..0].upcase} [#{$$}:#{log.thread_name}] #{tags}#{duration_str}#{log.name} -- #{message}"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Format the syslog packet so it can be sent over TCP or UDP
|
237
|
+
def syslog_packet_formatter(log)
|
238
|
+
packet = SyslogProtocol::Packet.new
|
239
|
+
packet.hostname = @local_hostname
|
240
|
+
packet.facility = @facility
|
241
|
+
packet.severity = @level_map[log.level]
|
242
|
+
packet.tag = @ident
|
243
|
+
packet.content = default_formatter.call(log)
|
244
|
+
packet.to_s
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -122,6 +122,14 @@ module SemanticLogger
|
|
122
122
|
SemanticLogger::Logger.flush
|
123
123
|
end
|
124
124
|
|
125
|
+
# After forking an active process call SemanticLogger.reopen to re-open
|
126
|
+
# any open file handles etc to resources
|
127
|
+
#
|
128
|
+
# Note: Only appenders that implement the reopen method will be called
|
129
|
+
def self.reopen
|
130
|
+
@@appenders.each {|appender| appender.reopen if appender.respond_to?(:reopen)}
|
131
|
+
end
|
132
|
+
|
125
133
|
############################################################################
|
126
134
|
protected
|
127
135
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Allow test to be run in-place without requiring a gem install
|
2
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'shoulda'
|
7
|
+
require 'mocha/setup'
|
8
|
+
require 'semantic_logger'
|
9
|
+
require 'socket'
|
10
|
+
require 'resilient_socket'
|
11
|
+
require 'syslog_protocol'
|
12
|
+
|
13
|
+
# Unit Test for SemanticLogger::Appender::Syslog
|
14
|
+
#
|
15
|
+
class AppenderSyslogTest < Test::Unit::TestCase
|
16
|
+
context SemanticLogger::Appender::Syslog do
|
17
|
+
|
18
|
+
should 'handle local syslog' do
|
19
|
+
::Syslog.expects(:open).once
|
20
|
+
::Syslog.expects(:log).once
|
21
|
+
syslog_appender = SemanticLogger::Appender::Syslog.new
|
22
|
+
syslog_appender.debug 'AppenderSyslogTest log message'
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'handle remote syslog over TCP' do
|
26
|
+
::ResilientSocket::TCPClient.any_instance.stubs('closed?').returns(false)
|
27
|
+
::ResilientSocket::TCPClient.any_instance.stubs('connect')
|
28
|
+
::ResilientSocket::TCPClient.any_instance.expects(:write).with{ |message| message =~ /<70>(.*?)SemanticLogger::Appender::Syslog -- AppenderSyslogTest log message\r\n/ }
|
29
|
+
syslog_appender = SemanticLogger::Appender::Syslog.new(:server => 'tcp://localhost:88888')
|
30
|
+
syslog_appender.debug 'AppenderSyslogTest log message'
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'handle remote syslog over UDP' do
|
34
|
+
::UDPSocket.any_instance.expects(:send).with{ |*params| params[0] =~ /<70>(.*?)SemanticLogger::Appender::Syslog -- AppenderSyslogTest log message/ }
|
35
|
+
syslog_appender = SemanticLogger::Appender::Syslog.new(:server => 'udp://localhost:88888')
|
36
|
+
syslog_appender.debug 'AppenderSyslogTest log message'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Should be able to log each level.
|
40
|
+
SemanticLogger::LEVELS.each do |level|
|
41
|
+
should "log #{level} information" do
|
42
|
+
::Syslog.expects(:open).once
|
43
|
+
::Syslog.expects(:log).once
|
44
|
+
syslog_appender = SemanticLogger::Appender::Syslog.new
|
45
|
+
syslog_appender.send(level, 'AppenderSyslogTest #{level.to_s} message')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semantic_logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sync_attr
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/semantic_logger/appender/base.rb
|
50
50
|
- lib/semantic_logger/appender/file.rb
|
51
51
|
- lib/semantic_logger/appender/mongodb.rb
|
52
|
+
- lib/semantic_logger/appender/syslog.rb
|
52
53
|
- lib/semantic_logger/appender/wrapper.rb
|
53
54
|
- lib/semantic_logger/base.rb
|
54
55
|
- lib/semantic_logger/loggable.rb
|
@@ -61,6 +62,7 @@ files:
|
|
61
62
|
- README.md
|
62
63
|
- test/appender_file_test.rb
|
63
64
|
- test/appender_mongodb_test.rb
|
65
|
+
- test/appender_syslog_test.rb
|
64
66
|
- test/appender_wrapper_test.rb
|
65
67
|
- test/loggable_test.rb
|
66
68
|
- test/logger_test.rb
|
@@ -92,6 +94,7 @@ summary: Improved logging for Ruby
|
|
92
94
|
test_files:
|
93
95
|
- test/appender_file_test.rb
|
94
96
|
- test/appender_mongodb_test.rb
|
97
|
+
- test/appender_syslog_test.rb
|
95
98
|
- test/appender_wrapper_test.rb
|
96
99
|
- test/loggable_test.rb
|
97
100
|
- test/logger_test.rb
|