lumberjack_syslog_device 1.0.0

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