Author: orudyy
Date: Wed Jul 8 12:51:46 2015
New Revision: 1689866
URL: http://svn.apache.org/r1689866
Log:
QPID-6631: [Java Broker] Add option to fail the Broker if logging fails (work
by Lorenz Quack and Alex Rudyy)
Added:
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/BrokerFileLoggerStatusListenerTest.java
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLogger.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLoggerImpl.java
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLogger.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLogger.java?rev=1689866&r1=1689865&r2=1689866&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLogger.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLogger.java
Wed Jul 8 12:51:46 2015
@@ -26,6 +26,7 @@ import java.util.Set;
import org.apache.qpid.server.model.BrokerLogger;
import org.apache.qpid.server.model.DerivedAttribute;
import org.apache.qpid.server.model.ManagedAttribute;
+import org.apache.qpid.server.model.ManagedContextDefault;
import org.apache.qpid.server.model.ManagedObject;
import org.apache.qpid.server.model.ManagedOperation;
import org.apache.qpid.server.model.Param;
@@ -37,6 +38,10 @@ public interface BrokerFileLogger<X exte
String TYPE = "File";
String FILE_NAME = "fileName";
+ String BROKER_FAIL_ON_LOGGER_IO_ERROR = "broker.failOnLoggerIOError";
+ @ManagedContextDefault(name = BROKER_FAIL_ON_LOGGER_IO_ERROR)
+ String DEFAULT_BROKER_FAIL_ON_LOGGER_IO_ERROR = "false";
+
@ManagedAttribute( defaultValue =
"${qpid.work_dir}${file.separator}log${file.separator}qpid.log")
String getFileName();
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLoggerImpl.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLoggerImpl.java?rev=1689866&r1=1689865&r2=1689866&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLoggerImpl.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/BrokerFileLoggerImpl.java
Wed Jul 8 12:51:46 2015
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.server.logging;
+import java.io.IOError;
+import java.io.IOException;
import java.security.AccessControlException;
import java.util.Collection;
import java.util.Map;
@@ -27,23 +29,31 @@ import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
-import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.rolling.RollingFileAppender;
+import ch.qos.logback.core.status.Status;
+import ch.qos.logback.core.status.StatusListener;
+import ch.qos.logback.core.status.StatusManager;
import org.apache.qpid.server.logging.logback.RollingPolicyDecorator;
import org.apache.qpid.server.logging.logback.RolloverWatcher;
+import org.apache.qpid.server.logging.messages.BrokerMessages;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.ManagedAttributeField;
import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
import org.apache.qpid.server.model.Content;
import org.apache.qpid.server.model.Param;
+import org.apache.qpid.server.model.SystemConfig;
import org.apache.qpid.server.util.DaemonThreadFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class BrokerFileLoggerImpl extends
AbstractBrokerLogger<BrokerFileLoggerImpl> implements
BrokerFileLogger<BrokerFileLoggerImpl>, FileLoggerSettings
{
+ private static final Logger LOGGER =
LoggerFactory.getLogger(BrokerFileLoggerImpl.class);
+
private RolloverWatcher _rolloverWatcher;
private ScheduledExecutorService _rolledPolicyExecutor;
@@ -61,6 +71,8 @@ public class BrokerFileLoggerImpl extend
private int _maxHistory;
@ManagedAttributeField
private String _maxFileSize;
+ private StatusManager _statusManager;
+ private StatusListener _logbackStatusListener;
@ManagedObjectFactoryConstructor
protected BrokerFileLoggerImpl(final Map<String, Object> attributes,
Broker<?> broker)
@@ -180,9 +192,62 @@ public class BrokerFileLoggerImpl extend
@Override
protected Appender<ILoggingEvent> createAppenderInstance(Context
loggerContext)
{
+ SystemConfig<?> systemConfig =
(SystemConfig<?>)getParent(Broker.class).getParent(SystemConfig.class);
+ _logbackStatusListener = new BrokerFileLoggerStatusListener(this,
systemConfig);
+ _statusManager = loggerContext.getStatusManager();
+ _statusManager.add(_logbackStatusListener);
+
final RollingFileAppender<ILoggingEvent> appender = new
RollingFileAppender<>();
AppenderUtils.configureRollingFileAppender(this, loggerContext,
appender);
return appender;
}
+ @Override
+ protected void onClose()
+ {
+ super.onClose();
+
+ if (_statusManager != null)
+ {
+ _statusManager.remove(_logbackStatusListener);
+ }
+ }
+
+ static class BrokerFileLoggerStatusListener implements StatusListener
+ {
+ private final SystemConfig<?> _systemConfig;
+ private final BrokerFileLogger<?> _brokerFileLogger;
+
+ public BrokerFileLoggerStatusListener(BrokerFileLogger<?>
brokerFileLogger, SystemConfig<?> systemConfig)
+ {
+ _brokerFileLogger = brokerFileLogger;
+ _systemConfig = systemConfig;
+ }
+
+ @Override
+ public void addStatusEvent(Status status)
+ {
+ Throwable throwable = status.getThrowable();
+ if (status.getEffectiveLevel() == Status.ERROR
+ && (throwable instanceof IOException || throwable
instanceof IOError))
+ {
+ LOGGER.error("Unexpected I/O error whilst trying to write to
log file. Log messages could be lost.", throwable);
+ if (_brokerFileLogger.getContextValue(Boolean.class,
BROKER_FAIL_ON_LOGGER_IO_ERROR))
+ {
+ try
+ {
+ _brokerFileLogger.stopLogging();
+
_systemConfig.getEventLogger().message(BrokerMessages.FATAL_ERROR(
+ String.format("Shutting down the broker
because context variable '%s' is set and unexpected i/o issue occurred: %s",
+ BROKER_FAIL_ON_LOGGER_IO_ERROR,
throwable.getMessage())));
+ }
+ finally
+ {
+ _systemConfig.closeAsync();
+ }
+ }
+ }
+ }
+ }
+
}
Added:
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/BrokerFileLoggerStatusListenerTest.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/BrokerFileLoggerStatusListenerTest.java?rev=1689866&view=auto
==============================================================================
---
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/BrokerFileLoggerStatusListenerTest.java
(added)
+++
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/BrokerFileLoggerStatusListenerTest.java
Wed Jul 8 12:51:46 2015
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.logging;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOError;
+import java.io.IOException;
+
+import ch.qos.logback.core.status.Status;
+import org.apache.qpid.server.model.SystemConfig;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class BrokerFileLoggerStatusListenerTest extends QpidTestCase
+{
+ private BrokerFileLoggerImpl.BrokerFileLoggerStatusListener
_statusListener;
+ private BrokerFileLogger<?> _fileLogger;
+ private SystemConfig<?> _systemConfig;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _fileLogger = mock(BrokerFileLogger.class);
+ _systemConfig = mock(SystemConfig.class);
+ EventLogger eventLogger = mock(EventLogger.class);
+ when(_systemConfig.getEventLogger()).thenReturn(eventLogger);
+ _statusListener = new
BrokerFileLoggerImpl.BrokerFileLoggerStatusListener(_fileLogger, _systemConfig);
+ when(_fileLogger.getContextValue(Boolean.class,
BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR)).thenReturn(true);
+ }
+
+ public void testAddStatusEventForIOError() throws Exception
+ {
+ Status event = createEvent(new IOError(new IOException("Mocked: No
disk space left")), Status.ERROR);
+ _statusListener.addStatusEvent(event);
+
+ verify(_systemConfig).closeAsync();
+ }
+
+ public void testAddStatusEventForIOErrorWithFailOnLoggerIOErrorDisabled()
throws Exception
+ {
+ Status event = createEvent(new IOError(new IOException("Mocked: No
disk space left")), Status.ERROR);
+ when(_fileLogger.getContextValue(Boolean.class,
BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR)).thenReturn(false);
+ _statusListener.addStatusEvent(event);
+
+ verify(_systemConfig, never()).closeAsync();
+ }
+
+ public void testAddStatusEventForIOException() throws Exception
+ {
+ Status event = createEvent(new IOException("Mocked: No disk space
left"), Status.ERROR);
+ _statusListener.addStatusEvent(event);
+
+ verify(_systemConfig).closeAsync();
+ }
+
+ public void testAddStatusEventForIOExceptionReportedAsWarning() throws
Exception
+ {
+ Status event = createEvent(new IOException("Mocked: No disk space
left"), Status.WARN);
+ _statusListener.addStatusEvent(event);
+
+ verify(_systemConfig, never()).closeAsync();
+ }
+
+ public void testAddStatusEventForNonIOException() throws Exception
+ {
+ Status event = createEvent(new RuntimeException("Mocked: No disk space
left"), Status.ERROR);
+ _statusListener.addStatusEvent(event);
+
+ verify(_systemConfig, never()).closeAsync();
+ }
+
+ private Status createEvent(Throwable throwable, int status)
+ {
+ Status event = mock(Status.class);
+ when(event.getThrowable()).thenReturn(throwable);
+ when(event.getEffectiveLevel()).thenReturn(status);
+ return event;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]