lumberjack_syslog_device 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT_LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Brian Durand
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,13 @@
1
+ Lumberjack Syslog Device
2
+
3
+ This gem provides a logging device for the lumberjack gem that will log to syslog, the centralized system logging facility. See http://en.wikipedia.org/wiki/Syslog for more information on syslog.
4
+
5
+ == Example Usage
6
+
7
+ require 'lumberjack_syslog_device'
8
+
9
+ device = Lumberjack::SyslogDevice.new
10
+ logger = Lumberjack::Logger.new(device)
11
+ logger.info("Write me to syslog!")
12
+
13
+ See SyslogDevice for more details.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/rdoctask'
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'RVM likes to call it tests'
10
+ task :tests => :test
11
+
12
+ begin
13
+ require 'rspec'
14
+ require 'rspec/core/rake_task'
15
+ desc 'Run the unit tests'
16
+ RSpec::Core::RakeTask.new(:test)
17
+ rescue LoadError
18
+ task :test do
19
+ STDERR.puts "You must have rspec 2.0 installed to run the tests"
20
+ end
21
+ end
22
+
23
+ desc 'Generate rdoc.'
24
+ Rake::RDocTask.new(:rdoc) do |rdoc|
25
+ rdoc.rdoc_dir = 'rdoc'
26
+ rdoc.options << '--title' << 'Lumberjack Syslog Device' << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc'
27
+ rdoc.rdoc_files.include('README.rdoc')
28
+ rdoc.rdoc_files.include('lib/**/*.rb')
29
+ end
30
+
31
+ namespace :rbx do
32
+ desc "Cleanup *.rbc files in lib directory"
33
+ task :delete_rbc_files do
34
+ FileList["lib/**/*.rbc"].each do |rbc_file|
35
+ File.delete(rbc_file)
36
+ end
37
+ nil
38
+ end
39
+ end
40
+
41
+ spec_file = File.expand_path('../lumberjack_syslog_device.gemspec', __FILE__)
42
+ if File.exist?(spec_file)
43
+ spec = eval(File.read(spec_file))
44
+
45
+ Rake::GemPackageTask.new(spec) do |p|
46
+ p.gem_spec = spec
47
+ end
48
+ Rake.application["package"].prerequisites.unshift("rbx:delete_rbc_files")
49
+
50
+ desc "Release to rubygems.org"
51
+ task :release => :package do
52
+ require 'rake/gemcutter'
53
+ Rake::Gemcutter::Tasks.new(spec).define
54
+ Rake::Task['gem:push'].invoke
55
+ end
56
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,104 @@
1
+ require 'syslog'
2
+ require 'lumberjack'
3
+
4
+ module Lumberjack
5
+ # This Lumberjack device logs output to syslog. There can only be one connection to syslog
6
+ # open at a time. If you use syslog elsewhere in your application, you'll need to pass
7
+ # <tt>:close_connection => true</tt> to the constructor. Otherwise, the connection will be kept
8
+ # open between +write+ calls.
9
+ class SyslogDevice < Device
10
+ SEVERITY_MAP = {
11
+ Severity::DEBUG => Syslog::LOG_DEBUG,
12
+ Severity::INFO => Syslog::LOG_INFO,
13
+ Severity::WARN => Syslog::LOG_WARNING,
14
+ Severity::ERROR => Syslog::LOG_ERR,
15
+ Severity::FATAL => Syslog::LOG_CRIT,
16
+ Severity::UNKNOWN => Syslog::LOG_ALERT
17
+ }
18
+
19
+ PERCENT = '%'
20
+ ESCAPED_PERCENT = '%%'
21
+
22
+ @@lock = Mutex.new
23
+
24
+
25
+ # Create a new SyslogDevice. The options control how messages are written to syslog.
26
+ #
27
+ # The template can be specified using the <tt>:template</tt> option. This can
28
+ # either be a Proc or a string that will compile into a Template object.
29
+ # If the template is a Proc, it should accept an LogEntry as its only argument and output a string.
30
+ # If the template is a template string, it will be used to create a Template.
31
+ # The default template is <tt>":message (#:unit_of_work_id)"</tt>.
32
+ #
33
+ # The <tt>:close_connection</tt> option can be used to specify that the connection to syslog should be
34
+ # closed after every +write+ call. This will slow down performance, but will allow you to use syslog
35
+ # elsewhere in your application.
36
+ #
37
+ # The <tt>:options</tt> option will pass through options to syslog. The default is
38
+ # <tt>Syslog::LOG_PID | Syslog::LOG_CONS</tt>. Available values for the bit map are:
39
+ # * <tt>Syslog::LOG_CONS</tt> - Write directly to system console if there is an error while sending to system logger.
40
+ # * <tt>Syslog::LOG_NDELAY</tt> - Open the connection immediately (normally, the connection is opened when the first message is logged).
41
+ # * <tt>Syslog::LOG_NOWAIT</tt> - Don't wait for child processes that may have been created while logging the message.
42
+ # * <tt>Syslog::LOG_ODELAY</tt> - The converse of LOG_NDELAY; opening of the connection is delayed.
43
+ # * <tt>Syslog::LOG_PERROR</tt> - Print to stderr as well.
44
+ # * <tt>Syslog::LOG_PID</tt> - Include PID with each message.
45
+ #
46
+ # The <tt>:facility</tt> option will pass through a facility to syslog. Available values are
47
+ # * <tt>Syslog::LOG_AUTH</tt>
48
+ # * <tt>Syslog::LOG_AUTHPRIV</tt>
49
+ # * <tt>Syslog::LOG_CRON</tt>
50
+ # * <tt>Syslog::LOG_DAEMON</tt>
51
+ # * <tt>Syslog::LOG_FTP</tt>
52
+ # * <tt>Syslog::LOG_KERN</tt>
53
+ # * <tt>Syslog::LOG_LOCAL0</tt> through <tt>Syslog::LOG_LOCAL7</tt>
54
+ # * <tt>Syslog::LOG_LPR</tt>
55
+ # * <tt>Syslog::LOG_MAIL</tt>
56
+ # * <tt>Syslog::LOG_NEWS</tt>
57
+ # * <tt>Syslog::LOG_SYSLOG</tt>
58
+ # * <tt>Syslog::LOG_USER</tt> (default)
59
+ # * <tt>Syslog::LOG_UUCP</tt>
60
+ def initialize(options = {})
61
+ @template = options[:template] || lambda{|entry| entry.unit_of_work_id ? "#{entry.message} (##{entry.unit_of_work_id})" : entry.message}
62
+ @template = Template.new(@template) if @template.is_a?(String)
63
+ @syslog_options = options[:options] || (Syslog::LOG_PID | Syslog::LOG_CONS)
64
+ @syslog_facility = options[:facility]
65
+ @close_connection = options[:close_connection]
66
+ @syslog_identity = nil
67
+ end
68
+
69
+ def write(entry)
70
+ message = @template.call(entry).gsub(PERCENT, ESCAPED_PERCENT)
71
+ @@lock.synchronize do
72
+ syslog = open_syslog(entry.progname)
73
+ begin
74
+ syslog.log(SEVERITY_MAP[entry.severity], message)
75
+ ensure
76
+ syslog.close if @close_connection
77
+ end
78
+ end
79
+ end
80
+
81
+ def close
82
+ flush
83
+ @lock.synchronize do
84
+ @syslog.close if @syslog && @syslog.opened?
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ # Open syslog with ident set to progname. If it is already open with a different
91
+ # ident, close it and reopen it.
92
+ def open_syslog(progname) #:nodoc:
93
+ if Syslog.opened?
94
+ if (progname.nil? || Syslog.ident == progname) && @syslog_facility == Syslog.facility && @syslog_options == Syslog.options
95
+ return Syslog
96
+ end
97
+ Syslog.close
98
+ end
99
+ syslog = Syslog.open(progname, @syslog_options, @syslog_facility)
100
+ syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_DEBUG)
101
+ syslog
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lumberjack::SyslogDevice do
4
+
5
+ let(:time){ Time.parse("2011-02-01T18:32:31Z") }
6
+ let(:entry){ Lumberjack::LogEntry.new(time, Lumberjack::Severity::WARN, "message 1", "lumberjack_syslog_device_spec", 12345, "ABCD") }
7
+
8
+ context "open connecton" do
9
+ it "should be able to specify syslog options" do
10
+ syslog = MockSyslog.new
11
+ device = Lumberjack::SyslogDevice.new(:options => Syslog::LOG_CONS)
12
+ Syslog.should_receive(:open).with(entry.progname, Syslog::LOG_CONS, nil).and_return(syslog)
13
+ device.write(entry)
14
+ end
15
+
16
+ it "should be able to specify a syslog facility" do
17
+ syslog = MockSyslog.new
18
+ device = Lumberjack::SyslogDevice.new(:facility => Syslog::LOG_FTP)
19
+ Syslog.should_receive(:open).with(entry.progname, (Syslog::LOG_PID | Syslog::LOG_CONS), Syslog::LOG_FTP).and_return(syslog)
20
+ device.write(entry)
21
+ end
22
+
23
+ it "should log all messages since the logger will filter them by severity" do
24
+ syslog = MockSyslog.new
25
+ device = Lumberjack::SyslogDevice.new
26
+ Syslog.should_receive(:open).with(entry.progname, (Syslog::LOG_PID | Syslog::LOG_CONS), nil).and_return(syslog)
27
+ device.write(entry)
28
+ syslog.mask.should == Syslog::LOG_UPTO(Syslog::LOG_DEBUG)
29
+ end
30
+ end
31
+
32
+ context "logging" do
33
+ it "should log entries to syslog" do
34
+ entry.unit_of_work_id = nil
35
+ device = Lumberjack::SyslogDevice.new
36
+ messages = read_syslog do
37
+ device.write(entry)
38
+ end
39
+ messages.first.should include("message 1")
40
+ end
41
+
42
+ it "should log output to syslog with the unit of work id if it exists" do
43
+ device = Lumberjack::SyslogDevice.new
44
+ messages = read_syslog do
45
+ device.write(entry)
46
+ end
47
+ messages.first.should include("message 1 (#ABCD)")
48
+ end
49
+
50
+ it "should be able to specify a string template" do
51
+ device = Lumberjack::SyslogDevice.new(:template => ":unit_of_work_id - :message")
52
+ messages = read_syslog do
53
+ device.write(entry)
54
+ end
55
+ messages.first.should include("ABCD - message 1")
56
+ end
57
+
58
+ it "should be able to specify a proc template" do
59
+ device = Lumberjack::SyslogDevice.new(:template => lambda{|e| e.message.upcase})
60
+ messages = read_syslog do
61
+ device.write(entry)
62
+ end
63
+ messages.first.should include("MESSAGE 1")
64
+ end
65
+
66
+ it "should properly handle percent signs in the syslog message" do
67
+ device = Lumberjack::SyslogDevice.new
68
+ entry.message = "message 100%"
69
+ messages = read_syslog do
70
+ device.write(entry)
71
+ end
72
+ messages.first.should include("message 100% (#ABCD)")
73
+ end
74
+
75
+ it "should convert lumberjack severities to syslog severities" do
76
+ syslog = MockSyslog.new
77
+ device = Lumberjack::SyslogDevice.new
78
+ Syslog.stub!(:open).and_return(syslog)
79
+ syslog.should_receive(:log).with(Syslog::LOG_DEBUG, "debug")
80
+ syslog.should_receive(:log).with(Syslog::LOG_INFO, "info")
81
+ syslog.should_receive(:log).with(Syslog::LOG_WARNING, "warn")
82
+ syslog.should_receive(:log).with(Syslog::LOG_ERR, "error")
83
+ syslog.should_receive(:log).with(Syslog::LOG_CRIT, "fatal")
84
+ device.write(Lumberjack::LogEntry.new(Time.now, Lumberjack::Severity::DEBUG, "debug", "lumberjack_syslog_device_spec", 12345, nil))
85
+ device.write(Lumberjack::LogEntry.new(Time.now, Lumberjack::Severity::INFO, "info", "lumberjack_syslog_device_spec", 12345, nil))
86
+ device.write(Lumberjack::LogEntry.new(Time.now, Lumberjack::Severity::WARN, "warn", "lumberjack_syslog_device_spec", 12345, nil))
87
+ device.write(Lumberjack::LogEntry.new(Time.now, Lumberjack::Severity::ERROR, "error", "lumberjack_syslog_device_spec", 12345, nil))
88
+ device.write(Lumberjack::LogEntry.new(Time.now, Lumberjack::Severity::FATAL, "fatal", "lumberjack_syslog_device_spec", 12345, nil))
89
+ end
90
+
91
+ it "should log messages with the syslog ident set to the progname" do
92
+ device = Lumberjack::SyslogDevice.new
93
+ messages = read_syslog("lumberjack_syslog_device") do
94
+ device.write(entry)
95
+ entry.progname = "spec_for_lumberjack_syslog_device"
96
+ entry.message = "new message"
97
+ device.write(entry)
98
+ end
99
+ messages.first.should include("lumberjack_syslog_device_spec")
100
+ messages.last.should include("spec_for_lumberjack_syslog_device")
101
+ end
102
+
103
+ it "should keep open the syslog connection by default" do
104
+ device = Lumberjack::SyslogDevice.new
105
+ messages = read_syslog do
106
+ device.write(entry)
107
+ Syslog.should be_opened
108
+ end
109
+ end
110
+
111
+ it "should close the syslog connection if :close_connection is true" do
112
+ device = Lumberjack::SyslogDevice.new(:close_connection => true)
113
+ messages = read_syslog do
114
+ device.write(entry)
115
+ Syslog.should_not be_opened
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path("../../lib/lumberjack_syslog_device.rb", __FILE__)
2
+
3
+ SYSLOG_FILE = ENV["SYSLOG_FILE"] || "/var/log/system.log"
4
+
5
+ # Round about way of reading syslog by following it using the command line and looking in the output.
6
+ def read_syslog(progname = "lumberjack_syslog_device_spec")
7
+ message_id = rand(0xFFFFFFFFFFFFFFFF)
8
+ Syslog.open("lumberjack_syslog_device_spec") do |syslog|
9
+ syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_DEBUG)
10
+ syslog.warning("************** start #{message_id}")
11
+ end
12
+
13
+ yield
14
+
15
+ Syslog.close if Syslog.opened?
16
+ Syslog.open("lumberjack_syslog_device_spec") do |syslog|
17
+ syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_DEBUG)
18
+ syslog.warning("************** end #{message_id}")
19
+ end
20
+
21
+ # Loop over the syslog file until the start and end markers are found
22
+ 8.times do
23
+ retval = nil
24
+ lines = `tail -500 #{SYSLOG_FILE}`.split("\n")
25
+ lines.each do |line|
26
+ if line.include?("start #{message_id}")
27
+ retval = []
28
+ elsif line.include?("end #{message_id}")
29
+ return retval
30
+ else
31
+ retval << line if retval && line.include?(progname)
32
+ end
33
+ end
34
+ break if retval
35
+ sleep(0.25)
36
+ end
37
+ raise "could not find message logged to #{SYSLOG_FILE}"
38
+ end
39
+
40
+ class MockSyslog
41
+ attr_accessor :mask
42
+ attr_reader :ident, :options, :facility
43
+
44
+ def open(ident, options, facility)
45
+ @ident = ident
46
+ @options = options
47
+ @facility = facility
48
+ end
49
+
50
+ def log(*args)
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lumberjack_syslog_device
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Brian Durand
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-11 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: lumberjack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 1
32
+ - 0
33
+ version: "1.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: A logging device for the lumberjack gem that writes log entries to syslog.
37
+ email:
38
+ - bdurand@embellishedvisions.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - README.rdoc
45
+ files:
46
+ - README.rdoc
47
+ - VERSION
48
+ - Rakefile
49
+ - MIT_LICENSE
50
+ - lib/lumberjack_syslog_device.rb
51
+ - spec/lumberjack_syslog_device_spec.rb
52
+ - spec/spec_helper.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/bdurand/lumberjack_mongo_device
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --charset=UTF-8
60
+ - --main
61
+ - README.rdoc
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirements: []
83
+
84
+ rubyforge_project:
85
+ rubygems_version: 1.5.0
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: A logging device for the lumberjack gem that writes log entries to syslog.
89
+ test_files: []
90
+