Skip to content

Commit

Permalink
Merge pull request #59 from dwbutler/syslog
Browse files Browse the repository at this point in the history
Support for logging to syslog
  • Loading branch information
dwbutler committed Sep 8, 2015
2 parents 2b84d6e + cb01341 commit 106f59a
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 14 deletions.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ writing to a file or syslog since logstash can receive the structured data direc
## Features

* Can write directly to logstash over a UDP or TCP/SSL connection.
* Can write to a file, Redis, a unix socket, stdout or stderr.
* Can write to a file, Redis, Kafka, a unix socket, syslog, stdout, or stderr.
* Writes in logstash JSON format, but supports other formats as well.
* Can write to multiple outputs.
* Logger can take a string message, a hash, a `LogStash::Event`, an object, or a JSON string as input.
Expand Down Expand Up @@ -44,6 +44,7 @@ tcp_logger = LogStashLogger.new(type: :tcp, host: 'localhost', port: 5229)
# Other types of loggers
file_logger = LogStashLogger.new(type: :file, path: 'log/development.log', sync: true)
unix_logger = LogStashLogger.new(type: :unix, path: '/tmp/sock')
syslog_logger = LogStashLogger.new(type: :syslog)
redis_logger = LogStashLogger.new(type: :redis)
kafka_logger = LogStashLogger.new(type: :kafka)
stdout_logger = LogStashLogger.new(type: :stdout)
Expand Down Expand Up @@ -75,14 +76,16 @@ ruby_default_formatter_logger = LogStashLogger.new(
)

# Send messages to multiple outputs. Each output will have the same format.
# Syslog cannot be an output because it requires a separate logger.
multi_delegating_logger = LogStashLogger.new(
type: :multi_delegator,
outputs: [
{ type: :file, path: 'log/development.log' },
{ type: :udp, host: 'localhost', port: 5228 }
])

# Balance messages between several outputs
# Balance messages between several outputs.
# Works the same as multi delegator, but randomly chooses an output to send each message.
balancer_logger = LogStashLogger.new(
type: :balancer,
outputs: [
Expand All @@ -92,6 +95,7 @@ balancer_logger = LogStashLogger.new(

# Send messages to multiple loggers.
# Use this if you need to send different formats to different outputs.
# If you need to log to syslog, you must use this.
multi_logger = LogStashLogger.new(
type: :multi_logger,
outputs: [
Expand Down Expand Up @@ -305,6 +309,25 @@ config.logstash.type = :unix
config.logstash.path = '/tmp/sock'
```

#### Syslog

If you're on Ruby 1.9, add `Syslog::Logger` v2 to your Gemfile:

gem 'SyslogLogger', '2.0'

If you're on Ruby 2+, `Syslog::Logger` is already built into the standard library.

```ruby
# Required
config.logstash.type = :syslog

# Optional. Defaults to 'ruby'
config.logstash.program_name = 'MyApp'

# Optional default facility level. Only works in Ruby 2+
config.logstash.facility = Syslog::LOG_LOCAL0
```

#### Redis

Add the redis gem to your Gemfile:
Expand Down
54 changes: 42 additions & 12 deletions lib/logstash-logger/logger.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
require 'logger'
require 'logstash-logger/tagged_logging'

autoload :Syslog, 'syslog'
module Syslog
autoload :Logger, 'syslog/logger'
end

module LogStashLogger
autoload :MultiLogger, 'logstash-logger/multi_logger'

Expand Down Expand Up @@ -45,20 +50,45 @@ def self.extract_opts(*args)
end

def self.build_logger(opts)
case opts[:type]
formatter = Formatter.new(opts.delete(:formatter))

logger = case opts[:type]
when :multi_logger
loggers = opts[:outputs].map {|logger_opts| build_logger(logger_opts) }
MultiLogger.new(loggers)
build_multi_logger(opts)
when :syslog
build_syslog_logger(opts)
else
formatter = Formatter.new(opts.delete(:formatter))
device = Device.new(opts)

::Logger.new(device).tap do |logger|
logger.instance_variable_set(:@device, device)
logger.extend(self)
logger.extend(TaggedLogging)
logger.formatter = formatter
end
build_default_logger(opts)
end

logger.formatter = formatter if formatter
logger
end

private

def self.build_default_logger(opts)
device = Device.new(opts)
::Logger.new(device).tap do |logger|
logger.instance_variable_set(:@device, device)
logger.extend(self)
logger.extend(TaggedLogging)
end
end

def self.build_multi_logger(opts)
loggers = opts[:outputs].map { |logger_opts| build_logger(logger_opts) }
MultiLogger.new(loggers)
end

def self.build_syslog_logger(opts)
logger = begin
Syslog::Logger.new(opts[:program_name], opts[:facility])
rescue ArgumentError
Syslog::Logger.new(opts[:program_name])
end

logger.extend(self)
logger.extend(TaggedLogging)
end
end
4 changes: 4 additions & 0 deletions logstash-logger.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Gem::Specification.new do |gem|
gem.add_development_dependency 'redis'
gem.add_development_dependency 'poseidon'

if RUBY_VERSION < '2'
gem.add_development_dependency 'SyslogLogger'
end

gem.add_development_dependency 'rspec', '>= 3'
gem.add_development_dependency 'rake'
gem.add_development_dependency 'pry'
Expand Down
10 changes: 10 additions & 0 deletions samples/syslog.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
input {
syslog {
codec => json_lines
}
}
output {
stdout {
codec => json_lines
}
}
25 changes: 25 additions & 0 deletions spec/syslog_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'logstash-logger'

describe LogStashLogger do
context "Syslog" do
let(:program_name) { "MyApp" }
let(:facility) { Syslog::LOG_LOCAL0 }
subject { LogStashLogger.new(type: :syslog, program_name: program_name, facility: facility) }
let(:syslog) { subject.class.class_variable_get(:@@syslog) }

it { is_expected.to be_a Syslog::Logger }

it "writes formatted messages to syslog" do
expect(syslog).to receive(:log)
subject.info("test")
end

it "sets the syslog identity" do
expect(syslog.ident).to eq(program_name)
end

it "sets the default facility if supported" do
expect(subject.facility).to eq(facility) if subject.respond_to?(:facility)
end
end
end

0 comments on commit 106f59a

Please sign in to comment.