You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by mr...@apache.org on 2015/11/02 18:17:09 UTC

[02/17] usergrid git commit: USERGRID-1044: save status code and error message for audit

USERGRID-1044: save status code and error message for audit


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

Branch: refs/heads/master
Commit: 7271935bb340a99f8961a99ca6f2d11b9e48b312
Parents: 1195ce8
Author: Mike Dunker <md...@apigee.com>
Authored: Mon Oct 26 09:56:28 2015 -0700
Committer: Mike Dunker <md...@apigee.com>
Committed: Mon Oct 26 09:56:28 2015 -0700

----------------------------------------------------------------------
 .../runAuditGetAllAppCollectionEntities.sh      |   6 +-
 .../loadtests/runAuditGetCollectionEntities.sh  |   6 +-
 .../datagenerators/FeederGenerator.scala        |   2 +-
 .../usergrid/enums/ConfigProperties.scala       |   6 +-
 .../usergrid/scenarios/AuditScenarios.scala     | 144 ++++++++++++-------
 .../scenarios/EntityCollectionScenarios.scala   |  74 ++++++----
 .../org/apache/usergrid/settings/Settings.scala |  40 ++++--
 7 files changed, 173 insertions(+), 105 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/7271935b/stack/loadtests/runAuditGetAllAppCollectionEntities.sh
----------------------------------------------------------------------
diff --git a/stack/loadtests/runAuditGetAllAppCollectionEntities.sh b/stack/loadtests/runAuditGetAllAppCollectionEntities.sh
index c8a30a3..f1304c0 100755
--- a/stack/loadtests/runAuditGetAllAppCollectionEntities.sh
+++ b/stack/loadtests/runAuditGetAllAppCollectionEntities.sh
@@ -31,10 +31,10 @@ if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
 
 die() { echo "$@" 1>&2 ; exit 1; }
 
-[ "$#" -ge 3 ] || die "At least 3 arguments required, $# provided.  Example is $0 RAMP_USERS RAMP_TIME(seconds) AUDIT_UUID_FILENAME [LATER_THAN_TIMESTAMP(ms)]"
+[ "$#" -ge 3 ] || die "At least 3 arguments required, $# provided.  Example is $0 RAMP_USERS RAMP_TIME(seconds) UUID_FILENAME [LATER_THAN_TIMESTAMP(ms)]"
 RAMP_USERS="$1"
 RAMP_TIME="$2"
-AUDIT_UUID_FILENAME="$3"
+UUID_FILENAME="$3"
 [ "$#" -ge 4 ] && LATER_THAN_TIMESTAMP="$4"
 
 shift 3
@@ -61,7 +61,7 @@ mvn gatling:execute \
 -DscenarioType=${SCENARIO_TYPE} \
 -DrampUsers=${RAMP_USERS}  \
 -DrampTime=${RAMP_TIME}  \
--DauditUuidFilename=${AUDIT_UUID_FILENAME} \
+-DuuidFilename=${UUID_FILENAME} \
 -DprintFailedRequests=${PRINT_FAILED_REQUESTS} \
 -Dgatling.simulationClass=org.apache.usergrid.simulations.AuditSimulation
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7271935b/stack/loadtests/runAuditGetCollectionEntities.sh
----------------------------------------------------------------------
diff --git a/stack/loadtests/runAuditGetCollectionEntities.sh b/stack/loadtests/runAuditGetCollectionEntities.sh
index 2ddc62b..7c87e25 100755
--- a/stack/loadtests/runAuditGetCollectionEntities.sh
+++ b/stack/loadtests/runAuditGetCollectionEntities.sh
@@ -32,10 +32,10 @@ if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
 
 die() { echo "$@" 1>&2 ; exit 1; }
 
-[ "$#" -ge 3 ] || die "At least 3 arguments required, $# provided.  Example is $0 RAMP_USERS RAMP_TIME(seconds) AUDIT_UUID_FILENAME [LATER_THAN_TIMESTAMP(ms)]"
+[ "$#" -ge 3 ] || die "At least 3 arguments required, $# provided.  Example is $0 RAMP_USERS RAMP_TIME(seconds) UUID_FILENAME [LATER_THAN_TIMESTAMP(ms)]"
 RAMP_USERS="$1"
 RAMP_TIME="$2"
-AUDIT_UUID_FILENAME="$3"
+UUID_FILENAME="$3"
 [ "$#" -ge 4 ] && LATER_THAN_TIMESTAMP="$4"
 
 shift 3
@@ -61,7 +61,7 @@ mvn gatling:execute \
 -DscenarioType=${SCENARIO_TYPE} \
 -DrampUsers=${RAMP_USERS}  \
 -DrampTime=${RAMP_TIME}  \
--DauditUuidFilename=${AUDIT_UUID_FILENAME} \
+-DuuidFilename=${UUID_FILENAME} \
 -DprintFailedRequests=${PRINT_FAILED_REQUESTS} \
 -Dgatling.simulationClass=org.apache.usergrid.simulations.AuditSimulation
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7271935b/stack/loadtests/src/main/scala/org/apache/usergrid/datagenerators/FeederGenerator.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/src/main/scala/org/apache/usergrid/datagenerators/FeederGenerator.scala b/stack/loadtests/src/main/scala/org/apache/usergrid/datagenerators/FeederGenerator.scala
index e08f8e8..b8a28d5 100755
--- a/stack/loadtests/src/main/scala/org/apache/usergrid/datagenerators/FeederGenerator.scala
+++ b/stack/loadtests/src/main/scala/org/apache/usergrid/datagenerators/FeederGenerator.scala
@@ -264,7 +264,7 @@ object FeederGenerator {
         if (i >= csvLinesLen) return null
 
         val line = csvLines(i)
-        if (line != Settings.auditUuidsHeader) return line
+        if (line != Settings.uuidsHeader) return line
 
       } while (true)
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7271935b/stack/loadtests/src/main/scala/org/apache/usergrid/enums/ConfigProperties.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/src/main/scala/org/apache/usergrid/enums/ConfigProperties.scala b/stack/loadtests/src/main/scala/org/apache/usergrid/enums/ConfigProperties.scala
index cbb484c..7def02b 100644
--- a/stack/loadtests/src/main/scala/org/apache/usergrid/enums/ConfigProperties.scala
+++ b/stack/loadtests/src/main/scala/org/apache/usergrid/enums/ConfigProperties.scala
@@ -86,7 +86,8 @@ object ConfigProperties {
   val InterleavedWorkerFeed = "interleavedWorkerFeed"
   val NewCsvOnFlush = "newCsvOnFlush"
   val DeleteAfterSuccessfulAudit = "deleteAfterSuccessfulAudit"
-  val UsergridRegion = "usergridRegion";
+  val UsergridRegion = "usergridRegion"
+  val SaveInvalidResponse = "saveInvalidResponse"
 
   val Values = Seq(Org,App,AdminUser,AdminPassword,BaseUrl,AuthType,TokenType,SkipSetup,CreateOrg,CreateApp,LoadEntities,
     ScenarioType,RampUsers,ConstantUsersPerSec,ConstantUsersDuration,UserSeed,AppUser,AppUserPassword,NumEntities,
@@ -96,7 +97,7 @@ object ConfigProperties {
     UuidFilename,AuditUuidFilename,FailedUuidFilename,SandboxCollection,PurgeUsers,RetryCount,LaterThanTimestamp,
     EntityProgressCount,InjectionList,PrintFailedRequests,GetViaQuery,MultiPropertyPrefix,MultiPropertyCount,
     MultiPropertySizeInK,EntityNumberProperty,QueryParams,CsvFeedPattern,UnlimitedFeed,FlushCsv,InterleavedWorkerFeed,
-    NewCsvOnFlush,DeleteAfterSuccessfulAudit,UsergridRegion)
+    NewCsvOnFlush,DeleteAfterSuccessfulAudit,UsergridRegion,SaveInvalidResponse)
 
   def isValid(str: String): Boolean = {
     Values.contains(str)
@@ -171,6 +172,7 @@ object ConfigProperties {
         case NewCsvOnFlush => false
         case DeleteAfterSuccessfulAudit => false
         case UsergridRegion => ""
+        case SaveInvalidResponse => false
       }
     } else {
       null

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7271935b/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/AuditScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/AuditScenarios.scala b/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/AuditScenarios.scala
index 4477338..f90348e 100644
--- a/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/AuditScenarios.scala
+++ b/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/AuditScenarios.scala
@@ -32,6 +32,7 @@ object AuditScenarios {
 
   //The value for the cursor
   val SessionVarCursor: String = "cursor"
+  val SessionVarStatus: String = "status"
   val SessionVarEntityUuid: String = "entityUuid"
   val SessionVarEntityName: String = "entityName"
   val SessionVarDeletedUuid: String = "deletedUuid"
@@ -59,15 +60,16 @@ object AuditScenarios {
       .get(collectionGetUrl(false))
       .headers(Headers.authToken)
       .headers(Headers.usergridRegionHeaders)
-      .check(status.is(200),extractAuditEntities(SessionVarCollectionEntities),maybeExtractCursor(SessionVarCursor)))
+      .check(status.is(200),status.saveAs(SessionVarStatus),extractAuditEntities(SessionVarCollectionEntities),maybeExtractCursor(SessionVarCursor)))
       .foreach("${" + SessionVarCollectionEntities + "}", "singleResult") {
         exec(session => {
           val resultObj = session("singleResult").as[Map[String,Any]]
+          val status = session(SessionVarStatus).as[Int]
           val uuid = resultObj.getOrElse("uuid", "").asInstanceOf[String]
           val entityName = resultObj.getOrElse("name", "").asInstanceOf[String]
-          val modified = resultObj.getOrElse("modified", "-1").asInstanceOf[Long]
+          val modified = resultObj.getOrElse("modified", "0").asInstanceOf[Long]
           val collectionName = session(SessionVarCollectionName).as[String]
-          Settings.addAuditUuid(uuid, collectionName, entityName, modified)
+          Settings.addUuid(uuid, collectionName, entityName, modified, status)
           session
         })
       }
@@ -77,15 +79,16 @@ object AuditScenarios {
       .get(collectionGetUrl(true))
       .headers(Headers.authToken)
       .headers(Headers.usergridRegionHeaders)
-      .check(status.is(200),extractAuditEntities(SessionVarCollectionEntities),maybeExtractCursor(SessionVarCursor)))
+      .check(status.is(200),status.saveAs(SessionVarStatus),extractAuditEntities(SessionVarCollectionEntities),maybeExtractCursor(SessionVarCursor)))
       .foreach("${" + SessionVarCollectionEntities + "}", "singleResult") {
         exec(session => {
           val resultObj = session("singleResult").as[Map[String,Any]]
+          val status = session(SessionVarStatus).as[Int]
           val uuid = resultObj.getOrElse("uuid","").asInstanceOf[String]
           val entityName = resultObj.getOrElse("name","").asInstanceOf[String]
           val modified = resultObj.getOrElse("modified","-1").asInstanceOf[Long]
           val collectionName = session(SessionVarCollectionName).as[String]
-          Settings.addAuditUuid(uuid, collectionName, entityName, modified)
+          Settings.addUuid(uuid, collectionName, entityName, modified, status)
           session
         })
       }
@@ -108,12 +111,12 @@ object AuditScenarios {
             }
           }
         }
-    }.exec { session =>
+    /*}.exec { session =>
       // displays the content of the session in the console (debugging only)
       println(session)
 
       // return the original session
-      session
+      session */
     }
 
   val deleteAuditedEntity = exec(
@@ -129,7 +132,11 @@ object AuditScenarios {
           // successful
           Settings.incAuditEntryDeleteSuccess()
         } else {
+          val collectionName = session(SessionVarCollectionName).as[String]
+          val reqName = session("name").as[String]
+          val entityUuid = session(SessionVarEntityUuid).as[String]
           Settings.incAuditEntryDeleteFailure()
+          println(s"DELETE FAILED: $collectionName:$reqName ($entityUuid)")
         }
 
         session
@@ -141,64 +148,80 @@ object AuditScenarios {
       .headers(Headers.authToken)
       .headers(Headers.usergridRegionHeaders)
       .check()
-      .check(status.in(Seq(200,404)),extractAuditEntities(SessionVarCollectionEntities),
+      .check(status.in(Seq(200,404)),status.saveAs(SessionVarStatus),extractAuditEntities(SessionVarCollectionEntities),
         extractEntityUuid(SessionVarEntityUuid),extractEntityName(SessionVarEntityName)))
       .exec(session => {
+        val saveFailures = Settings.saveInvalidResponse
+        val status = session(SessionVarStatus).as[Int]
+        val collectionName = session(SessionVarCollectionName).as[String]
+        val modified = session("modified").as[String].toLong
         val uuid = session("uuid").as[String]
         val reqName = session("name").as[String]
-        val modified = session("modified").as[String].toLong
-        val collectionName = session(SessionVarCollectionName).as[String]
-        val collectionEntities = session(SessionVarCollectionEntities).as[Seq[Any]]
-        val entityUuid = session(SessionVarEntityUuid).as[String]
-        val entityName = session(SessionVarEntityName).as[String]
+        if (status == 200 || status == 404) {
+          val collectionEntities = session(SessionVarCollectionEntities).as[Seq[Any]]
+          val entityUuid = session(SessionVarEntityUuid).as[String]
+          val entityName = session(SessionVarEntityName).as[String]
 
-        val count = collectionEntities.length
-        if (count < 1) {
-          Settings.addAuditUuid(uuid, collectionName, reqName, modified)
-          Settings.incAuditNotFoundAtAll()
-          println(s"NOT FOUND AT ALL: $collectionName.$reqName ($uuid)")
-        } else if (count > 1) {
-          // invalid
-          Settings.addAuditUuid(uuid, collectionName, reqName, modified)
-          Settings.incAuditBadResponse()
-          println(s"INVALID RESPONSE (count=$count): $collectionName.$reqName ($uuid)")
-        } else {
-          // count == 1 -> found via direct access but not query
+          val count = collectionEntities.length
+          if (count < 1) {
+            Settings.addAuditUuid(uuid, collectionName, reqName, modified, status, s"NotFoundAtAll")
+            Settings.incAuditNotFoundAtAll()
+            println(s"NOT FOUND AT ALL: $collectionName.$reqName ($uuid)")
+          } else if (count > 1) {
+            // invalid
+            Settings.addAuditUuid(uuid, collectionName, reqName, modified, status, s"QueryInvalidCount$count")
+            Settings.incAuditBadResponse()
+            println(s"INVALID RESPONSE (count=$count): $collectionName.$reqName ($uuid)")
+          } else {
+            // count == 1 -> found via direct access but not query
 
-          // will count as found directly even if there is a uuid or name mismatch
-          if (entityUuid == null || entityUuid.isEmpty) {
-            Settings.incAuditPayloadUuidError()
-            println(s"PAYLOAD UUID MISSING (DIRECT): requestedUuid=$uuid")
-          } else if (!uuid.equalsIgnoreCase(entityUuid)) {
-            Settings.incAuditPayloadUuidError()
-            println(s"PAYLOAD UUID MISMATCH (DIRECT): requestedUuid=$uuid returnedUuid=$entityUuid")
-          }
-          if (entityName == null || entityName.isEmpty) {
-            Settings.incAuditPayloadNameError()
-            println(s"PAYLOAD NAME MISSING (DIRECT): requestedName=$reqName")
-          } else if (!reqName.equalsIgnoreCase(entityName)) {
-            Settings.incAuditPayloadNameError()
-            println(s"PAYLOAD NAME MISMATCH (DIRECT): requestedName=$reqName returnedName=$entityName")
-          }
+            // will count as found directly even if there is a uuid or name mismatch
+            val errorPrefix = "DirectAccessSuccessful"
+            var errorString: String = errorPrefix
+            if (entityUuid == null || entityUuid.isEmpty) {
+              errorString += "|NoUuidReturned"
+              Settings.incAuditPayloadUuidError()
+              println(s"PAYLOAD UUID MISSING (DIRECT): requestedUuid=$uuid")
+            } else if (!uuid.equalsIgnoreCase(entityUuid)) {
+              errorString += "|ReturnedUuidMismatch"
+              Settings.incAuditPayloadUuidError()
+              println(s"PAYLOAD UUID MISMATCH (DIRECT): requestedUuid=$uuid returnedUuid=$entityUuid")
+            }
+            if (entityName == null || entityName.isEmpty) {
+              errorString += "|NoNameReturned"
+              Settings.incAuditPayloadNameError()
+              println(s"PAYLOAD NAME MISSING (DIRECT): requestedName=$reqName")
+            } else if (!reqName.equalsIgnoreCase(entityName)) {
+              errorString += "|ReturnedNameMismatch"
+              Settings.incAuditPayloadNameError()
+              println(s"PAYLOAD NAME MISMATCH (DIRECT): requestedName=$reqName returnedName=$entityName")
+            }
 
-          Settings.addAuditUuid(uuid, collectionName, reqName, modified)
-          Settings.incAuditNotFoundViaQuery()
-          println(s"NOT FOUND VIA QUERY: $collectionName.$reqName ($uuid)")
+            Settings.addAuditUuid(uuid, collectionName, reqName, modified, status, errorString)
+            Settings.incAuditNotFoundViaQuery()
+            println(s"NOT FOUND VIA QUERY: $collectionName.$reqName ($uuid)")
+          }
+          session
+        } else if (saveFailures) {
+          Settings.addAuditUuid(uuid, collectionName, reqName, modified, status, "Failure")
+          session
+        } else {
+          session.markAsFailed
         }
 
-        session
-      })
+      }).exitHereIfFailed
 
   val getCollectionEntity = exec(
     http("GET collection entity")
       .get("/${collectionName}?ql=uuid=${uuid}")
       .headers(Headers.authToken)
       .headers(Headers.usergridRegionHeaders)
-      .check(status.is(200),jsonPath("$.count").optional.saveAs("count"),
+      .check(status.is(200), status.saveAs(SessionVarStatus), jsonPath("$.count").optional.saveAs("count"),
         extractAuditEntities(SessionVarCollectionEntities),
         extractEntityUuid(SessionVarEntityUuid),extractEntityName(SessionVarEntityName)))
       .exec(session => {
         val count = session("count").as[String].toInt
+        val status = session(SessionVarStatus).as[Int]
         val uuid = session("uuid").as[String]
         val reqName = session("name").as[String]
         val modified = session("modified").as[String].toLong
@@ -209,29 +232,40 @@ object AuditScenarios {
         if (count < 1) {
           // will check to see whether accessible directly
         } else if (count > 1) {
-          Settings.addAuditUuid(uuid, collectionName, reqName, modified)
+          Settings.addAuditUuid(uuid, collectionName, reqName, modified, status, s"QueryInvalidCount$count")
           Settings.incAuditBadResponse()
           println(s"INVALID RESPONSE (count=$count): $collectionName.$reqName ($uuid)")
         } else {
           // count == 1 -> success
           // println(s"FOUND: $collectionName.$entityName ($uuid)")
 
-          // will count as success even if there is a uuid or name mismatch
+          val errorPrefix = "QuerySuccessful"
+          var errorString: String = errorPrefix
           if (entityUuid == null || entityUuid.isEmpty) {
+            errorString += "|NoUuidReturned"
             Settings.incAuditPayloadUuidError()
             println(s"PAYLOAD UUID MISSING (QUERY): requestedUuid=$uuid")
           } else if (!uuid.equalsIgnoreCase(entityUuid)) {
+            errorString += "|ReturnedUuidMismatch"
             Settings.incAuditPayloadUuidError()
             println(s"PAYLOAD UUID MISMATCH (QUERY): requestedUuid=$uuid returnedUuid=$entityUuid")
           }
-          if (entityName == null || entityName.isEmpty) {
-            Settings.incAuditPayloadNameError()
-            println(s"PAYLOAD NAME MISSING (QUERY): requestedName=$reqName")
-          } else if (!reqName.equalsIgnoreCase(entityName)) {
-            Settings.incAuditPayloadNameError()
-            println(s"PAYLOAD NAME MISMATCH (QUERY): requestedName=$reqName returnedName=$entityName")
+          if (reqName != null && reqName != "") {
+            if (entityName == null || entityName.isEmpty) {
+              errorString += "|NoNameReturned"
+              Settings.incAuditPayloadNameError()
+              println(s"PAYLOAD NAME MISSING (QUERY): requestedName=$reqName")
+            } else if (!reqName.equalsIgnoreCase(entityName)) {
+              errorString += "|ReturnedNameMismatch"
+              Settings.incAuditPayloadNameError()
+              println(s"PAYLOAD NAME MISMATCH (QUERY): requestedName=$reqName returnedName=$entityName")
+            }
           }
 
+          // log even if technically successful -- we need to capture incorrect response
+          if (errorString != errorPrefix) {
+            Settings.addAuditUuid(uuid, collectionName, reqName, modified, status, errorString)
+          }
           Settings.incAuditSuccess()
         }
 
@@ -252,7 +286,7 @@ object AuditScenarios {
     .asLongAs(session => session("validEntity").asOption[String].map(validEntity => validEntity != "no").getOrElse[Boolean](true)) {
     feed(FeederGenerator.collectionCsvFeeder)
       .doIf(session => session("validEntity").as[String] == "yes") {
-        tryMax(1+Settings.retryCount) {
+        tryMax(if (Settings.saveInvalidResponse) 1 else 1+Settings.retryCount) {
           exec(getCollectionEntity)
         }
       }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7271935b/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/EntityCollectionScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/EntityCollectionScenarios.scala b/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/EntityCollectionScenarios.scala
index b56917a..ecd0c21 100644
--- a/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/EntityCollectionScenarios.scala
+++ b/stack/loadtests/src/main/scala/org/apache/usergrid/scenarios/EntityCollectionScenarios.scala
@@ -35,6 +35,7 @@ object EntityCollectionScenarios {
 
   //The value for the cursor
   val SessionVarCursor: String = "cursor"
+  val SessionVarStatus: String = "status"
   val SessionVarUuid: String = "createUuid"
   val SessionVarModified: String = "createModified"
 
@@ -216,15 +217,22 @@ object EntityCollectionScenarios {
         .headers(Headers.usergridRegionHeaders)
         .body(StringBody("""${entity}"""))
         // 200 for success, 400 if already exists
-        .check(status.in(Seq(200)), extractEntityUuid(SessionVarUuid), extractEntityModified(SessionVarModified)))
+        .check(status.saveAs(SessionVarStatus), extractEntityUuid(SessionVarUuid), extractEntityModified(SessionVarModified)))
         .exec(session => {
-          val uuid = session(SessionVarUuid).as[String]
-          val entityName = session("entityName").as[String]
-          val modified = session(SessionVarModified).as[Long]
-          val collectionName = session("collectionName").as[String]
-          Settings.addUuid(uuid, collectionName, entityName, modified)
-          session
-        })
+          val saveFailures = Settings.saveInvalidResponse
+          val status = session(SessionVarStatus).as[Int]
+          Settings.addStatus(status)
+          if (saveFailures || status == 200) {
+            val uuid = if (status == 200) session(SessionVarUuid).as[String] else ""
+            val entityName = session("entityName").as[String]
+            val modified = if (status == 200) session(SessionVarModified).as[Long] else 0
+            val collectionName = session("collectionName").as[String]
+            Settings.addUuid(uuid, collectionName, entityName, modified, status)
+            session
+          } else {
+            session.markAsFailed
+          }
+        }).exitHereIfFailed
     }
   )
 
@@ -238,7 +246,7 @@ object EntityCollectionScenarios {
           session
         }*/
         .doIf(session => session("validEntity").as[String] == "yes") {
-          tryMax(1+Settings.retryCount) {
+          tryMax(if (Settings.saveInvalidResponse) 1 else 1+Settings.retryCount) {
             exec(loadEntity)
           }
         }
@@ -309,15 +317,22 @@ object EntityCollectionScenarios {
         .queryParamMap(Settings.queryParamMap)
         .headers(Headers.authAnonymous)
         .headers(Headers.usergridRegionHeaders)
-        .check(status.is(200), extractEntityUuid(SessionVarUuid), extractEntityModified(SessionVarModified)))
+        .check(status.saveAs(SessionVarStatus), extractEntityUuid(SessionVarUuid), extractEntityModified(SessionVarModified)))
         .exec(session => {
-          val uuid = session(SessionVarUuid).as[String]
-          val entityName = session("entityName").as[String]
-          val modified = session(SessionVarModified).as[Long]
-          val collectionName = session("collectionName").as[String]
-          Settings.addUuid(uuid, collectionName, entityName, modified)
-          session
-        })
+          val saveFailures = Settings.saveInvalidResponse
+          val status = session(SessionVarStatus).as[Int]
+          Settings.addStatus(status)
+          if (saveFailures || status == 200) {
+            val uuid = if (status == 200) session(SessionVarUuid).as[String] else ""
+            val entityName = session("entityName").as[String]
+            val modified = if (status == 200) session(SessionVarModified).as[Long] else 0
+            val collectionName = session("collectionName").as[String]
+            Settings.addUuid(uuid, collectionName, entityName, modified, status)
+            session
+          } else {
+            session.markAsFailed
+          }
+        }).exitHereIfFailed
     }
   )
 
@@ -328,15 +343,22 @@ object EntityCollectionScenarios {
         .queryParamMap(Settings.queryParamMap)
         .headers(Headers.authToken)
         .headers(Headers.usergridRegionHeaders)
-        .check(status.is(200), extractEntityUuid(SessionVarUuid), extractEntityModified(SessionVarModified)))
+        .check(status.saveAs(SessionVarStatus), extractEntityUuid(SessionVarUuid), extractEntityModified(SessionVarModified)))
         .exec(session => {
-          val uuid = session(SessionVarUuid).as[String]
-          val entityName = session("entityName").as[String]
-          val modified = session(SessionVarModified).as[Long]
-          val collectionName = session("collectionName").as[String]
-          Settings.addUuid(uuid, collectionName, entityName, modified)
-          session
-      })
+          val saveFailures = Settings.saveInvalidResponse
+          val status = session(SessionVarStatus).as[Int]
+          Settings.addStatus(status)
+          if (saveFailures || status == 200) {
+            val uuid = if (status == 200) session(SessionVarUuid).as[String] else ""
+            val entityName = session("entityName").as[String]
+            val modified = if (status == 200) session(SessionVarModified).as[Long] else 0
+            val collectionName = session("collectionName").as[String]
+            Settings.addUuid(uuid, collectionName, entityName, modified, status)
+            session
+          } else {
+            session.markAsFailed
+          }
+      }).exitHereIfFailed
     }
   )
 
@@ -350,7 +372,7 @@ object EntityCollectionScenarios {
           session
         }*/
         .doIf(session => session("validEntity").as[String] == "yes") {
-          tryMax(1+Settings.retryCount) {
+          tryMax(if (Settings.saveInvalidResponse) 1 else 1+Settings.retryCount) {
             doIfOrElse(_ => Settings.authType == AuthType.Anonymous) {
               exec(getEntityByNameSequentialAnonymous)
             } {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7271935b/stack/loadtests/src/main/scala/org/apache/usergrid/settings/Settings.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/src/main/scala/org/apache/usergrid/settings/Settings.scala b/stack/loadtests/src/main/scala/org/apache/usergrid/settings/Settings.scala
index 2ecc3e3..1db0a55 100755
--- a/stack/loadtests/src/main/scala/org/apache/usergrid/settings/Settings.scala
+++ b/stack/loadtests/src/main/scala/org/apache/usergrid/settings/Settings.scala
@@ -188,6 +188,7 @@ object Settings {
   val newCsvOnFlush:Boolean = initBoolSetting(ConfigProperties.NewCsvOnFlush)
   val deleteAfterSuccessfulAudit:Boolean = initBoolSetting(ConfigProperties.DeleteAfterSuccessfulAudit)
   val usergridRegion = initStrSetting(ConfigProperties.UsergridRegion)
+  val saveInvalidResponse = initBoolSetting(ConfigProperties.SaveInvalidResponse)
 
   val multiPropertyPrefix = initStrSetting(ConfigProperties.MultiPropertyPrefix)
   val multiPropertyCount:Int = initIntSetting(ConfigProperties.MultiPropertyCount)
@@ -289,22 +290,31 @@ object Settings {
 
   val purgeUsers:Int = initIntSetting(ConfigProperties.PurgeUsers)
 
-  val auditUuidsHeader = "collection,name,uuid,modified"
-  val uuidsHeader = "name,uuid"
-  case class AuditList(var collection: String, var entityName: String, var uuid: String, var modified: Long)
+  val uuidsHeader = "collection,name,uuid,modified,status"
+  val uuidsFailHeader = "collection,name,uuid,modified,status,error"
+  case class AuditList(var collection: String, var entityName: String, var uuid: String, var modified: Long, var status: Int)
+  case class AuditFailList(var collection: String, var entityName: String, var uuid: String, var modified: Long, var status: Int, var error: String)
 
   //private var uuidMap: Map[Int, String] = Map()
   private var uuidList: mutable.MutableList[AuditList] = mutable.MutableList[AuditList]()
+  private val statusCounts: mutable.Map[Int,Long] = mutable.Map[Int,Long]().withDefaultValue(0L)
   private var entityCounter: Long = 0L
   private var lastEntityCountPrinted: Long = 0L
   private var flushCounter: Long = 0L
   private var firstFlush: Boolean = true
   private var numberFlushes: Long = 0L
   private var uuidWriter: PrintWriter = null
-  def addUuid(uuid: String, collection: String, entityName: String, modified: Long): Unit = {
+
+  def addStatus(status: Int): Unit = {
+    statusCounts.synchronized {
+      statusCounts(status) += 1L
+    }
+  }
+
+  def addUuid(uuid: String, collection: String, entityName: String, modified: Long, status: Int): Unit = {
     if (captureUuids) {
       uuidList.synchronized {
-        uuidList += AuditList(collection, entityName, uuid, modified)
+        uuidList += AuditList(collection, entityName, uuid, modified, status)
         entityCounter += 1L
         flushCounter += 1L
         if (logEntityProgress && (entityCounter >= lastEntityCountPrinted + entityProgressCount)) {
@@ -320,11 +330,11 @@ object Settings {
             }
           }
           if (newCsvOnFlush || firstFlush) {
-            uuidWriter.println(auditUuidsHeader)
+            uuidWriter.println(uuidsHeader)
           }
           val sortedUuidList: List[AuditList] = uuidList.toList.sortBy(e => (e.collection, e.entityName, e.modified))
           sortedUuidList.foreach { e =>
-            uuidWriter.println(s"${e.collection},${e.entityName},${e.uuid},${e.modified}")
+            uuidWriter.println(s"${e.collection},${e.entityName},${e.uuid},${e.modified},${e.status}")
           }
           uuidWriter.flush()
           if (newCsvOnFlush) {
@@ -351,11 +361,11 @@ object Settings {
         }
       }
       if (newCsvOnFlush || firstFlush) {
-        uuidWriter.println(auditUuidsHeader)
+        uuidWriter.println(uuidsHeader)
       }
       val sortedUuidList: List[AuditList] = uuidList.toList.sortBy(e => (e.collection, e.entityName, e.modified))
       sortedUuidList.foreach { e =>
-        uuidWriter.println(s"${e.collection},${e.entityName},${e.uuid},${e.modified}")
+        uuidWriter.println(s"${e.collection},${e.entityName},${e.uuid},${e.modified},${e.status}")
       }
       uuidWriter.flush()
       uuidWriter.close()
@@ -370,11 +380,11 @@ object Settings {
   // key: uuid, value: collection
   private var auditEntityCounter: Long = 0L
   private var lastAuditEntityCountPrinted: Long = 0L
-  private var auditUuidList: mutable.MutableList[AuditList] = mutable.MutableList[AuditList]()
-  def addAuditUuid(uuid: String, collection: String, entityName: String, modified: Long): Unit = {
+  private var auditUuidList: mutable.MutableList[AuditFailList] = mutable.MutableList[AuditFailList]()
+  def addAuditUuid(uuid: String, collection: String, entityName: String, modified: Long, status: Int, error: String): Unit = {
     if (captureAuditUuids) {
       auditUuidList.synchronized {
-        auditUuidList += AuditList(collection, entityName, uuid, modified)
+        auditUuidList += AuditFailList(collection, entityName, uuid, modified, status, error)
         auditEntityCounter += 1L
         if (logEntityProgress && (auditEntityCounter >= lastAuditEntityCountPrinted + entityProgressCount)) {
           println(s"Entity: $auditEntityCounter")
@@ -391,10 +401,10 @@ object Settings {
         val fos = new FileOutputStream(captureAuditUuidFilename)
         new PrintWriter(fos, false)
       }
-      writer.println(auditUuidsHeader)
-      val uuidList: List[AuditList] = auditUuidList.toList.sortBy(e => (e.collection, e.entityName, e.modified))
+      writer.println(uuidsFailHeader)
+      val uuidList: List[AuditFailList] = auditUuidList.toList.sortBy(e => (e.collection, e.entityName, e.modified, e.status))
       uuidList.foreach { e =>
-        writer.println(s"${e.collection},${e.entityName},${e.uuid},${e.modified}")
+        writer.println(s"${e.collection},${e.entityName},${e.uuid},${e.modified},${e.status},${e.error}")
       }
       writer.flush()
       writer.close()