summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/rabbitmq-multi.pod6
-rw-r--r--docs/rabbitmqctl.pod18
-rw-r--r--include/rabbit.hrl2
-rw-r--r--include/rabbit_framing_spec.hrl2
-rw-r--r--packaging/RPMS/Fedora/Makefile1
-rw-r--r--packaging/RPMS/Fedora/init.d129
-rw-r--r--packaging/RPMS/Fedora/rabbitmq-server.logrotate12
-rw-r--r--packaging/RPMS/Fedora/rabbitmq-server.spec125
-rw-r--r--packaging/debs/Debian/debian/control2
-rw-r--r--packaging/debs/Debian/debian/copyright6
-rw-r--r--packaging/debs/Debian/debian/dirs1
-rw-r--r--packaging/debs/Debian/debian/init.d119
-rw-r--r--packaging/debs/Debian/debian/rabbitmq-server.logrotate12
-rw-r--r--packaging/debs/Debian/debian/rules1
-rwxr-xr-xscripts/rabbitmq-server2
-rw-r--r--scripts/rabbitmq-server.bat2
-rw-r--r--src/rabbit.erl131
-rw-r--r--src/rabbit_control.erl8
-rw-r--r--src/rabbit_error_logger_file_h.erl74
-rw-r--r--src/rabbit_misc.erl26
-rw-r--r--src/rabbit_multi.erl66
-rw-r--r--src/rabbit_sasl_report_file_h.erl86
-rw-r--r--src/rabbit_tests.erl184
23 files changed, 805 insertions, 210 deletions
diff --git a/docs/rabbitmq-multi.pod b/docs/rabbitmq-multi.pod
index 2e3f28c8..65d05833 100644
--- a/docs/rabbitmq-multi.pod
+++ b/docs/rabbitmq-multi.pod
@@ -23,9 +23,15 @@ start_all I<count>
start count nodes with unique names, listening on all IP addresses
and on sequential ports starting from 5672.
+status
+ print the status of all running RabbitMQ nodes
+
stop_all
stop all local RabbitMQ nodes
+rotate_logs
+ rotate log files for all local and running RabbitMQ nodes
+
=head1 EXAMPLES
Start 3 local RabbitMQ nodes with unique, sequential port numbers:
diff --git a/docs/rabbitmqctl.pod b/docs/rabbitmqctl.pod
index db31b621..b34cbca7 100644
--- a/docs/rabbitmqctl.pod
+++ b/docs/rabbitmqctl.pod
@@ -66,6 +66,19 @@ force_reset
It should only be used as a last resort if the database or cluster
configuration has been corrupted.
+rotate_logs [suffix]
+ instruct the RabbitMQ node to rotate the log files. The RabbitMQ
+ broker will attempt to append the current contents of the log file
+ to the file with the name composed of the original name and the
+ suffix. It will create a new file if such a file does not already
+ exist. When no I<suffix> is specified, the empty log file is
+ simply created at the original location; no rotation takes place.
+ When an error occurs while appending the contents of the old log
+ file, the operation behaves in the same way as if no I<suffix> was
+ specified.
+ This command might be helpful when you are e.g. writing your own
+ logrotate script and you do not want to restart the RabbitMQ node.
+
cluster I<clusternode> ...
instruct the node to become member of a cluster with the specified
nodes determined by I<clusternode> option(s).
@@ -118,6 +131,11 @@ Grant user named foo access to the virtual host called test at the
default Erlang node:
rabbitmqctl map_user_vhost foo test
+
+Append the current logs' content to the files with ".1" suffix and reopen
+them:
+
+ rabbitmqctl rotate_logs .1
=head1 SEE ALSO
diff --git a/include/rabbit.hrl b/include/rabbit.hrl
index cc8fb1b5..180a0dc3 100644
--- a/include/rabbit.hrl
+++ b/include/rabbit.hrl
@@ -71,7 +71,7 @@
-type(r(Kind) ::
#resource{virtual_host :: vhost(),
kind :: Kind,
- name :: name()}).
+ name :: resource_name()}).
-type(queue_name() :: r('queue')).
-type(exchange_name() :: r('exchange')).
-type(user() ::
diff --git a/include/rabbit_framing_spec.hrl b/include/rabbit_framing_spec.hrl
index ef9ab584..e9e65092 100644
--- a/include/rabbit_framing_spec.hrl
+++ b/include/rabbit_framing_spec.hrl
@@ -46,7 +46,7 @@
-type(channel_number() :: non_neg_integer()).
%% TODO: make this more precise
-type(amqp_error() :: {bool(), non_neg_integer(), binary()}).
--type(name() :: binary()).
+-type(resource_name() :: binary()).
-type(routing_key() :: binary()).
-type(username() :: binary()).
-type(password() :: binary()).
diff --git a/packaging/RPMS/Fedora/Makefile b/packaging/RPMS/Fedora/Makefile
index 521fac43..814c79f0 100644
--- a/packaging/RPMS/Fedora/Makefile
+++ b/packaging/RPMS/Fedora/Makefile
@@ -21,6 +21,7 @@ prepare:
cp $(TOP_DIR)/rabbitmq-server.spec $(TOP_DIR)/SPECS
cp $(TOP_DIR)/init.d $(TOP_DIR)/BUILD
cp $(TOP_DIR)/rabbitmqctl_wrapper $(TOP_DIR)/BUILD
+ cp $(TOP_DIR)/rabbitmq-server.logrotate $(TOP_DIR)/BUILD
server: prepare
rpmbuild -ba $(TOP_DIR)/SPECS/rabbitmq-server.spec $(DEFINES) --target noarch
diff --git a/packaging/RPMS/Fedora/init.d b/packaging/RPMS/Fedora/init.d
index 09ca02c9..397beeaa 100644
--- a/packaging/RPMS/Fedora/init.d
+++ b/packaging/RPMS/Fedora/init.d
@@ -1,79 +1,140 @@
#!/bin/sh
+#
+# rabbitmq-server RabbitMQ broker
+#
+#chkconfig: 2345 80 05
+#description: Enable AMQP service provided by RabbitMQ
+#
+
### BEGIN INIT INFO
# Provides: rabbitmq
# Required-Start: $remote_fs $network
# Required-Stop: $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
+# Description: RabbitMQ broker
+# Short-Description: Enable AMQP service provided by RabbitMQ broker
### END INIT INFO
-#chkconfig: 2345 80 05
-#description: RabbitMQ Server
-
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
-DAEMON=/usr/sbin/rabbitmq-multi
+DAEMON_NAME=rabbitmq-multi
+DAEMON=/usr/sbin/$DAEMON_NAME
NAME=rabbitmq-server
DESC=rabbitmq-server
USER=rabbitmq
NODE_COUNT=1
+ROTATE_SUFFIX=
+
+LOCK_FILE=/var/lock/subsys/$NAME
test -x $DAEMON || exit 0
+# source function library
+. /etc/rc.d/init.d/functions
+
# Include rabbitmq defaults if available
if [ -f /etc/default/rabbitmq ] ; then
. /etc/default/rabbitmq
fi
+RETVAL=0
set -e
cd /
start_rabbitmq () {
set +e
- su rabbitmq -s /bin/sh -c "$DAEMON start_all ${NODE_COUNT}" > /var/log/rabbitmq/startup.log 2> /var/log/rabbitmq/startup.err
+ su $USER -s /bin/sh -c "$DAEMON start_all ${NODE_COUNT}" > /var/log/rabbitmq/startup_log 2> /var/log/rabbitmq/startup_err
case "$?" in
0)
- echo SUCCESS;;
+ echo SUCCESS && touch $LOCK_FILE
+ RETVAL=0
+ ;;
1)
- echo TIMEOUT - check /var/log/rabbitmq/startup.\{log,err\};;
+ echo TIMEOUT - check /var/log/rabbitmq/startup_\{log,err\}
+ RETVAL=1
+ ;;
*)
- echo FAILED - check /var/log/rabbitmq/startup.log, .err
- exit 1;;
+ echo FAILED - check /var/log/rabbitmq/startup_log, _err
+ RETVAL=1
+ ;;
esac
set -e
}
stop_rabbitmq () {
set +e
- su rabbitmq -s /bin/sh -c "$DAEMON stop_all" > /var/log/rabbitmq/shutdown.log 2> /var/log/rabbitmq/shutdown.err
+ status_rabbitmq quiet
+ if [ $RETVAL == 0 ] ; then
+ su $USER -s /bin/sh -c "$DAEMON stop_all" > /var/log/rabbitmq/shutdown_log 2> /var/log/rabbitmq/shutdown_err
+ RETVAL=$?
+ if [ $RETVAL != 0 ] ; then
+ echo FAILED - check /var/log/rabbitmq/shutdown_log, _err
+ else
+ rm -rf $LOCK_FILE
+ fi
+ else
+ echo No nodes running
+ RETVAL=0
+ fi
+ set -e
+}
+
+status_rabbitmq() {
+ set +e
+ if [ "$1" != "quiet" ] ; then
+ su $USER -s /bin/sh -c "$DAEMON status" 2>&1
+ else
+ su $USER -s /bin/sh -c "$DAEMON status" > /dev/null 2>&1
+ fi
if [ $? != 0 ] ; then
- echo FAILED - check /var/log/rabbitmq/shutdown.log, .err
- exit 0
+ RETVAL=1
fi
set -e
}
+rotate_logs_rabbitmq() {
+ set +e
+ su $USER -s /bin/sh -c "$DAEMON rotate_logs ${ROTATE_SUFFIX}" 2>&1
+ set -e
+}
+
+restart_rabbitmq() {
+ stop_rabbitmq
+ start_rabbitmq
+}
+
case "$1" in
- start)
- echo -n "Starting $DESC: "
- start_rabbitmq
- echo "$NAME."
- ;;
- stop)
- echo -n "Stopping $DESC: "
- stop_rabbitmq
- echo "$NAME."
- ;;
- force-reload|restart)
- echo -n "Restarting $DESC: "
- stop_rabbitmq
- start_rabbitmq
- echo "$NAME."
- ;;
- *)
- N=/etc/init.d/$NAME
- echo "Usage: $N {start|stop|restart|force-reload}" >&2
- exit 1
- ;;
+ start)
+ echo -n "Starting $DESC: "
+ start_rabbitmq
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ stop_rabbitmq
+ echo "$NAME."
+ ;;
+ status)
+ status_rabbitmq
+ ;;
+ rotate-logs)
+ echo -n "Rotating log files for $DESC: "
+ rotate_logs_rabbitmq
+ ;;
+ force-reload|reload|restart)
+ echo -n "Restarting $DESC: "
+ restart_rabbitmq
+ echo "$NAME."
+ ;;
+ condrestart|try-restart)
+ echo -n "Restarting $DESC: "
+ restart_rabbitmq
+ echo "$NAME."
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|status|rotate-logs|restart|condrestart|try-restart|reload|force-reload}" >&2
+ RETVAL=1
+ ;;
esac
-exit 0
+exit $RETVAL
diff --git a/packaging/RPMS/Fedora/rabbitmq-server.logrotate b/packaging/RPMS/Fedora/rabbitmq-server.logrotate
new file mode 100644
index 00000000..64cd01a1
--- /dev/null
+++ b/packaging/RPMS/Fedora/rabbitmq-server.logrotate
@@ -0,0 +1,12 @@
+/var/log/rabbitmq/*.log {
+ weekly
+ missingok
+ rotate 20
+ compress
+ delaycompress
+ notifempty
+ sharedscripts
+ postrotate
+ /sbin/service rabbitmq-server rotate-logs
+ endscript
+} \ No newline at end of file
diff --git a/packaging/RPMS/Fedora/rabbitmq-server.spec b/packaging/RPMS/Fedora/rabbitmq-server.spec
index 6a57babd..43837ba3 100644
--- a/packaging/RPMS/Fedora/rabbitmq-server.spec
+++ b/packaging/RPMS/Fedora/rabbitmq-server.spec
@@ -1,79 +1,70 @@
-%define source_name rabbitmq-server
-
Name: rabbitmq-server
Version: %{rpm_version}
Release: 1
-License: Mozilla Public License
+License: MPLv1.1
Group: Development/Libraries
-Source: http://www.rabbitmq.com/releases/%{source_name}-%{main_version}.tar.gz
+Source: http://www.rabbitmq.com/releases/rabbitmq-server/v%{main_version}/%{name}-%{main_version}.tar.gz
URL: http://www.rabbitmq.com/
Vendor: LShift Ltd., Cohesive Financial Technologies LLC., Rabbit Technlogies Ltd.
%if 0%{?debian}
%else
BuildRequires: python, python-json
%endif
-Requires: erlang
+Requires: erlang, logrotate
Packager: Hubert Plociniczak <hubert@lshift.net>
BuildRoot: %{_tmppath}/%{name}-%{main_version}-%{release}-root
Summary: The RabbitMQ server
+Requires(post): chkconfig
+Requires(pre): chkconfig initscripts
%description
RabbitMQ is an implementation of AMQP, the emerging standard for high
performance enterprise messaging. The RabbitMQ server is a robust and
scalable implementation of an AMQP broker.
-%define _libdir /usr/lib/erlang
-%define _docdir /usr/share/doc
%define _mandir /usr/share/man
-%define _maindir $RPM_BUILD_ROOT%{_libdir}/lib/rabbitmq_server-%{main_version}
-%define package_name rabbitmq-server-dist
+%define _sbindir /usr/sbin
+%define _libdir %(erl -noshell -eval "io:format('~s~n', [code:lib_dir()]), halt().")
+%define _maindir %{buildroot}%{_libdir}/rabbitmq_server-%{main_version}
%pre
if [ $1 -gt 1 ]; then
- #Upgrade - stop and remove previous instance of rabbitmq init.d script
- /etc/init.d/rabbitmq-server stop
+ #Upgrade - stop and remove previous instance of rabbitmq-server init.d script
+ /sbin/service rabbitmq-server stop
/sbin/chkconfig --del rabbitmq-server
fi
%prep
-%setup -n %{source_name}-%{main_version}
+%setup -n %{name}-%{main_version}
%build
-mkdir %{package_name}
-mkdir %{package_name}/sbin
-mkdir %{package_name}/man
-make install TARGET_DIR=`pwd`/%{package_name} \
- SBIN_DIR=`pwd`/%{package_name}/sbin \
- MAN_DIR=`pwd`/%{package_name}/man
- VERSION=%{main_version}
+make
%install
-mkdir -p %{_maindir}
-mkdir -p $RPM_BUILD_ROOT%{_docdir}/rabbitmq-server
-mkdir -p $RPM_BUILD_ROOT/etc/init.d
-mkdir -p $RPM_BUILD_ROOT/usr/sbin
-mkdir -p $RPM_BUILD_ROOT%{_mandir}
+rm -rf %{buildroot}
-mkdir -p $RPM_BUILD_ROOT/var/lib/rabbitmq/mnesia
-mkdir -p $RPM_BUILD_ROOT/var/log/rabbitmq
+make install TARGET_DIR=%{_maindir} \
+ SBIN_DIR=%{buildroot}%{_sbindir} \
+ MAN_DIR=%{buildroot}%{_mandir}
+ VERSION=%{main_version}
-#Copy all necessary lib files etc.
-cp -r %{package_name}/ebin %{_maindir}
-cp -r %{package_name}/src %{_maindir}
-cp -r %{package_name}/include %{_maindir}
-chmod 755 %{package_name}/sbin/*
-cp %{package_name}/sbin/* $RPM_BUILD_ROOT/usr/sbin/
-cp -r %{package_name}/man/* $RPM_BUILD_ROOT%{_mandir}/
+mkdir -p %{buildroot}/var/lib/rabbitmq/mnesia
+mkdir -p %{buildroot}/var/log/rabbitmq
+mkdir -p %{buildroot}/etc/rc.d/init.d/
-cp ../init.d $RPM_BUILD_ROOT/etc/init.d/rabbitmq-server
-chmod 775 $RPM_BUILD_ROOT/etc/init.d/rabbitmq-server
+#Copy all necessary lib files etc.
+cp ../init.d %{buildroot}/etc/rc.d/init.d/rabbitmq-server
+chmod 0755 %{buildroot}/etc/rc.d/init.d/rabbitmq-server
-mv $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl_real
-cp ../rabbitmqctl_wrapper $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl
-chmod 755 $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl
+mv %{buildroot}/usr/sbin/rabbitmqctl %{buildroot}/usr/sbin/rabbitmqctl_real
+cp ../rabbitmqctl_wrapper %{buildroot}/usr/sbin/rabbitmqctl
+chmod 0755 %{buildroot}/usr/sbin/rabbitmqctl
cp %{buildroot}%{_mandir}/man1/rabbitmqctl.1.gz %{buildroot}%{_mandir}/man1/rabbitmqctl_real.1.gz
+mkdir -p %{buildroot}/etc/logrotate.d
+cp ../rabbitmq-server.logrotate %{buildroot}/etc/logrotate.d/rabbitmq-server
+
%post
# create rabbitmq group
if ! getent group rabbitmq >/dev/null; then
@@ -86,65 +77,59 @@ if ! getent passwd rabbitmq >/dev/null; then
usermod -c "Rabbit AMQP Messaging Server" rabbitmq
fi
-# On 64bit /usr/lib64 contains Erlang, not /usr/lib. Fix with a symlink
-ERL_LIB_DIR=$(erl -noshell -eval "io:format(\"~s~n\", [code:lib_dir()]), halt().")
-if [ ! ${ERL_LIB_DIR} = "/usr/lib/erlang/lib" ] ; then
- ln -s /usr/lib/erlang/lib/rabbitmq_server-%{main_version} ${ERL_LIB_DIR}
-fi
-
chown -R rabbitmq:rabbitmq /var/lib/rabbitmq
chown -R rabbitmq:rabbitmq /var/log/rabbitmq
-/sbin/chkconfig --add rabbitmq-server
-/etc/init.d/rabbitmq-server start
+/sbin/chkconfig --add %{name}
+/sbin/service rabbitmq-server start
%preun
if [ $1 = 0 ]; then
#Complete uninstall
- /etc/init.d/rabbitmq-server stop
+ /sbin/service rabbitmq-server stop
/sbin/chkconfig --del rabbitmq-server
-
- # Remove symlink we added above
- ERL_LIB_DIR=$(erl -noshell -eval "io:format(\"~s~n\", [code:lib_dir()]), halt().")
- if [ ! ${ERL_LIB_DIR} = "/usr/lib/erlang/lib" ] ; then
- rm ${ERL_LIB_DIR}/rabbitmq_server-%{main_version}
- fi
- # We do not remove log and lib directories
+ # We do not remove /var/log and /var/lib directories
# Leave rabbitmq user and group
fi
%files
-%defattr(-,root,root)
-%{_libdir}/lib/rabbitmq_server-%{main_version}/
-%{_docdir}/rabbitmq-server/
-%{_mandir}
-/usr/sbin
-/var/lib/rabbitmq
-/var/log/rabbitmq
-/etc/init.d/rabbitmq-server
+%defattr(-,root,root,-)
+%{_libdir}/rabbitmq_server-%{main_version}/
+%{_mandir}/man1/rabbitmq-multi.1.gz
+%{_mandir}/man1/rabbitmq-server.1.gz
+%{_mandir}/man1/rabbitmqctl.1.gz
+%{_mandir}/man1/rabbitmqctl_real.1.gz
+%{_sbindir}/rabbitmq-multi
+%{_sbindir}/rabbitmq-server
+%{_sbindir}/rabbitmqctl
+%{_sbindir}/rabbitmqctl_real
+/var/lib/rabbitmq/
+/var/log/rabbitmq/
+/etc/rc.d/init.d/rabbitmq-server
+%config(noreplace) /etc/logrotate.d/rabbitmq-server
%clean
-rm -rf $RPM_BUILD_ROOT
+rm -rf %{buildroot}
%changelog
-* Thu Jul 24 2008 Tony Garnock-Jones <tonyg@lshift.net> 1.4.0
+* Thu Jul 24 2008 Tony Garnock-Jones <tonyg@lshift.net> 1.4.0-1
- New upstream release
-* Mon Mar 3 2008 Adrien Pierard <adrian@lshift.net> 1.3.0
+* Mon Mar 3 2008 Adrien Pierard <adrian@lshift.net> 1.3.0-1
- New upstream release
-* Wed Sep 26 2007 Simon MacMullen <simon@lshift.net> 1.2.0
+* Wed Sep 26 2007 Simon MacMullen <simon@lshift.net> 1.2.0-1
- New upstream release
-* Wed Aug 29 2007 Simon MacMullen <simon@lshift.net> 1.1.1
+* Wed Aug 29 2007 Simon MacMullen <simon@lshift.net> 1.1.1-1
- New upstream release
-* Mon Jul 30 2007 Simon MacMullen <simon@lshift.net> 1.1.0-alpha
+* Mon Jul 30 2007 Simon MacMullen <simon@lshift.net> 1.1.0-1.alpha
- New upstream release
-* Tue Jun 12 2007 Hubert Plociniczak <hubert@lshift.net> hubert-20070607
+* Tue Jun 12 2007 Hubert Plociniczak <hubert@lshift.net> 1.0.0-1.20070607
- Building from source tarball, added starting script, stopping
-* Mon May 21 2007 Hubert Plociniczak <hubert@lshift.net> 1.0.0-alpha
+* Mon May 21 2007 Hubert Plociniczak <hubert@lshift.net> 1.0.0-1.alpha
- Initial build of server library of RabbitMQ package
diff --git a/packaging/debs/Debian/debian/control b/packaging/debs/Debian/debian/control
index abc6a658..675e15f4 100644
--- a/packaging/debs/Debian/debian/control
+++ b/packaging/debs/Debian/debian/control
@@ -7,7 +7,7 @@ Standards-Version: 3.7.2
Package: rabbitmq-server
Architecture: all
-Depends: erlang-nox, adduser
+Depends: erlang-nox, adduser, logrotate
Description: An AMQP server written in Erlang
RabbitMQ is an implementation of AMQP, the emerging standard for high
performance enterprise messaging. The RabbitMQ server is a robust and
diff --git a/packaging/debs/Debian/debian/copyright b/packaging/debs/Debian/debian/copyright
index e16996e5..9f9f8672 100644
--- a/packaging/debs/Debian/debian/copyright
+++ b/packaging/debs/Debian/debian/copyright
@@ -5,7 +5,7 @@ It was downloaded from http://www.rabbitmq.com/
Upstream Author: The RabbitMQ team <info@rabbitmq.com>
-Copyright: 2006-2008 LShift Ltd.
+Copyright: 2006-2008 Rabbit Technologies Ltd.
License:
The RabbitMQ server is licensed under the MPL.
@@ -485,7 +485,7 @@ EXHIBIT A -Mozilla Public License.
If you have any questions regarding licensing, please contact us at
info@rabbitmq.com.
-The Debian packaging is (C) 2007, Tony Garnock-Jones <tonyg@rabbitmq.com> and
-is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+The Debian packaging is (C) 2007-2008, Rabbit Technologies Ltd. <info@rabbitmq.com>
+and is licensed under the MPL 1.1, see above.
diff --git a/packaging/debs/Debian/debian/dirs b/packaging/debs/Debian/debian/dirs
index 0b3f55b9..74f86314 100644
--- a/packaging/debs/Debian/debian/dirs
+++ b/packaging/debs/Debian/debian/dirs
@@ -3,4 +3,5 @@ usr/sbin
usr/share/man
var/lib/rabbitmq/mnesia
var/log/rabbitmq
+etc/logrotate.d
diff --git a/packaging/debs/Debian/debian/init.d b/packaging/debs/Debian/debian/init.d
index f3999888..a93f3066 100644
--- a/packaging/debs/Debian/debian/init.d
+++ b/packaging/debs/Debian/debian/init.d
@@ -5,7 +5,8 @@
# Required-Stop: $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
-# Short-Description: Enable AMQP service provided by RabbitMQ.
+# Description: RabbitMQ broker
+# Short-Description: Enable AMQP service provided by RabbitMQ broker
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
@@ -14,6 +15,7 @@ NAME=rabbitmq-server
DESC=rabbitmq-server
USER=rabbitmq
NODE_COUNT=1
+ROTATE_SUFFIX=
test -x $DAEMON || exit 0
@@ -22,56 +24,97 @@ if [ -f /etc/default/rabbitmq ] ; then
. /etc/default/rabbitmq
fi
+RETVAL=0
set -e
cd /
start_rabbitmq () {
- set +e
- su rabbitmq -s /bin/sh -c "$DAEMON start_all ${NODE_COUNT}" > /var/log/rabbitmq/startup.log 2> /var/log/rabbitmq/startup.err
- case "$?" in
- 0)
- echo SUCCESS;;
- 1)
- echo TIMEOUT - check /var/log/rabbitmq/startup.\{log,err\};;
- *)
- echo FAILED - check /var/log/rabbitmq/startup.log, .err
- exit 1;;
- esac
- set -e
+ set +e
+ su $USER -s /bin/sh -c "$DAEMON start_all ${NODE_COUNT}" > /var/log/rabbitmq/startup_log 2> /var/log/rabbitmq/startup_err
+ case "$?" in
+ 0)
+ echo SUCCESS
+ RETVAL=0
+ ;;
+ 1)
+ echo TIMEOUT - check /var/log/rabbitmq/startup_\{log,err\}
+ RETVAL=1
+ ;;
+ *)
+ echo FAILED - check /var/log/rabbitmq/startup_log, _err
+ RETVAL=1
+ ;;
+ esac
+ set -e
}
stop_rabbitmq () {
set +e
- su rabbitmq -s /bin/sh -c "$DAEMON stop_all" > /var/log/rabbitmq/shutdown.log 2> /var/log/rabbitmq/shutdown.err
+ status_rabbitmq quiet
+ if [ $RETVAL == 0 ] ; then
+ su $USER -s /bin/sh -c "$DAEMON stop_all" > /var/log/rabbitmq/shutdown_log 2> /var/log/rabbitmq/shutdown_err
+ RETVAL=$?
+ if [ $RETVAL != 0 ] ; then
+ echo FAILED - check /var/log/rabbitmq/shutdown_log, _err
+ fi
+ else
+ echo No nodes running
+ RETVAL=0
+ fi
+ set -e
+}
+
+status_rabbitmq() {
+ set +e
+ if [ "$1" != "quiet" ] ; then
+ su $USER -s /bin/sh -c "$DAEMON status" 2>&1
+ else
+ su $USER -s /bin/sh -c "$DAEMON status" > /dev/null 2>&1
+ fi
if [ $? != 0 ] ; then
- echo FAILED - check /var/log/rabbitmq/shutdown.log, .err
- exit 0
+ RETVAL=1
fi
set -e
}
+rotate_logs_rabbitmq() {
+ set +e
+ su $USER -s /bin/sh -c "$DAEMON rotate_logs ${ROTATE_SUFFIX}" 2>&1
+ set -e
+}
+
+restart_rabbitmq() {
+ stop_rabbitmq
+ start_rabbitmq
+}
+
case "$1" in
- start)
- echo -n "Starting $DESC: "
- start_rabbitmq
- echo "$NAME."
- ;;
- stop)
- echo -n "Stopping $DESC: "
- stop_rabbitmq
- echo "$NAME."
- ;;
- force-reload|restart)
- echo -n "Restarting $DESC: "
- stop_rabbitmq
- start_rabbitmq
- echo "$NAME."
- ;;
- *)
- N=/etc/init.d/$NAME
- echo "Usage: $N {start|stop|restart|force-reload}" >&2
- exit 1
- ;;
+ start)
+ echo -n "Starting $DESC: "
+ start_rabbitmq
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ stop_rabbitmq
+ echo "$NAME."
+ ;;
+ status)
+ status_rabbitmq
+ ;;
+ rotate-logs)
+ echo -n "Rotating log files for $DESC: "
+ rotate_logs_rabbitmq
+ ;;
+ force-reload|restart)
+ echo -n "Restarting $DESC: "
+ restart_rabbitmq
+ echo "$NAME."
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|status|rotate-logs|restart|force-reload}" >&2
+ RETVAL=1
+ ;;
esac
-exit 0
+exit $RETVAL
diff --git a/packaging/debs/Debian/debian/rabbitmq-server.logrotate b/packaging/debs/Debian/debian/rabbitmq-server.logrotate
new file mode 100644
index 00000000..247635d1
--- /dev/null
+++ b/packaging/debs/Debian/debian/rabbitmq-server.logrotate
@@ -0,0 +1,12 @@
+/var/log/rabbitmq/*.log {
+ weekly
+ missingok
+ rotate 20
+ compress
+ delaycompress
+ notifempty
+ sharedscripts
+ postrotate
+ /etc/init.d/rabbitmq-server rotate-logs
+ endscript
+} \ No newline at end of file
diff --git a/packaging/debs/Debian/debian/rules b/packaging/debs/Debian/debian/rules
index 6edf27c1..39af711c 100644
--- a/packaging/debs/Debian/debian/rules
+++ b/packaging/debs/Debian/debian/rules
@@ -14,5 +14,6 @@ install/rabbitmq-server::
rm $(RABBIT_LIB)/LICENSE*
mv $(DEB_DESTDIR)usr/sbin/rabbitmqctl $(DEB_DESTDIR)usr/sbin/rabbitmqctl_real
cp debian/rabbitmqctl_wrapper $(DEB_DESTDIR)usr/sbin/rabbitmqctl
+ cp debian/rabbitmq-server.logrotate $(DEB_DESTDIR)etc/logrotate.d/rabbitmq-server
cp $(DEB_DESTDIR)usr/share/man/man1/rabbitmqctl.1.gz $(DEB_DESTDIR)usr/share/man/man1/rabbitmqctl_real.1.gz
chmod a+x $(DEB_DESTDIR)usr/sbin/rabbitmqctl
diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server
index e5fb93cc..80289d8e 100755
--- a/scripts/rabbitmq-server
+++ b/scripts/rabbitmq-server
@@ -39,7 +39,7 @@ CLUSTER_CONFIG_FILE=/etc/default/rabbitmq_cluster.config
## Log rotation
LOGS="${LOG_BASE}/${NODENAME}.log"
SASL_LOGS="${LOG_BASE}/${NODENAME}-sasl.log"
-BACKUP_EXTENSION=".bak"
+BACKUP_EXTENSION=".1"
[ -f "${LOGS}" ] && cat "${LOGS}" >> "${LOGS}${BACKUP_EXTENSION}"
[ -f "${SASL_LOGS}" ] && cat "${SASL_LOGS}" >> "${SASL_LOGS}${BACKUP_EXTENSION}"
diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat
index 8b06c0b4..42c09fac 100644
--- a/scripts/rabbitmq-server.bat
+++ b/scripts/rabbitmq-server.bat
@@ -65,7 +65,7 @@ set LOG_BASE=%RABBITMQ_BASE_UNIX%/log
rem We save the previous logs in their respective backup
rem Log management (rotation, filtering based of size...) is left as an exercice for the user.
-set BACKUP_EXTENSION=.bak
+set BACKUP_EXTENSION=.1
set LOGS="%RABBITMQ_BASE%\log\%NODENAME%.log"
set SASL_LOGS="%RABBITMQ_BASE%\log\%NODENAME%-sasl.log"
diff --git a/src/rabbit.erl b/src/rabbit.erl
index 9ab6b1a6..c6ef1749 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -27,10 +27,12 @@
-behaviour(application).
--export([start/0, stop/0, stop_and_halt/0, status/0]).
+-export([start/0, stop/0, stop_and_halt/0, status/0, rotate_logs/1]).
-export([start/2, stop/1]).
+-export([log_location/1]).
+
-import(application).
-import(mnesia).
-import(lists).
@@ -46,13 +48,18 @@
-ifdef(use_specs).
+-type(log_location() :: 'tty' | 'undefined' | string()).
+-type(file_suffix() :: binary()).
+
-spec(start/0 :: () -> 'ok').
-spec(stop/0 :: () -> 'ok').
-spec(stop_and_halt/0 :: () -> 'ok').
+-spec(rotate_logs/1 :: (file_suffix()) -> 'ok' | {'error', any()}).
-spec(status/0 :: () ->
[{running_applications, [{atom(), string(), string()}]} |
{nodes, [node()]} |
{running_nodes, [node()]}]).
+-spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()).
-endif.
@@ -60,7 +67,7 @@
start() ->
try
- ok = ensure_working_log_config(),
+ ok = ensure_working_log_handlers(),
ok = rabbit_mnesia:ensure_mnesia_dir(),
ok = start_applications(?APPS)
after
@@ -85,6 +92,15 @@ status() ->
[{running_applications, application:which_applications()}] ++
rabbit_mnesia:status().
+rotate_logs(BinarySuffix) ->
+ Suffix = binary_to_list(BinarySuffix),
+ log_rotation_result(rotate_logs(log_location(kernel),
+ Suffix,
+ rabbit_error_logger_file_h),
+ rotate_logs(log_location(sasl),
+ Suffix,
+ rabbit_sasl_report_file_h)).
+
%%--------------------------------------------------------------------
manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) ->
@@ -186,6 +202,21 @@ stop(_State) ->
%---------------------------------------------------------------------------
+log_location(Type) ->
+ case application:get_env(Type, case Type of
+ kernel -> error_logger;
+ sasl -> sasl_error_logger
+ end) of
+ {ok, {file, File}} -> File;
+ {ok, false} -> undefined;
+ {ok, tty} -> tty;
+ {ok, silent} -> undefined;
+ {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}});
+ _ -> undefined
+ end.
+
+%---------------------------------------------------------------------------
+
print_banner() ->
{ok, Product} = application:get_key(id),
{ok, Version} = application:get_key(vsn),
@@ -194,7 +225,9 @@ print_banner() ->
?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR,
?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]),
io:format("Logging to ~p~nSASL logging to ~p~n~n",
- [error_log_location(), sasl_log_location()]).
+ [log_location(kernel), log_location(sasl)]).
+
+
start_child(Mod) ->
{ok,_} = supervisor:start_child(rabbit_sup,
@@ -202,6 +235,43 @@ start_child(Mod) ->
transient, 100, worker, [Mod]}),
ok.
+ensure_working_log_handlers() ->
+ Handlers = gen_event:which_handlers(error_logger),
+ ok = ensure_working_log_handler(error_logger_file_h,
+ rabbit_error_logger_file_h,
+ error_logger_tty_h,
+ log_location(kernel),
+ Handlers),
+
+ ok = ensure_working_log_handler(sasl_report_file_h,
+ rabbit_sasl_report_file_h,
+ sasl_report_tty_h,
+ log_location(sasl),
+ Handlers),
+ ok.
+
+ensure_working_log_handler(OldFHandler, NewFHandler, TTYHandler,
+ LogLocation, Handlers) ->
+ case LogLocation of
+ undefined -> ok;
+ tty -> case lists:member(TTYHandler, Handlers) of
+ true -> ok;
+ false ->
+ throw({error, {cannot_log_to_tty,
+ TTYHandler, not_installed}})
+ end;
+ _ -> case lists:member(NewFHandler, Handlers) of
+ true -> ok;
+ false -> case rotate_logs(LogLocation, "",
+ OldFHandler, NewFHandler) of
+ ok -> ok;
+ {error, Reason} ->
+ throw({error, {cannot_log_to_file,
+ LogLocation, Reason}})
+ end
+ end
+ end.
+
maybe_insert_default_data() ->
case rabbit_mnesia:is_db_empty() of
true -> insert_default_data();
@@ -223,40 +293,25 @@ start_builtin_amq_applications() ->
%%restart
ok.
-ensure_working_log_config() ->
- case error_logger:logfile(filename) of
- {error, no_log_file} ->
- %% either no log file was configured or opening it failed.
- case application:get_env(kernel, error_logger) of
- {ok, {file, Filename}} ->
- case filelib:ensure_dir(Filename) of
- ok -> ok;
- {error, Reason1} ->
- throw({error, {cannot_log_to_file,
- Filename, Reason1}})
- end,
- case error_logger:logfile({open, Filename}) of
- ok -> ok;
- {error, Reason2} ->
- throw({error, {cannot_log_to_file,
- Filename, Reason2}})
- end;
- _ -> ok
- end;
- _Filename -> ok
+rotate_logs(File, Suffix, Handler) ->
+ rotate_logs(File, Suffix, Handler, Handler).
+
+rotate_logs(File, Suffix, OldHandler, NewHandler) ->
+ case File of
+ undefined -> ok;
+ tty -> ok;
+ _ -> gen_event:swap_handler(
+ error_logger,
+ {OldHandler, swap},
+ {NewHandler, {File, Suffix}})
end.
-error_log_location() ->
- case error_logger:logfile(filename) of
- {error,no_log_file} -> tty;
- File -> File
- end.
-
-sasl_log_location() ->
- case application:get_env(sasl, sasl_error_logger) of
- {ok, {file, File}} -> File;
- {ok, false} -> undefined;
- {ok, tty} -> tty;
- {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}});
- _ -> undefined
- end.
+log_rotation_result({error, MainLogError}, {error, SaslLogError}) ->
+ {error, {{cannot_rotate_main_logs, MainLogError},
+ {cannot_rotate_sasl_logs, SaslLogError}}};
+log_rotation_result({error, MainLogError}, ok) ->
+ {error, {cannot_rotate_main_logs, MainLogError}};
+log_rotation_result(ok, {error, SaslLogError}) ->
+ {error, {cannot_rotate_sasl_logs, SaslLogError}};
+log_rotation_result(ok, ok) ->
+ ok.
diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl
index eb24b782..bc588279 100644
--- a/src/rabbit_control.erl
+++ b/src/rabbit_control.erl
@@ -73,6 +73,7 @@ Available commands:
force_reset
cluster <ClusterNode> ...
status
+ rotate_logs [Suffix]
add_user <UserName> <Password>
delete_user <UserName>
@@ -129,6 +130,13 @@ action(status, Node, []) ->
io:format("~n~p~n", [Res]),
ok;
+action(rotate_logs, Node, []) ->
+ io:format("Reopening logs for node ~p ...", [Node]),
+ call(Node, {rabbit, rotate_logs, [""]});
+action(rotate_logs, Node, Args = [Suffix]) ->
+ io:format("Rotating logs to files with suffix ~p ...", [Suffix]),
+ call(Node, {rabbit, rotate_logs, Args});
+
action(add_user, Node, Args = [Username, _Password]) ->
io:format("Creating user ~p ...", [Username]),
call(Node, {rabbit_access_control, add_user, Args});
diff --git a/src/rabbit_error_logger_file_h.erl b/src/rabbit_error_logger_file_h.erl
new file mode 100644
index 00000000..d67b02ef
--- /dev/null
+++ b/src/rabbit_error_logger_file_h.erl
@@ -0,0 +1,74 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License at
+%% http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+%% License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developers of the Original Code are LShift Ltd.,
+%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
+%%
+%% Portions created by LShift Ltd., Cohesive Financial Technologies
+%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008
+%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
+%% Technologies Ltd.;
+%%
+%% All Rights Reserved.
+%%
+%% Contributor(s): ______________________________________.
+%%
+
+-module(rabbit_error_logger_file_h).
+
+-behaviour(gen_event).
+
+-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
+
+%% rabbit_error_logger_file_h is a wrapper around the error_logger_file_h
+%% module because the original's init/1 does not match properly
+%% with the result of closing the old handler when swapping handlers.
+%% The first init/1 additionally allows for simple log rotation
+%% when the suffix is not the empty string.
+
+%% Used only when swapping handlers in log rotation
+init({{File, Suffix}, []}) ->
+ case rabbit_misc:append_file(File, Suffix) of
+ ok -> ok;
+ {error, Error} ->
+ rabbit_log:error("Failed to append contents of " ++
+ "log file '~s' to '~s':~n~p~n",
+ [File, [File, Suffix], Error])
+ end,
+ init(File);
+%% Used only when swapping handlers and the original handler
+%% failed to terminate or was never installed
+init({{File, _}, error}) ->
+ init(File);
+%% Used only when swapping handlers without performing
+%% log rotation
+init({File, []}) ->
+ init(File);
+init({_File, _Type} = FileInfo) ->
+ error_logger_file_h:init(FileInfo);
+init(File) ->
+ error_logger_file_h:init(File).
+
+handle_event(Event, State) ->
+ error_logger_file_h:handle_event(Event, State).
+
+handle_info(Event, State) ->
+ error_logger_file_h:handle_info(Event, State).
+
+handle_call(Event, State) ->
+ error_logger_file_h:handle_call(Event, State).
+
+terminate(Reason, State) ->
+ error_logger_file_h:terminate(Reason, State).
+
+code_change(OldVsn, State, Extra) ->
+ error_logger_file_h:code_change(OldVsn, State, Extra).
diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl
index 11ab0caf..3e4ed8f3 100644
--- a/src/rabbit_misc.erl
+++ b/src/rabbit_misc.erl
@@ -26,6 +26,7 @@
-module(rabbit_misc).
-include("rabbit.hrl").
-include("rabbit_framing.hrl").
+-include_lib("kernel/include/file.hrl").
-export([method_record_type/1, polite_pause/0, polite_pause/1]).
-export([die/1, frame_error/2, protocol_error/3, protocol_error/4]).
@@ -41,6 +42,7 @@
-export([intersperse/2, upmap/2, map_in_order/2]).
-export([guid/0, string_guid/1, binstring_guid/1]).
-export([dirty_read_all/1, dirty_foreach_key/2, dirty_dump_log/1]).
+-export([append_file/2]).
-import(mnesia).
-import(lists).
@@ -66,7 +68,7 @@
-spec(get_config/2 :: (atom(), A) -> A).
-spec(set_config/2 :: (atom(), any()) -> 'ok').
-spec(dirty_read/1 :: ({atom(), any()}) -> {'ok', any()} | not_found()).
--spec(r/3 :: (vhost(), K, name()) -> r(K) when is_subtype(K, atom())).
+-spec(r/3 :: (vhost(), K, resource_name()) -> r(K) when is_subtype(K, atom())).
-spec(r/2 :: (vhost(), K) -> #resource{virtual_host :: vhost(),
kind :: K,
name :: '_'}
@@ -92,6 +94,7 @@
-spec(dirty_foreach_key/2 :: (fun ((any()) -> any()), atom()) ->
'ok' | 'aborted').
-spec(dirty_dump_log/1 :: (string()) -> 'ok' | {'error', any()}).
+-spec(append_file/2 :: (string(), string()) -> 'ok' | {'error', any()}).
-endif.
@@ -333,3 +336,24 @@ dirty_dump_log1(LH, {K, Terms}) ->
dirty_dump_log1(LH, {K, Terms, BadBytes}) ->
io:format("Bad Chunk, ~p: ~p~n", [BadBytes, Terms]),
dirty_dump_log1(LH, disk_log:chunk(LH, K)).
+
+
+append_file(File, Suffix) ->
+ case file:read_file_info(File) of
+ {ok, FInfo} -> append_file(File, FInfo#file_info.size, Suffix);
+ {error, enoent} -> append_file(File, 0, Suffix);
+ Error -> Error
+ end.
+
+append_file(_, _, "") ->
+ ok;
+append_file(File, 0, Suffix) ->
+ case file:open([File, Suffix], [append]) of
+ {ok, Fd} -> file:close(Fd);
+ Error -> Error
+ end;
+append_file(File, _, Suffix) ->
+ case file:read_file(File) of
+ {ok, Data} -> file:write_file([File, Suffix], Data, [append]);
+ Error -> Error
+ end.
diff --git a/src/rabbit_multi.erl b/src/rabbit_multi.erl
index bde69336..c6a7e920 100644
--- a/src/rabbit_multi.erl
+++ b/src/rabbit_multi.erl
@@ -70,7 +70,9 @@ usage() ->
Available commands:
start_all <NodeCount> - start a local cluster of RabbitMQ nodes.
+ status - print status of all running nodes
stop_all - stops all local RabbitMQ nodes.
+ rotate_logs [Suffix] - rotate logs for all local and running RabbitMQ nodes.
"),
halt(3).
@@ -87,13 +89,46 @@ action(start_all, [NodeCount], RpcTimeout) ->
false -> timeout
end;
+action(status, [], RpcTimeout) ->
+ io:format("Status of all running nodes...~n", []),
+ call_all_nodes(
+ fun({Node, Pid}) ->
+ Status = rpc:call(Node, rabbit, status, [], RpcTimeout),
+ io:format("Node '~p' with Pid ~p: ~p~n",
+ [Node, Pid, case parse_status(Status) of
+ false -> not_running;
+ true -> running
+ end])
+ end);
+
action(stop_all, [], RpcTimeout) ->
io:format("Stopping all nodes...~n", []),
- case read_pids_file() of
- [] -> throw(no_nodes_running);
- NodePids -> stop_nodes(NodePids, RpcTimeout),
- delete_pids_file()
- end.
+ call_all_nodes(fun({Node, Pid}) ->
+ io:format("Stopping node ~p~n", [Node]),
+ rpc:call(Node, rabbit, stop_and_halt, []),
+ case kill_wait(Pid, RpcTimeout, false) of
+ false -> kill_wait(Pid, RpcTimeout, true);
+ true -> ok
+ end,
+ io:format("OK~n", [])
+ end),
+ delete_pids_file();
+
+action(rotate_logs, [], RpcTimeout) ->
+ action(rotate_logs, [""], RpcTimeout);
+
+action(rotate_logs, [Suffix], RpcTimeout) ->
+ io:format("Rotating logs for all nodes...~n", []),
+ BinarySuffix = list_to_binary(Suffix),
+ call_all_nodes(
+ fun ({Node, _}) ->
+ io:format("Rotating logs for node ~p", [Node]),
+ case rpc:call(Node, rabbit, rotate_logs,
+ [BinarySuffix], RpcTimeout) of
+ {badrpc, Error} -> io:format(": ~p.~n", [Error]);
+ ok -> io:format(": ok.~n", [])
+ end
+ end).
%% PNodePid is the list of PIDs
%% Running is a boolean exhibiting success at some moment
@@ -222,21 +257,6 @@ read_pids_file() ->
FileName, Reason}})
end.
-stop_nodes([],_) -> ok;
-
-stop_nodes([NodePid | Rest], RpcTimeout) ->
- stop_node(NodePid, RpcTimeout),
- stop_nodes(Rest, RpcTimeout).
-
-stop_node({Node, Pid}, RpcTimeout) ->
- io:format("Stopping node ~p~n", [Node]),
- rpc:call(Node, rabbit, stop_and_halt, []),
- case kill_wait(Pid, RpcTimeout, false) of
- false -> kill_wait(Pid, RpcTimeout, true);
- true -> ok
- end,
- io:format("OK~n", []).
-
kill_wait(Pid, TimeLeft, Forceful) when TimeLeft < 0 ->
Cmd = with_os([{unix, fun () -> if Forceful -> "kill -9";
true -> "kill"
@@ -272,6 +292,12 @@ is_dead(Pid) ->
end
end}]).
+call_all_nodes(Func) ->
+ case read_pids_file() of
+ [] -> throw(no_nodes_running);
+ NodePids -> lists:foreach(Func, NodePids)
+ end.
+
getenv(Var) ->
case os:getenv(Var) of
false -> throw({missing_env_var, Var});
diff --git a/src/rabbit_sasl_report_file_h.erl b/src/rabbit_sasl_report_file_h.erl
new file mode 100644
index 00000000..3374d63d
--- /dev/null
+++ b/src/rabbit_sasl_report_file_h.erl
@@ -0,0 +1,86 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License at
+%% http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+%% License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developers of the Original Code are LShift Ltd.,
+%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
+%%
+%% Portions created by LShift Ltd., Cohesive Financial Technologies
+%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008
+%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
+%% Technologies Ltd.;
+%%
+%% All Rights Reserved.
+%%
+%% Contributor(s): ______________________________________.
+%%
+
+-module(rabbit_sasl_report_file_h).
+
+-behaviour(gen_event).
+
+-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
+
+%% rabbit_sasl_report_file_h is a wrapper around the sasl_report_file_h
+%% module because the original's init/1 does not match properly
+%% with the result of closing the old handler when swapping handlers.
+%% The first init/1 additionally allows for simple log rotation
+%% when the suffix is not the empty string.
+
+%% Used only when swapping handlers and performing
+%% log rotation
+init({{File, Suffix}, []}) ->
+ case rabbit_misc:append_file(File, Suffix) of
+ ok -> ok;
+ {error, Error} ->
+ rabbit_log:error("Failed to append contents of " ++
+ "sasl log file '~s' to '~s':~n~p~n",
+ [File, [File, Suffix], Error])
+ end,
+ init(File);
+%% Used only when swapping handlers and the original handler
+%% failed to terminate or was never installed
+init({{File, _}, error}) ->
+ init(File);
+%% Used only when swapping handlers without
+%% doing any log rotation
+init({File, []}) ->
+ init(File);
+init({_File, _Type} = FileInfo) ->
+ sasl_report_file_h:init(FileInfo);
+init(File) ->
+ sasl_report_file_h:init({File, sasl_error_logger_type()}).
+
+handle_event(Event, State) ->
+ sasl_report_file_h:handle_event(Event, State).
+
+handle_info(Event, State) ->
+ sasl_report_file_h:handle_info(Event, State).
+
+handle_call(Event, State) ->
+ sasl_report_file_h:handle_call(Event, State).
+
+terminate(Reason, State) ->
+ sasl_report_file_h:terminate(Reason, State).
+
+code_change(OldVsn, State, Extra) ->
+ sasl_report_file_h:code_change(OldVsn, State, Extra).
+
+%%----------------------------------------------------------------------
+
+sasl_error_logger_type() ->
+ case application:get_env(sasl, errlog_type) of
+ {ok, error} -> error;
+ {ok, progress} -> progress;
+ {ok, all} -> all;
+ {ok, Bad} -> throw({error, {wrong_errlog_type, Bad}});
+ _ -> all
+ end.
diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl
index 6f43b08a..fff02d73 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -29,6 +29,8 @@
-import(lists).
+-include_lib("kernel/include/file.hrl").
+
test_content_prop_roundtrip(Datum, Binary) ->
Types = [element(1, E) || E <- Datum],
Values = [element(2, E) || E <- Datum],
@@ -38,7 +40,9 @@ test_content_prop_roundtrip(Datum, Binary) ->
all_tests() ->
passed = test_parsing(),
passed = test_topic_matching(),
+ passed = test_log_management(),
passed = test_app_management(),
+ passed = test_log_management_during_startup(),
passed = test_cluster_management(),
passed = test_user_management(),
passed.
@@ -136,6 +140,134 @@ test_app_management() ->
ok = control_action(status, []),
passed.
+test_log_management() ->
+ MainLog = rabbit:log_location(kernel),
+ SaslLog = rabbit:log_location(sasl),
+ Suffix = ".1",
+
+ %% prepare basic logs
+ file:delete([MainLog, Suffix]),
+ file:delete([SaslLog, Suffix]),
+
+ %% simple logs reopening
+ ok = control_action(rotate_logs, []),
+ [true, true] = empty_files([MainLog, SaslLog]),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% simple log rotation
+ ok = control_action(rotate_logs, [Suffix]),
+ [true, true] = non_empty_files([[MainLog, Suffix], [SaslLog, Suffix]]),
+ [true, true] = empty_files([MainLog, SaslLog]),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% reopening logs with log rotation performed first
+ ok = clean_logs([MainLog, SaslLog], Suffix),
+ ok = control_action(rotate_logs, []),
+ ok = file:rename(MainLog, [MainLog, Suffix]),
+ ok = file:rename(SaslLog, [SaslLog, Suffix]),
+ ok = test_logs_working([MainLog, Suffix], [SaslLog, Suffix]),
+ ok = control_action(rotate_logs, []),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% log rotation on empty file
+ ok = clean_logs([MainLog, SaslLog], Suffix),
+ ok = control_action(rotate_logs, []),
+ ok = control_action(rotate_logs, [Suffix]),
+ [true, true] = empty_files([[MainLog, Suffix], [SaslLog, Suffix]]),
+
+ %% original main log file is not writable
+ ok = make_files_non_writable([MainLog]),
+ {error, {cannot_rotate_main_logs, _}} = control_action(rotate_logs, []),
+ ok = clean_logs([MainLog], Suffix),
+ ok = add_log_handlers([{rabbit_error_logger_file_h, MainLog}]),
+
+ %% original sasl log file is not writable
+ ok = make_files_non_writable([SaslLog]),
+ {error, {cannot_rotate_sasl_logs, _}} = control_action(rotate_logs, []),
+ ok = clean_logs([SaslLog], Suffix),
+ ok = add_log_handlers([{rabbit_sasl_report_file_h, SaslLog}]),
+
+ %% logs with suffix are not writable
+ ok = control_action(rotate_logs, [Suffix]),
+ ok = make_files_non_writable([[MainLog, Suffix], [SaslLog, Suffix]]),
+ ok = control_action(rotate_logs, [Suffix]),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% original log files are not writable
+ ok = make_files_non_writable([MainLog, SaslLog]),
+ {error, {{cannot_rotate_main_logs, _},
+ {cannot_rotate_sasl_logs, _}}} = control_action(rotate_logs, []),
+
+ %% logging directed to tty (handlers were removed in last test)
+ ok = clean_logs([MainLog, SaslLog], Suffix),
+ ok = application:set_env(sasl, sasl_error_logger, tty),
+ ok = application:set_env(kernel, error_logger, tty),
+ ok = control_action(rotate_logs, []),
+ [{error, enoent}, {error, enoent}] = empty_files([MainLog, SaslLog]),
+
+ %% rotate logs when logging is turned off
+ ok = application:set_env(sasl, sasl_error_logger, false),
+ ok = application:set_env(kernel, error_logger, silent),
+ ok = control_action(rotate_logs, []),
+ [{error, enoent}, {error, enoent}] = empty_files([MainLog, SaslLog]),
+
+ %% cleanup
+ ok = application:set_env(sasl, sasl_error_logger, {file, SaslLog}),
+ ok = application:set_env(kernel, error_logger, {file, MainLog}),
+ ok = add_log_handlers([{rabbit_error_logger_file_h, MainLog},
+ {rabbit_sasl_report_file_h, SaslLog}]),
+ passed.
+
+test_log_management_during_startup() ->
+ MainLog = rabbit:log_location(kernel),
+ SaslLog = rabbit:log_location(sasl),
+
+ %% start application with simple tty logging
+ ok = control_action(stop_app, []),
+ ok = application:set_env(kernel, error_logger, tty),
+ ok = application:set_env(sasl, sasl_error_logger, tty),
+ ok = add_log_handlers([{error_logger_tty_h, []},
+ {sasl_report_tty_h, []}]),
+ ok = control_action(start_app, []),
+
+ %% start application with tty logging and
+ %% proper handlers not installed
+ ok = control_action(stop_app, []),
+ ok = error_logger:tty(false),
+ ok = delete_log_handlers([sasl_report_tty_h]),
+ ok = case catch control_action(start_app, []) of
+ ok -> exit(got_success_but_expected_failure);
+ {error, {cannot_log_to_tty, _, _}} -> ok
+ end,
+
+ %% fix sasl logging
+ ok = application:set_env(sasl, sasl_error_logger,
+ {file, SaslLog}),
+
+ %% start application with logging to invalid directory
+ TmpLog = "/tmp/rabbit-tests/test.log",
+ file:delete(TmpLog),
+ ok = application:set_env(kernel, error_logger, {file, TmpLog}),
+
+ ok = delete_log_handlers([rabbit_error_logger_file_h]),
+ ok = add_log_handlers([{error_logger_file_h, MainLog}]),
+ ok = case catch control_action(start_app, []) of
+ ok -> exit(got_success_but_expected_failure);
+ {error, {cannot_log_to_file, _, _}} -> ok
+ end,
+
+ %% start application with standard error_logger_file_h
+ %% handler not installed
+ ok = application:set_env(kernel, error_logger, {file, MainLog}),
+ ok = control_action(start_app, []),
+ ok = control_action(stop_app, []),
+
+ %% start application with standard sasl handler not installed
+ %% and rabbit main log handler installed correctly
+ ok = delete_log_handlers([rabbit_sasl_report_file_h]),
+ ok = control_action(start_app, []),
+ passed.
+
test_cluster_management() ->
%% 'cluster' and 'reset' should only work if the app is stopped
@@ -203,7 +335,6 @@ test_cluster_management() ->
end,
ok = control_action(start_app, []),
-
passed.
test_cluster_management2(SecondaryNode) ->
@@ -329,6 +460,8 @@ test_user_management() ->
passed.
+%---------------------------------------------------------------------
+
control_action(Command, Args) -> control_action(Command, node(), Args).
control_action(Command, Node, Args) ->
@@ -340,3 +473,52 @@ control_action(Command, Node, Args) ->
io:format("failed.~n"),
Other
end.
+
+empty_files(Files) ->
+ [case file:read_file_info(File) of
+ {ok, FInfo} -> FInfo#file_info.size == 0;
+ Error -> Error
+ end || File <- Files].
+
+non_empty_files(Files) ->
+ [case EmptyFile of
+ {error, Reason} -> {error, Reason};
+ _ -> not(EmptyFile)
+ end || EmptyFile <- empty_files(Files)].
+
+test_logs_working(MainLogFile, SaslLogFile) ->
+ ok = rabbit_log:error("foo bar"),
+ ok = error_logger:error_report(crash_report, [foo, bar]),
+ %% give the error loggers some time to catch up
+ timer:sleep(50),
+ [true, true] = non_empty_files([MainLogFile, SaslLogFile]),
+ ok.
+
+clean_logs(Files, Suffix) ->
+ [begin
+ ok = delete_file(File),
+ ok = delete_file([File, Suffix])
+ end || File <- Files],
+ ok.
+
+delete_file(File) ->
+ case file:delete(File) of
+ ok -> ok;
+ {error, enoent} -> ok;
+ Error -> Error
+ end.
+
+make_files_non_writable(Files) ->
+ [ok = file:write_file_info(File, #file_info{mode=0}) ||
+ File <- Files],
+ ok.
+
+add_log_handlers(Handlers) ->
+ [ok = error_logger:add_report_handler(Handler, Args) ||
+ {Handler, Args} <- Handlers],
+ ok.
+
+delete_log_handlers(Handlers) ->
+ [[] = error_logger:delete_report_handler(Handler) ||
+ Handler <- Handlers],
+ ok.