diff options
-rw-r--r-- | docs/rabbitmq-multi.pod | 6 | ||||
-rw-r--r-- | docs/rabbitmqctl.pod | 18 | ||||
-rw-r--r-- | include/rabbit.hrl | 2 | ||||
-rw-r--r-- | include/rabbit_framing_spec.hrl | 2 | ||||
-rw-r--r-- | packaging/RPMS/Fedora/Makefile | 1 | ||||
-rw-r--r-- | packaging/RPMS/Fedora/init.d | 129 | ||||
-rw-r--r-- | packaging/RPMS/Fedora/rabbitmq-server.logrotate | 12 | ||||
-rw-r--r-- | packaging/RPMS/Fedora/rabbitmq-server.spec | 125 | ||||
-rw-r--r-- | packaging/debs/Debian/debian/control | 2 | ||||
-rw-r--r-- | packaging/debs/Debian/debian/copyright | 6 | ||||
-rw-r--r-- | packaging/debs/Debian/debian/dirs | 1 | ||||
-rw-r--r-- | packaging/debs/Debian/debian/init.d | 119 | ||||
-rw-r--r-- | packaging/debs/Debian/debian/rabbitmq-server.logrotate | 12 | ||||
-rw-r--r-- | packaging/debs/Debian/debian/rules | 1 | ||||
-rwxr-xr-x | scripts/rabbitmq-server | 2 | ||||
-rw-r--r-- | scripts/rabbitmq-server.bat | 2 | ||||
-rw-r--r-- | src/rabbit.erl | 131 | ||||
-rw-r--r-- | src/rabbit_control.erl | 8 | ||||
-rw-r--r-- | src/rabbit_error_logger_file_h.erl | 74 | ||||
-rw-r--r-- | src/rabbit_misc.erl | 26 | ||||
-rw-r--r-- | src/rabbit_multi.erl | 66 | ||||
-rw-r--r-- | src/rabbit_sasl_report_file_h.erl | 86 | ||||
-rw-r--r-- | src/rabbit_tests.erl | 184 |
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. |