You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rn...@apache.org on 2016/04/25 20:41:16 UTC

ambari git commit: AMBARI-16093. LogSearch Integration creates too many error logs during connection failures. (rnettleton)

Repository: ambari
Updated Branches:
  refs/heads/trunk 12c43397f -> e1e51217e


AMBARI-16093. LogSearch Integration creates too many error logs during connection failures. (rnettleton)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/e1e51217
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e1e51217
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e1e51217

Branch: refs/heads/trunk
Commit: e1e51217e801696640ea5fa25b3d4e7fb61be412
Parents: 12c4339
Author: Bob Nettleton <rn...@hortonworks.com>
Authored: Mon Apr 25 14:40:41 2016 -0400
Committer: Bob Nettleton <rn...@hortonworks.com>
Committed: Mon Apr 25 14:41:06 2016 -0400

----------------------------------------------------------------------
 .../logging/LoggingRequestHelperImpl.java       |  14 +-
 .../logging/LoggingSearchPropertyProvider.java  |   6 +-
 .../ambari/server/controller/logging/Utils.java |  65 +++++
 .../server/controller/logging/UtilsTest.java    | 273 +++++++++++++++++++
 4 files changed, 353 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e1e51217/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java
index a5cd369..3fac655 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingRequestHelperImpl.java
@@ -46,6 +46,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Convenience class to handle the connection details of a LogSearch query request.
@@ -67,6 +68,8 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper {
 
   private static final String LOGSEARCH_ADMIN_CREDENTIAL_NAME = "logsearch.admin.credential";
 
+  private static AtomicInteger errorLogCounterForLogSearchConnectionExceptions = new AtomicInteger(0);
+
   private final String hostName;
 
   private final String portNumber;
@@ -112,12 +115,14 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper {
       return logQueryResponseReader.readValue(stringReader);
 
     } catch (Exception e) {
-      LOG.error("Error occurred while trying to connect to the LogSearch service...", e);
+      Utils.logErrorMessageWithThrowableWithCounter(LOG, errorLogCounterForLogSearchConnectionExceptions,
+        "Error occurred while trying to connect to the LogSearch service...", e);
     }
 
     return null;
   }
 
+
   private void setupCredentials(HttpURLConnection httpURLConnection) {
     final String logSearchAdminUser =
       getLogSearchAdminUser();
@@ -217,7 +222,8 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper {
       return logQueryResponseReader.readValue(stringReader);
 
     } catch (Exception e) {
-      LOG.error("Error occurred while trying to connect to the LogSearch service...", e);
+      Utils.logErrorMessageWithThrowableWithCounter(LOG, errorLogCounterForLogSearchConnectionExceptions,
+        "Error occurred while trying to connect to the LogSearch service...", e);
     }
 
     return null;
@@ -291,10 +297,10 @@ public class LoggingRequestHelperImpl implements LoggingRequestHelper {
       if (credential == null) {
         LOG.debug("LogSearch credentials could not be obtained from store.");
       } else {
-        LOG.error("LogSearch credentials were not of the correct type, this is likely an error in configuration, credential type is = " + credential.getClass().getName());
+        LOG.debug("LogSearch credentials were not of the correct type, this is likely an error in configuration, credential type is = " + credential.getClass().getName());
       }
     } catch (AmbariException ambariException) {
-      LOG.error("Error encountered while trying to obtain LogSearch admin credentials.", ambariException);
+      LOG.debug("Error encountered while trying to obtain LogSearch admin credentials.", ambariException);
     }
 
     return null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/e1e51217/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java
index e2da4c8..f80bc6d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/LoggingSearchPropertyProvider.java
@@ -36,6 +36,7 @@ import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class LoggingSearchPropertyProvider implements PropertyProvider {
 
@@ -53,6 +54,8 @@ public class LoggingSearchPropertyProvider implements PropertyProvider {
 
   private static final String PAGE_SIZE_QUERY_PARAMETER_NAME = "pageSize";
 
+  private static AtomicInteger errorLogCounterForLogSearchConnectionExceptions = new AtomicInteger(0);
+
   private final LoggingRequestHelperFactory requestHelperFactory;
 
   private final ControllerFactory controllerFactory;
@@ -126,7 +129,8 @@ public class LoggingSearchPropertyProvider implements PropertyProvider {
             // add the logging metadata for this host component
             resource.setProperty("logging", loggingInfo);
           } else {
-            LOG.error("Error occurred while making request to LogSearch service, unable to populate logging properties on this resource");
+            Utils.logErrorMessageWithCounter(LOG, errorLogCounterForLogSearchConnectionExceptions,
+              "Error occurred while making request to LogSearch service, unable to populate logging properties on this resource");
           }
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e1e51217/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/Utils.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/Utils.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/Utils.java
new file mode 100644
index 0000000..2de7388
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/logging/Utils.java
@@ -0,0 +1,65 @@
+/**
+ * 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.ambari.server.controller.logging;
+
+import org.apache.log4j.Logger;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Utility class to hold static convenience methods for
+ * the LogSearch integration layer
+ *
+ */
+public class Utils {
+
+  private static int WAIT_COUNT_MAX = 1000;
+
+  // dis-allow creating separate instances of this class, since
+  // only static methods will be allowed on this convenience class
+  private Utils() {}
+
+  static void logErrorMessageWithThrowableWithCounter(Logger logger, AtomicInteger atomicInteger, String errorMessage, Throwable throwable) {
+    logErrorMessageWithThrowableWithCounter(logger, atomicInteger, errorMessage, throwable, WAIT_COUNT_MAX);
+  }
+
+
+  static void logErrorMessageWithThrowableWithCounter(Logger logger, AtomicInteger atomicInteger, String errorMessage, Throwable throwable, int maxCount) {
+    if (atomicInteger.getAndIncrement() == 0) {
+      // only log the message once every maxCount attempts
+      logger.error(errorMessage, throwable);
+    } else {
+      // if we've hit maxCount attempts, reset the counter
+      atomicInteger.compareAndSet(maxCount, 0);
+    }
+  }
+
+  static void logErrorMessageWithCounter(Logger logger, AtomicInteger atomicInteger, String errorMessage) {
+    logErrorMessageWithCounter(logger, atomicInteger, errorMessage, WAIT_COUNT_MAX);
+  }
+
+  static void logErrorMessageWithCounter(Logger logger, AtomicInteger atomicInteger, String errorMessage, int maxCount) {
+    if (atomicInteger.getAndIncrement() == 0) {
+      // only log the message once every maxCount attempts
+      logger.error(errorMessage);
+    } else {
+      // if we've hit maxCount attempts, reset the counter
+      atomicInteger.compareAndSet(maxCount, 0);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e1e51217/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/UtilsTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/UtilsTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/UtilsTest.java
new file mode 100644
index 0000000..12267f6
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/logging/UtilsTest.java
@@ -0,0 +1,273 @@
+/**
+ * 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.ambari.server.controller.logging;
+
+import org.apache.log4j.Logger;
+import org.easymock.Capture;
+import org.easymock.EasyMockSupport;
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.eq;
+
+import static org.junit.Assert.assertSame;
+
+public class UtilsTest {
+
+  @Test
+  public void testLogErrorMsgWaitDefault() throws Exception {
+    final String expectedErrorMessage = "This is a test error message!";
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    // expect that the the call to the logger is only
+    // executed once in this test
+    loggerMock.error(expectedErrorMessage);
+    expectLastCall().times(1);
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 1000; i++) {
+      Utils.logErrorMessageWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage);
+    }
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
+  public void testLogErrorMsgWaitDefaultExceedsMaxCount() throws Exception {
+    final String expectedErrorMessage = "This is a test error message that should only repeat once!";
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    // expect that the the call to the logger is only
+    // executed twice in this test
+    loggerMock.error(expectedErrorMessage);
+    expectLastCall().times(2);
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 2000; i++) {
+      Utils.logErrorMessageWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage);
+    }
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
+  public void testLogErrorMsgWithCustomWaitMax() throws Exception {
+    final String expectedErrorMessage = "This is a test error message!";
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    // expect that the the call to the logger is only
+    // executed once in this test
+    loggerMock.error(expectedErrorMessage);
+    expectLastCall().times(1);
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 5; i++) {
+      Utils.logErrorMessageWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage, 5);
+    }
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
+  public void testLogErrorMsgWaitExceedsCustomMaxCount() throws Exception {
+    final String expectedErrorMessage = "This is a test error message that should only repeat once!";
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    // expect that the the call to the logger is only
+    // executed twice in this test
+    loggerMock.error(expectedErrorMessage);
+    expectLastCall().times(2);
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 10; i++) {
+      Utils.logErrorMessageWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage, 5);
+    }
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
+  public void testLogErrorMsgAndThrowableWaitDefault() throws Exception {
+    final String expectedErrorMessage = "This is a test error message!";
+    final Exception expectedException = new Exception("test exception");
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    Capture<Exception> exceptionCaptureOne = new Capture<Exception>();
+
+    // expect that the the call to the logger is only
+    // executed once in this test
+    loggerMock.error(eq(expectedErrorMessage), capture(exceptionCaptureOne));
+    expectLastCall().times(1);
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 1000; i++) {
+      Utils.logErrorMessageWithThrowableWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage, expectedException);
+    }
+
+    assertSame("Exception passed to Logger should have been the same instance passed into the Utils method",
+      expectedException, exceptionCaptureOne.getValue());
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
+  public void testLogErrorMsgAndThrowableWaitDefaultExceedsMaxCount() throws Exception {
+    final String expectedErrorMessage = "This is a test error message that should only repeat once!";
+    final Exception expectedException = new Exception("test exception");
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    Capture<Exception> exceptionCaptureOne = new Capture<Exception>();
+    Capture<Exception> exceptionCaptureTwo = new Capture<Exception>();
+
+    // expect that the the call to the logger is only
+    // executed twice in this test
+    loggerMock.error(eq(expectedErrorMessage), capture(exceptionCaptureOne));
+    loggerMock.error(eq(expectedErrorMessage), capture(exceptionCaptureTwo));
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 2000; i++) {
+      Utils.logErrorMessageWithThrowableWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage, expectedException);
+    }
+
+    assertSame("Exception passed to Logger should have been the same instance passed into the Utils method",
+      expectedException, exceptionCaptureOne.getValue());
+    assertSame("Exception passed to Logger should have been the same instance passed into the Utils method",
+      expectedException, exceptionCaptureTwo.getValue());
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
+  public void testLogErrorMsgAndThrowableWithCustomWaitMax() throws Exception {
+    final String expectedErrorMessage = "This is a test error message!";
+    final Exception expectedException = new Exception("test exception");
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    Capture<Exception> exceptionCaptureOne = new Capture<Exception>();
+
+    // expect that the the call to the logger is only
+    // executed once in this test
+    loggerMock.error(eq(expectedErrorMessage), capture(exceptionCaptureOne));
+    expectLastCall().times(1);
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 5; i++) {
+      Utils.logErrorMessageWithThrowableWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage, expectedException, 5);
+    }
+
+    assertSame("Exception passed to Logger should have been the same instance passed into the Utils method",
+      expectedException, exceptionCaptureOne.getValue());
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
+  public void testLogErrorMsgAndThrowableWaitExceedsCustomMaxCount() throws Exception {
+    final String expectedErrorMessage = "This is a test error message that should only repeat once!";
+    final Exception expectedException = new Exception("test exception");
+
+    EasyMockSupport mockSupport =
+      new EasyMockSupport();
+
+    Logger loggerMock =
+      mockSupport.createMock(Logger.class);
+
+    AtomicInteger testAtomicInteger = new AtomicInteger(0);
+
+    Capture<Exception> exceptionCaptureOne = new Capture<Exception>();
+    Capture<Exception> exceptionCaptureTwo = new Capture<Exception>();
+
+    // expect that the the call to the logger is only
+    // executed twice in this test
+    loggerMock.error(eq(expectedErrorMessage), capture(exceptionCaptureOne));
+    loggerMock.error(eq(expectedErrorMessage), capture(exceptionCaptureTwo));
+
+    mockSupport.replayAll();
+
+    for (int i = 0; i < 10; i++) {
+      Utils.logErrorMessageWithThrowableWithCounter(loggerMock, testAtomicInteger, expectedErrorMessage, expectedException, 5);
+    }
+
+    assertSame("Exception passed to Logger should have been the same instance passed into the Utils method",
+      expectedException, exceptionCaptureOne.getValue());
+    assertSame("Exception passed to Logger should have been the same instance passed into the Utils method",
+      expectedException, exceptionCaptureTwo.getValue());
+
+    mockSupport.verifyAll();
+  }
+
+}