Last active
August 29, 2016 16:14
-
-
Save lpar/1092788 to your computer and use it in GitHub Desktop.
Ruby code to pump IBM Lotus Domino server logs to regular Unix syslog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# encoding: UTF-8 | |
# Script to take IBM Lotus Domino console input on stdin, and send it to | |
# syslog. | |
# | |
# Allows you to do all your logging via syslog, rather than having to | |
# keep weeks of data in log.nsf. | |
# | |
# In rsyslog, filter like this: | |
# :programname, isequal, "domino" -/var/log/domino.log | |
# | |
# See https://gist.github.com/1092764 for how to incorporate this into | |
# Domino startup using Daniel Nashed's rc_domino scripts. | |
# | |
# This code is placed in the public domain in order to aid integration of IBM | |
# software with standard POSIX logging. | |
require 'syslog' | |
require 'date' | |
# Syslog ident to use. | |
SYSLOG_IDENT = 'domino' | |
# The strptime format used to parse Domino timestamps | |
# Note that we add the (missing) current time zone before parsing them, | |
# hence the %z at the end. | |
TIMESTAMP_STRPTIME = '%m/%d/%Y %I:%M:%S %p %z' | |
# The regular expression used to spot thread IDs prepended to console output | |
LOG_THREADID = Regexp.new(/^\[([\d:-]+)\]\s+/) | |
# The regular expression used to parse the rest of the line | |
LOG_REGEXP = Regexp.new(/^(\d\d\/\d\d\/\d\d\d\d \d\d:\d\d:\d\d [AP]M){0,1}\s+(.*)$/) | |
# Number of seconds by which the parsed timestamp can differ from what | |
# we think the system date/time is, before we append the parsed timestamp | |
# to the end of the syslog message | |
TIMESTAMP_ACCURACY = 2 | |
# Strings and regexps used to work out severity | |
# LOG_EMERG - System is unusable | |
# LOG_ALERT - Action needs to be taken immediately | |
# LOG_CRIT - A critical condition has occurred | |
# LOG_ERR - An error occurred | |
# LOG_WARNING - Warning of a possible problem | |
# LOG_NOTICE - A normal but significant condition occurred | |
# LOG_INFO - Informational message | |
# LOG_DEBUG - Debugging information | |
SEVERITIES = { | |
Regexp.new(/Access control is set in .* to not allow replication from/) => Syslog::LOG_WARNING, | |
Regexp.new(/Access control is set in .* to not replicate/) => Syslog::LOG_WARNING, | |
"not authorized to" => Syslog::LOG_WARNING, | |
"Unable to find path to server." => Syslog::LOG_CRIT, | |
"No route is known from this host to " => Syslog::LOG_CRIT, | |
"The server is not responding" => Syslog::LOG_CRIT, | |
"Server not reachable on Cluster Port" => Syslog::LOG_CRIT, | |
Regexp.new(/Full text operations on database .* which is not full text indexed/) => Syslog::LOG_WARNING, | |
Regexp.new(/ATTEMPT TO ACCESS SERVER by .* was denied/) => Syslog::LOG_ERR, | |
Regexp.new(/Directory Assistance could not/) => Syslog::LOG_ERR, | |
"Corrupt Data Exception" => Syslog::LOG_ERR, | |
"Couldn't find design note" => Syslog::LOG_ERR, | |
Regexp.new(/\berror\b/) => Syslog::LOG_ERR, | |
"Warning:" => Syslog::LOG_WARNING | |
} | |
def severity(text) | |
SEVERITIES.each_pair do |condition, severity| | |
if text.match(condition) | |
return severity | |
end | |
end | |
return Syslog::LOG_INFO | |
end | |
syslog = Syslog.open(SYSLOG_IDENT, | |
Syslog::LOG_NDELAY | Syslog::LOG_PID, Syslog::LOG_DAEMON) | |
begin | |
# Domino still writes its console output in Latin-1, so convert on the fly | |
input = STDIN.set_encoding('iso-8859-1:UTF-8') | |
while line = input.gets | |
now = DateTime.now | |
zone = now.strftime('%z') | |
line.gsub!(/\s\s+/, ' ') | |
line.chop! | |
m = LOG_THREADID.match(line) | |
if m | |
threadid = m[1] | |
line.sub!(LOG_THREADID, '') | |
else | |
threadid = nil | |
end | |
m = LOG_REGEXP.match(line) | |
if m | |
message = m[2] | |
if m[1] | |
dt = "#{m[1]} #{zone}" | |
dts = DateTime.strptime(dt, TIMESTAMP_STRPTIME) | |
tdiff = 86400 * (dts - now).abs | |
if tdiff > TIMESTAMP_ACCURACY | |
message << " [#{m[0]}]" | |
end | |
sev = severity(message) | |
else | |
sev = severity(message) | |
end | |
syslog.log(sev, "%s", message) | |
end | |
end | |
rescue => e | |
syslog.log(Syslog::LOG_CRIT, 'Ruby exception in %s: %s', $0, e.inspect) | |
e.backtrace.each {|line| | |
syslog.log(Syslog::LOG_DEBUG, "%s", line)} | |
end |
@lpar, I found this helpful today when a customer was looking to get their Domino logs in Splunk. Thanks for posting.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Why dont you use nartive Domino functions to write to syslog ?
Just create an event handler in events4.nsf to forward everything to Unix syslog.