From 09a4937b2fcf883fa57af1dfa5d12f605f812970 Mon Sep 17 00:00:00 2001 From: knu Date: Mon, 26 Nov 2001 12:00:40 +0000 Subject: [PATCH] Import the "syslog" module from the rough ruby project. This module provides the interface to the UNIX system logger (syslog). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1860 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 + doc/NEWS | 4 + ext/Setup | 1 + ext/Setup.dj | 1 + ext/Setup.emx | 1 + ext/Setup.nt | 1 + ext/Setup.x68 | 1 + ext/syslog/MANIFEST | 5 + ext/syslog/extconf.rb | 10 ++ ext/syslog/syslog.c | 409 ++++++++++++++++++++++++++++++++++++++++++ ext/syslog/syslog.txt | 124 +++++++++++++ ext/syslog/test.rb | 161 +++++++++++++++++ 12 files changed, 723 insertions(+) create mode 100644 ext/syslog/MANIFEST create mode 100644 ext/syslog/extconf.rb create mode 100644 ext/syslog/syslog.c create mode 100644 ext/syslog/syslog.txt create mode 100644 ext/syslog/test.rb diff --git a/ChangeLog b/ChangeLog index bb448c42c6..3159db3e4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Nov 26 20:57:24 2001 Akinori MUSHA + + * ext/Setup*, ext/syslog/*: import the "syslog" module from the + rough ruby project. + Mon Nov 26 16:54:59 2001 Usaku Nakamura * win32/win32.c (mypopen): fixed that mypclose() didn't really close diff --git a/doc/NEWS b/doc/NEWS index 0e84050c59..1a5634d64b 100644 --- a/doc/NEWS +++ b/doc/NEWS @@ -1,3 +1,7 @@ +: Syslog module + + Imported. + : String#chomp if $/ == '\n', chops off last newlines (any of \n, \r, \r\n). diff --git a/ext/Setup b/ext/Setup index cc412e8667..df88155294 100644 --- a/ext/Setup +++ b/ext/Setup @@ -14,6 +14,7 @@ #pty #sdbm #socket +#syslog #tk #tcltklib #gtk diff --git a/ext/Setup.dj b/ext/Setup.dj index 3c01afa747..7d7aa7f87e 100644 --- a/ext/Setup.dj +++ b/ext/Setup.dj @@ -16,4 +16,5 @@ marshal readline sdbm #socket +#syslog #tkutil diff --git a/ext/Setup.emx b/ext/Setup.emx index c85f724d9f..bba3d76887 100644 --- a/ext/Setup.emx +++ b/ext/Setup.emx @@ -16,5 +16,6 @@ nkf #readline #sdbm socket +#syslog #tcltklib #tk diff --git a/ext/Setup.nt b/ext/Setup.nt index 39b9030987..cb0014350b 100644 --- a/ext/Setup.nt +++ b/ext/Setup.nt @@ -19,5 +19,6 @@ nkf #readline sdbm socket +#syslog #tcltklib #tk diff --git a/ext/Setup.x68 b/ext/Setup.x68 index 25e9544d76..84b8902732 100644 --- a/ext/Setup.x68 +++ b/ext/Setup.x68 @@ -13,4 +13,5 @@ fcntl kconv marshal #socket +#syslog #tkutil diff --git a/ext/syslog/MANIFEST b/ext/syslog/MANIFEST new file mode 100644 index 0000000000..67c588a36e --- /dev/null +++ b/ext/syslog/MANIFEST @@ -0,0 +1,5 @@ +MANIFEST +extconf.rb +syslog.c +syslog.txt +test.rb diff --git a/ext/syslog/extconf.rb b/ext/syslog/extconf.rb new file mode 100644 index 0000000000..0fa0bc339b --- /dev/null +++ b/ext/syslog/extconf.rb @@ -0,0 +1,10 @@ +# $RoughId: extconf.rb,v 1.3 2001/11/24 17:49:26 knu Exp $ +# $Id$ + +require 'mkmf' + +have_header("syslog.h") && + have_func("openlog") && + have_func("setlogmask") && + create_makefile("syslog") + diff --git a/ext/syslog/syslog.c b/ext/syslog/syslog.c new file mode 100644 index 0000000000..5bd577caad --- /dev/null +++ b/ext/syslog/syslog.c @@ -0,0 +1,409 @@ +/* + * UNIX Syslog extension for Ruby + * Amos Gouaux, University of Texas at Dallas + * + * + * $RoughId: syslog.c,v 1.17 2001/11/24 12:42:39 knu Exp $ + * $Id$ + */ + +#include "ruby.h" +#include + +/* Syslog class */ +static VALUE cSyslog, mSyslogConstants; +static VALUE syslog_instance = Qnil, syslog_ident, syslog_options, + syslog_facility, syslog_mask; +static int syslog_opened = 0; + +/* Package helper routines */ +static void syslog_write(int pri, int argc, VALUE *argv) +{ + VALUE str; + + if (argc < 1) { + rb_raise(rb_eArgError, "no log message supplied"); + } + + if (!syslog_opened) { + rb_raise(rb_eRuntimeError, "must open syslog before write"); + } + + str = rb_f_sprintf(argc, argv); + + syslog(pri, "%s", RSTRING(str)->ptr); +} + +/* Syslog instance methods */ +static VALUE cSyslog_close(VALUE self) +{ + closelog(); + syslog_opened = 0; + + return Qnil; +} + +static VALUE cSyslog_open(int argc, VALUE *argv, VALUE self) +{ + VALUE ident, opt, fac; + int mask; + + if (syslog_opened) { + rb_raise(rb_eRuntimeError, "syslog already open"); + } + rb_scan_args(argc, argv, "03", &ident, &opt, &fac); + if (NIL_P(ident)) { + ident = rb_gv_get("$0"); + } + if (NIL_P(opt)) { + opt = INT2NUM(LOG_PID | LOG_CONS); + } + if (NIL_P(fac)) { + fac = INT2NUM(LOG_USER); + } + + Check_SafeStr(ident); + syslog_ident = ident; + syslog_options = opt; + syslog_facility = fac; + openlog(RSTRING(ident)->ptr, NUM2INT(opt), NUM2INT(fac)); + syslog_opened = 1; + + setlogmask(mask = setlogmask(0)); + syslog_mask = INT2NUM(mask); + + /* be like File.new.open {...} */ + if (rb_block_given_p()) { + rb_ensure(rb_yield, self, cSyslog_close, self); + } + + return self; +} + +static VALUE cSyslog_init(VALUE self) +{ + syslog_instance = self; + syslog_opened = 0; + syslog_ident = Qnil; + syslog_options = syslog_facility = syslog_mask = INT2FIX(-1); + + return self; +} + +static VALUE cSyslog_reopen(int argc, VALUE *argv, VALUE self) +{ + cSyslog_close(self); + + return cSyslog_open(argc, argv, self); +} + +static VALUE cSyslog_isopen(VALUE self) +{ + return syslog_opened ? Qtrue : Qfalse; +} + +static VALUE cSyslog_ident(VALUE self) +{ + return syslog_ident; +} + +static VALUE cSyslog_options(VALUE self) +{ + return syslog_options; +} + +static VALUE cSyslog_facility(VALUE self) +{ + return syslog_facility; +} + +static VALUE cSyslog_get_mask(VALUE self) +{ + return syslog_mask; +} + +static VALUE cSyslog_set_mask(VALUE self, VALUE mask) +{ + if (!syslog_opened) { + rb_raise(rb_eRuntimeError, "must open syslog before setting log mask"); + } + + setlogmask(NUM2INT(mask)); + syslog_mask = mask; + + return mask; +} + +static VALUE cSyslog_log(int argc, VALUE *argv, VALUE self) +{ + VALUE pri; + + if (argc < 2) { + rb_raise(rb_eArgError, "wrong # of arguments(%d for 2+)", argc); + } + + argc--; + pri = *argv++; + + if (!FIXNUM_P(pri)) { + rb_raise(rb_eTypeError, "type mismatch: %s given", rb_class2name(CLASS_OF(pri))); + } + + syslog_write(FIX2INT(pri), argc, argv); + + return self; +} + +static VALUE cSyslog_inspect(VALUE self) +{ +#define N 7 + int argc = N; + VALUE argv[N]; + const char fmt[] = + "<#%s: opened=%s, ident=\"%s\", options=%d, facility=%d, mask=%d>"; + + argv[0] = rb_str_new(fmt, sizeof(fmt) - 1); + argv[1] = cSyslog; + argv[2] = syslog_opened ? Qtrue : Qfalse; + argv[3] = syslog_ident; + argv[4] = syslog_options; + argv[5] = syslog_facility; + argv[6] = syslog_mask; + + return rb_f_sprintf(argc, argv); +#undef N +} + +#define define_syslog_shortcut_method(pri, name) \ +static VALUE cSyslog_##name(int argc, VALUE *argv, VALUE self) \ +{ \ + syslog_write(pri, argc, argv); \ +\ + return self; \ +} + +#ifdef LOG_EMERG +define_syslog_shortcut_method(LOG_EMERG, emerg) +#endif +#ifdef LOG_ALERT +define_syslog_shortcut_method(LOG_ALERT, alert) +#endif +#ifdef LOG_CRIT +define_syslog_shortcut_method(LOG_CRIT, crit) +#endif +#ifdef LOG_ERR +define_syslog_shortcut_method(LOG_ERR, err) +#endif +#ifdef LOG_WARNING +define_syslog_shortcut_method(LOG_WARNING, warning) +#endif +#ifdef LOG_NOTICE +define_syslog_shortcut_method(LOG_NOTICE, notice) +#endif +#ifdef LOG_INFO +define_syslog_shortcut_method(LOG_INFO, info) +#endif +#ifdef LOG_DEBUG +define_syslog_shortcut_method(LOG_DEBUG, debug) +#endif + +/* Syslog class methods */ +static VALUE cSyslog_s_instance(VALUE klass) +{ + VALUE obj; + + obj = syslog_instance; + + if (NIL_P(obj)) { + obj = rb_obj_alloc(klass); + rb_obj_call_init(obj, 0, NULL); + } + + return obj; +} + +static VALUE cSyslog_s_open(int argc, VALUE *argv, VALUE klass) +{ + VALUE obj; + + obj = cSyslog_s_instance(klass); + + cSyslog_open(argc, argv, obj); + + return obj; +} + +static VALUE cSyslog_s_LOG_MASK(VALUE klass, VALUE pri) +{ + return INT2FIX(LOG_MASK(FIX2INT(pri))); +} + +static VALUE cSyslog_s_LOG_UPTO(VALUE klass, VALUE pri) +{ + return INT2FIX(LOG_UPTO(FIX2INT(pri))); +} + +/* Init for package syslog */ +void Init_syslog() +{ + cSyslog = rb_define_class("Syslog", rb_cObject); + + mSyslogConstants = rb_define_module_under(cSyslog, "Constants"); + + rb_include_module(cSyslog, mSyslogConstants); + + rb_define_module_function(cSyslog, "open", cSyslog_s_open, -1); + rb_define_module_function(cSyslog, "instance", cSyslog_s_instance, 0); + rb_define_module_function(cSyslog, "LOG_MASK", cSyslog_s_LOG_MASK, 1); + rb_define_module_function(cSyslog, "LOG_UPTO", cSyslog_s_LOG_UPTO, 1); + + rb_undef_method(CLASS_OF(cSyslog), "new"); + + rb_define_method(cSyslog, "initialize", cSyslog_init, 0); + rb_define_method(cSyslog, "open", cSyslog_open, -1); + rb_define_method(cSyslog, "reopen", cSyslog_reopen, -1); + rb_define_method(cSyslog, "open!", cSyslog_reopen, -1); + rb_define_method(cSyslog, "opened?", cSyslog_isopen, 0); + + rb_define_method(cSyslog, "ident", cSyslog_ident, 0); + rb_define_method(cSyslog, "options", cSyslog_options, 0); + rb_define_method(cSyslog, "facility", cSyslog_facility, 0); + + rb_define_method(cSyslog, "log", cSyslog_log, -1); + rb_define_method(cSyslog, "close", cSyslog_close, 0); + rb_define_method(cSyslog, "mask", cSyslog_get_mask, 0); + rb_define_method(cSyslog, "mask=", cSyslog_set_mask, 1); + + rb_define_method(cSyslog, "inspect", cSyslog_inspect, 0); + +#define rb_define_syslog_const(id) \ + rb_define_const(mSyslogConstants, #id, INT2NUM(id)) + + /* Various options when opening log */ +#ifdef LOG_PID + rb_define_syslog_const(LOG_PID); +#endif +#ifdef LOG_CONS + rb_define_syslog_const(LOG_CONS); +#endif +#ifdef LOG_ODELAY + rb_define_syslog_const(LOG_ODELAY); /* deprecated */ +#endif +#ifdef LOG_NDELAY + rb_define_syslog_const(LOG_NDELAY); +#endif +#ifdef LOG_NOWAIT + rb_define_syslog_const(LOG_NOWAIT); /* deprecated */ +#endif +#ifdef LOG_PERROR + rb_define_syslog_const(LOG_PERROR); +#endif + + /* Various syslog facilities */ +#ifdef LOG_AUTH + rb_define_syslog_const(LOG_AUTH); +#endif +#ifdef LOG_AUTHPRIV + rb_define_syslog_const(LOG_AUTHPRIV); +#endif +#ifdef LOG_CONSOLE + rb_define_syslog_const(LOG_CONSOLE); +#endif +#ifdef LOG_CRON + rb_define_syslog_const(LOG_CRON); +#endif +#ifdef LOG_DAEMON + rb_define_syslog_const(LOG_DAEMON); +#endif +#ifdef LOG_FTP + rb_define_syslog_const(LOG_FTP); +#endif +#ifdef LOG_KERN + rb_define_syslog_const(LOG_KERN); +#endif +#ifdef LOG_LPR + rb_define_syslog_const(LOG_LPR); +#endif +#ifdef LOG_MAIL + rb_define_syslog_const(LOG_MAIL); +#endif +#ifdef LOG_NEWS + rb_define_syslog_const(LOG_NEWS); +#endif +#ifdef LOG_NTP + rb_define_syslog_const(LOG_NTP); +#endif +#ifdef LOG_SECURITY + rb_define_syslog_const(LOG_SECURITY); +#endif +#ifdef LOG_SYSLOG + rb_define_syslog_const(LOG_SYSLOG); +#endif +#ifdef LOG_USER + rb_define_syslog_const(LOG_USER); +#endif +#ifdef LOG_UUCP + rb_define_syslog_const(LOG_UUCP); +#endif +#ifdef LOG_LOCAL0 + rb_define_syslog_const(LOG_LOCAL0); +#endif +#ifdef LOG_LOCAL1 + rb_define_syslog_const(LOG_LOCAL1); +#endif +#ifdef LOG_LOCAL2 + rb_define_syslog_const(LOG_LOCAL2); +#endif +#ifdef LOG_LOCAL3 + rb_define_syslog_const(LOG_LOCAL3); +#endif +#ifdef LOG_LOCAL4 + rb_define_syslog_const(LOG_LOCAL4); +#endif +#ifdef LOG_LOCAL5 + rb_define_syslog_const(LOG_LOCAL5); +#endif +#ifdef LOG_LOCAL6 + rb_define_syslog_const(LOG_LOCAL6); +#endif +#ifdef LOG_LOCAL7 + rb_define_syslog_const(LOG_LOCAL7); +#endif + +#define rb_define_syslog_shortcut(name) \ + rb_define_method(cSyslog, #name, cSyslog_##name, -1) + + /* Various syslog priorities and the shortcut methods */ +#ifdef LOG_EMERG + rb_define_syslog_const(LOG_EMERG); + rb_define_syslog_shortcut(emerg); +#endif +#ifdef LOG_ALERT + rb_define_syslog_const(LOG_ALERT); + rb_define_syslog_shortcut(alert); +#endif +#ifdef LOG_CRIT + rb_define_syslog_const(LOG_CRIT); + rb_define_syslog_shortcut(crit); +#endif +#ifdef LOG_ERR + rb_define_syslog_const(LOG_ERR); + rb_define_syslog_shortcut(err); +#endif +#ifdef LOG_WARNING + rb_define_syslog_const(LOG_WARNING); + rb_define_syslog_shortcut(warning); +#endif +#ifdef LOG_NOTICE + rb_define_syslog_const(LOG_NOTICE); + rb_define_syslog_shortcut(notice); +#endif +#ifdef LOG_INFO + rb_define_syslog_const(LOG_INFO); + rb_define_syslog_shortcut(info); +#endif +#ifdef LOG_DEBUG + rb_define_syslog_const(LOG_DEBUG); + rb_define_syslog_shortcut(debug); +#endif +} diff --git a/ext/syslog/syslog.txt b/ext/syslog/syslog.txt new file mode 100644 index 0000000000..d9dcfc4315 --- /dev/null +++ b/ext/syslog/syslog.txt @@ -0,0 +1,124 @@ +.\" syslog.txt - -*- Indented-Text -*- +$RoughId: syslog.txt,v 1.15 2001/11/25 21:21:23 knu Exp $ +$Id$ + +UNIX Syslog extension for Ruby +Amos Gouaux, University of Texas at Dallas + +& +Akinori MUSHA + + +** Syslog(Class) + +Superclass: Object + +Mix-ins: Syslog::Constants + +require 'syslog' + +A Simple wrapper for the UNIX syslog system calls that might be handy +if you're writing a server in Ruby. For the details of the syslog(8) +architecture and constants, see the syslog(3) manual page of your +platform. + +Class Methods: + + open(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS, + facility = Syslog::LOG_USER) [{ |syslog| ... }] + + Opens syslog with the given options and returns the singleton + object of the Syslog class. If a block is given, calls it + with an argument of the object. If syslog is already opened, + raises RuntimeError. + + Example: + sl = Syslog.open('ftpd', Syslog::LOG_PID | Syslog::LOG_NDELAY, + Syslog::LOG_FTP) + + instance + + Returns the singleton object. + + LOG_MASK(pri) + + Creates a mask for one priority. + + LOG_UPTO(pri) + + Creates a mask for all priorities up to pri. + +Methods: + + open(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS, + facility = Syslog::LOG_USER) + + Opens syslog with the given options. If syslog is already + opened, raises RuntimeError. + + open!(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS, + facility = Syslog::LOG_USER) + reopen(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS, + facility = Syslog::LOG_USER) + + Same as open, but does a close first. + + opened? + + Returns true if syslog opened, otherwise false. + + ident + options + facility + + Returns the parameters given in the last open, respectively. + Every call of Syslog::open/Syslog#open resets those values. + + log(pri, message, ...) + + Writes message to syslog. + + Example: + sl.log(Syslog::LOG_CRIT, "the sky is falling in %d seconds!", 10) + + crit(message, ...) + emerg(message, ...) + alert(message, ...) + err(message, ...) + warning(message, ...) + notice(message, ...) + info(message, ...) + debug(message, ...) + + These are shortcut methods of Syslog#log(). The Lineup may + vary depending on what priorities are defined on your system. + + Example: + sl.crit("the sky is falling in %d seconds!",5) + + mask + mask=(mask) + + Returns or sets the log priority mask. The value of the mask + is persistent and Syslog::open/Syslog#open/Syslog#close don't + reset it. + + Example: + sl.mask = Syslog::LOG_UPTO(Syslog::LOG_ERR) + + close + + Closes syslog. + + inspect + + Returns the "inspect" string of the object. + +** Syslog::Constants(Module) + +Superclass: Object + +require 'syslog' +include Syslog::Constants + +This module includes the LOG_* constants available on the system. diff --git a/ext/syslog/test.rb b/ext/syslog/test.rb new file mode 100644 index 0000000000..fd94f1e590 --- /dev/null +++ b/ext/syslog/test.rb @@ -0,0 +1,161 @@ +#!/usr/bin/env ruby +# $RoughId: test.rb,v 1.8 2001/11/24 18:11:32 knu Exp $ +# $Id$ + +# Please only run this test on machines reasonable for testing. +# If in doubt, ask your admin. + +require 'runit/testcase' +require 'runit/cui/testrunner' + +# Prepend current directory to load path for testing. +$:.unshift('.') + +require 'syslog' + +class TestSyslog < RUNIT::TestCase + def test_s_new + assert_exception(NameError) { + Syslog.new + } + end + + def test_s_instance + sl1 = Syslog.instance + sl2 = Syslog.open + sl3 = Syslog.instance + + assert_equal(sl1, sl2) + assert_equal(sl1, sl3) + ensure + sl1.close + end + + def test_s_open + # default parameters + sl = Syslog.open + + assert_equal($0, sl.ident) + assert_equal(Syslog::LOG_PID | Syslog::LOG_CONS, sl.options) + assert_equal(Syslog::LOG_USER, sl.facility) + + # open without close + assert_exception(RuntimeError) { + sl.open + } + + sl.close + + # given parameters + sl = Syslog.open("foo", Syslog::LOG_NDELAY | Syslog::LOG_PERROR, Syslog::LOG_DAEMON) + + assert_equal('foo', sl.ident) + assert_equal(Syslog::LOG_NDELAY | Syslog::LOG_PERROR, sl.options) + assert_equal(Syslog::LOG_DAEMON, sl.facility) + + sl.close + + # default parameters again (after close) + sl = Syslog.open + sl.close + + assert_equal($0, sl.ident) + assert_equal(Syslog::LOG_PID | Syslog::LOG_CONS, sl.options) + assert_equal(Syslog::LOG_USER, sl.facility) + + # block + param = nil + Syslog.open { |param| } + assert_equal(sl, param) + ensure + sl.close + end + + def test_opened? + sl = Syslog.instance + assert_equal(false, sl.opened?) + + sl.open + assert_equal(true, sl.opened?) + + sl.close + assert_equal(false, sl.opened?) + + sl.open { + assert_equal(true, sl.opened?) + } + + assert_equal(false, sl.opened?) + end + + def test_mask + sl = Syslog.open + + orig = sl.mask + + sl.mask = Syslog.LOG_UPTO(Syslog::LOG_ERR) + assert_equal(Syslog.LOG_UPTO(Syslog::LOG_ERR), sl.mask) + + sl.mask = Syslog.LOG_MASK(Syslog::LOG_CRIT) + assert_equal(Syslog.LOG_MASK(Syslog::LOG_CRIT), sl.mask) + + sl.mask = orig + ensure + sl.close + end + + def test_log + stderr = IO::pipe + + pid = fork { + stderr[0].close + STDERR.reopen(stderr[1]) + stderr[1].close + + options = Syslog::LOG_PERROR | Syslog::LOG_NDELAY + + Syslog.open("syslog_test", options) { |sl| + sl.log(Syslog::LOG_NOTICE, "test1 - hello, %s!", "world") + sl.notice("test1 - hello, %s!", "world") + } + + Syslog.open("syslog_test", options | Syslog::LOG_PID) { |sl| + sl.log(Syslog::LOG_CRIT, "test2 - pid") + sl.crit("test2 - pid") + } + exit! + } + + stderr[1].close + Process.waitpid(pid) + + # LOG_PERROR is not yet implemented on Cygwin. + return if RUBY_PLATFORM =~ /cygwin/ + + 2.times { + assert_equal("syslog_test: test1 - hello, world!\n", stderr[0].gets) + } + + 2.times { + assert_equal(format("syslog_test[%d]: test2 - pid\n", pid), stderr[0].gets) + } + end + + def test_inspect + Syslog.open { |sl| + assert_equal(format('<#%s: opened=%s, ident="%s", ' + + 'options=%d, facility=%d, mask=%d>', + Syslog, sl.opened?, sl.ident, + sl.options, sl.facility, sl.mask), + sl.inspect) + } + end +end + +if $0 == __FILE__ + suite = RUNIT::TestSuite.new + + suite.add_test(TestSyslog.suite) + + RUNIT::CUI::TestRunner.run(suite) +end