semantic_logger 2.3.1 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|