Handle more than 100 error logs

Added new Cap for info(and below) severity errors, if cap size reaches,
next commited error of severity:info(and below) will replace the first
entry of severity:info(and below).

Resolves openbmc/openbmc#2381

Change-Id: I2e56c28a934bf3139e57b36d252bd5ad3e1dd90f
Signed-off-by: Nagaraju Goruganti <ngorugan@in.ibm.com>
diff --git a/configure.ac b/configure.ac
index b73f2ca..256cd8c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -102,6 +102,11 @@
 AS_IF([test "x$ERROR_CAP" == "x"], [ERROR_CAP=100])
 AC_DEFINE_UNQUOTED([ERROR_CAP], [$ERROR_CAP], [Max number of error entries allowed for commit])
 
+AC_ARG_VAR(ERROR_INFO_CAP, [Cap on informational (and below) severity errors])
+AS_IF([test "x$ERROR_INFO_CAP" == "x"], [ERROR_INFO_CAP=10])
+AC_DEFINE_UNQUOTED([ERROR_INFO_CAP], [$ERROR_INFO_CAP], \
+    [Cap on informational (and below) severity errors])
+
 AC_ARG_VAR(CLASS_VERSION, [Class version to register with Cereal])
 AS_IF([test "x$CLASS_VERSION" == "x"], [CLASS_VERSION=1])
 AC_DEFINE_UNQUOTED([CLASS_VERSION], [$CLASS_VERSION], [Class version to register with Cereal])
diff --git a/elog_entry.hpp b/elog_entry.hpp
index 24d93cf..8dcc2a2 100644
--- a/elog_entry.hpp
+++ b/elog_entry.hpp
@@ -111,6 +111,13 @@
          */
         void delete_() override;
 
+        /** @brief Severity level to check in cap.
+         *  @details Errors with severity lesser than this will be
+         *           considered as low priority and maximum ERROR_INFO_CAP
+         *           number errors of this category will be captured.
+        */
+        static constexpr auto sevLowerLimit = Entry::Level::Informational;
+
     private:
         /** @brief This entry's associations */
         AssociationList assocs = {};
diff --git a/log_manager.cpp b/log_manager.cpp
index 1efec9c..bd36d66 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -27,19 +27,37 @@
 {
 void Manager::commit(uint64_t transactionId, std::string errMsg)
 {
-    if (capped)
+    auto reqLevel = level::ERR; // Default to ERR
+    size_t realErrCnt = entries.size() - infoErrors.size();
+    auto levelmap = g_errLevelMap.find(errMsg);
+
+    if (levelmap != g_errLevelMap.end())
     {
-        return;
-    }
-    if (entries.size() >= ERROR_CAP)
-    {
-        log<level::ERR>("Reached error cap, Ignoring error",
-                entry("SIZE=%d", entries.size()),
-                entry("ERROR_CAP=%d", ERROR_CAP));
-        capped = true;
-        return;
+        reqLevel = levelmap->second;
     }
 
+    if (static_cast<Entry::Level>(reqLevel) < Entry::sevLowerLimit)
+    {
+        if (capped)
+        {
+            return;
+        }
+        if (realErrCnt >= ERROR_CAP)
+        {
+            log<level::ERR>("Reached error cap, Ignoring error",
+                            entry("SIZE=%d", realErrCnt),
+                            entry("ERROR_CAP=%d", ERROR_CAP));
+            capped = true;
+            return;
+        }
+    }
+    else
+    {
+        if (infoErrors.size() >= ERROR_INFO_CAP)
+        {
+            erase(infoErrors.front());
+        }
+    }
     constexpr const auto transactionIdVar = "TRANSACTION_ID";
     // Length of 'TRANSACTION_ID' string.
     constexpr const auto transactionIdVarSize = strlen(transactionIdVar);
@@ -149,6 +167,10 @@
 
     // Create error Entry dbus object
     entryId++;
+    if (static_cast<Entry::Level>(reqLevel) >= Entry::sevLowerLimit)
+    {
+        infoErrors.push_back(entryId);
+    }
     auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                 std::chrono::system_clock::now().time_since_epoch()).count();
     auto objPath =  std::string(OBJ_ENTRY) + '/' +
@@ -157,12 +179,6 @@
     AssociationList objects {};
     processMetadata(errMsg, additionalData, objects);
 
-    level reqLevel = level::ERR; // Default to ERR
-    auto levelmap = g_errLevelMap.find(errMsg);
-    if (levelmap != g_errLevelMap.end())
-    {
-        reqLevel = levelmap->second;
-    }
     auto e = std::make_unique<Entry>(
                  busLog,
                  objPath,
@@ -208,11 +224,20 @@
         fs::path errorPath(ERRLOG_PERSIST_PATH);
         errorPath /= std::to_string(id);
         fs::remove(errorPath);
-
+        if (entry->second->severity() >= Entry::sevLowerLimit)
+        {
+            auto it = std::find(infoErrors.begin(), infoErrors.end(), entryId);
+            if (it != infoErrors.end())
+            {
+                infoErrors.erase(it);
+            }
+        }
         entries.erase(entry);
     }
 
-    if (entries.size() <  ERROR_CAP)
+    size_t realErrCnt = entries.size() - infoErrors.size();
+
+    if (realErrCnt <  ERROR_CAP)
     {
         capped = false;
     }
@@ -240,6 +265,10 @@
         if (deserialize(file.path(), *e))
         {
             e->emit_object_added();
+            if (e->severity() >= Entry::sevLowerLimit)
+            {
+                infoErrors.push_back(idNum);
+            }
             entries.insert(std::make_pair(idNum, std::move(e)));
             errorIds.push_back(idNum);
         }
diff --git a/log_manager.hpp b/log_manager.hpp
index af176f9..399a243 100644
--- a/log_manager.hpp
+++ b/log_manager.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <list>
 #include <sdbusplus/bus.hpp>
 #include <phosphor-logging/log.hpp>
 #include "elog_entry.hpp"
@@ -111,6 +112,9 @@
         /** @brief Persistent map of Entry dbus objects and their ID */
         std::map<uint32_t, std::unique_ptr<Entry>> entries;
 
+        /** @brief List of error ids for Info(and below) severity */
+        std::list<uint32_t> infoErrors;
+
         /** @brief Id of last error log entry */
         uint32_t entryId;