Ruby & Syslog & custom facility
I am very new playing with syslog.
We have decided to use syslog to track some 开发者_StackOverflow中文版special events in our Rails application.
The problem is that I don't want to use the default /var/log/system.log
file but use a custom one like /var/log/myapp_events.log
.
I see that for that I have to define my own facility in /etc/syslog.conf
like this:
myapp_events.* /var/log/myapp_events.log
After restarting syslogd I see that I can play with it directly into the bash console:
syslog -s -k Facility myapp_events Message "this is my message"
The message appears into the /var/log/myapp_events.log
as expected, but I cannot reproduce this behavior using the syslog ruby gem. I have tried:
require 'syslog'
Syslog.open('myapp_events', Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.warning 'this is my message' } # sends the message to system.log
Syslog.open('myapp_events', Syslog::LOG_PID | Syslog::LOG_CONS, 'myapp_events') { |s| s.warning 'this is my message' } # error because 'myapp_event' can't be converted to int.
I see that Syslog.open
has a third argument which is the facility but it has to be an integer and what I have is a string.
Any suggestion?
Definitely the syslog
ruby implementation doesn't allow us to use custom facilities.
The syslog
ruby implementation is using the syslog
[C implementation] (http://github.com/ruby/ruby/blob/trunk/ext/syslog/syslog.c#L36).
The syslog
C implementation only allows us to use a very short list of facility names: LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS, LOG_UUCP, UUCP , LOG_CRON, LOG_AUTHPRIV, LOG_FTP, LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7
.
So in the end what I did was to use one of the LOG_LOCALX
facilities that are already there for personal use.
Now I can configure syslog like this:
# /etc/syslog.conf
local5.* /var/log/myapp_events.log
And in Ruby do this:
Syslog.open('myapp', Syslog::LOG_PID, Syslog::LOG_LOCAL5) { |s| s.info 'this is my message' }
I think is the way that syslog
wants you to define custom facilities.
Logger isn't useful when you have multiple workers or threads, since the log messages get interleaved. This is why the default logger in Rails 3 is BufferedLogger.
This is also why you must use a buffering syslogger like rsyslog, or it will kill your performance. (I believe syslogd uses fsync() which is a synchronous call that waits to return.)
Take a look at Lumberjack.
It has support for Syslog as a log device, and you can specify facility as an option:
require 'lumberjack'
require 'lumberjack_syslog_device'
syslog_device = Lumberjack::SyslogDevice.new(:facility => 'myapp_events')
logger = Lumberjack::Logger.new(syslog_device)
logger.info "Hello, Syslog!"
Lumberjack also has quite a few other features that makes it worth a look.
You might want to look into using Logger
, which is very similar to syslog, only it is a bit more user-friendly. It has multiple levels of criticality, like Syslog, and offers log rolling based on size or age.
精彩评论