- uptime counters for SLM
authorAlex Kalimulin <alex@netxms.org>
Wed, 31 Aug 2011 23:06:25 +0000 (23:06 +0000)
committerAlex Kalimulin <alex@netxms.org>
Wed, 31 Aug 2011 23:06:25 +0000 (23:06 +0000)
include/nms_cscp.h
src/server/core/bizservice.cpp
src/server/core/session.cpp
src/server/include/nms_objects.h

index ef383d1..c49aaf8 100644 (file)
@@ -872,6 +872,9 @@ typedef struct
 #define VID_SLMCHECK_TYPE           ((DWORD)391)
 #define VID_REASON                  ((DWORD)392)
 #define VID_NODE_ID                 ((DWORD)393)
+#define VID_UPTIME_DAY                         ((DWORD)394)
+#define VID_UPTIME_WEEK                                ((DWORD)395)
+#define VID_UPTIME_MONTH                       ((DWORD)396)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((DWORD)0x00800000)
index 76155d2..150b7d0 100644 (file)
@@ -34,6 +34,7 @@ BusinessService::BusinessService() : Container()
 {
        m_busy = false;
        m_lastPollTime = time_t(0);
+       m_lastPollStatus = STATUS_UNKNOWN;
        _tcscpy(m_szName, _T("Default"));
 }
 
@@ -46,6 +47,7 @@ BusinessService::BusinessService(const TCHAR *name) : Container(name, 0)
 {
        m_busy = false;
        m_lastPollTime = time_t(0);
+       m_lastPollStatus = STATUS_UNKNOWN;
        nx_strncpy(m_szName, name, MAX_OBJECT_NAME);
 }
 
@@ -211,7 +213,9 @@ BOOL BusinessService::DeleteFromDB()
 void BusinessService::CreateMessage(CSCPMessage *pMsg)
 {
    NetObj::CreateMessage(pMsg);
-   // Calling just a base method should do fine
+   pMsg->SetVariable(VID_UPTIME_DAY, m_uptimeDay);
+   pMsg->SetVariable(VID_UPTIME_WEEK, m_uptimeWeek);
+   pMsg->SetVariable(VID_UPTIME_MONTH, m_uptimeMonth);
 }
 
 
@@ -224,8 +228,6 @@ DWORD BusinessService::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLoc
    if (!bAlreadyLocked)
       LockData();
 
-   // ... and here too
-
    return NetObj::ModifyFromMessage(pRequest, TRUE);
 }
 
@@ -273,8 +275,12 @@ void BusinessService::poll(ClientSession *pSession, DWORD dwRqId, int nPoller)
        // Set the status based on what the kids' been up to
        calculateCompoundStatus();
 
-       m_busy = false;
+       // Update uptime counters
+       updateUptimeStats();
+
+       m_lastPollStatus = m_iStatus;
        DbgPrintf(5, _T("Finished polling of business service %s [%d]"), m_szName, (int)m_dwId);
+       m_busy = false;
 }
 
 
@@ -321,3 +327,127 @@ BOOL BusinessService::addHistoryRecord()
        DBFreeStatement(hStmt);
        return TRUE;
 }
+
+//
+// Initialize uptime statistics (daily, weekly, monthly) by examining slm_service_history
+//
+
+void BusinessService::initUptimeStats()
+{
+       m_uptimeDay             = getUptimeFromDBFor(DAY, &m_downtimeDay);
+       m_uptimeWeek    = getUptimeFromDBFor(WEEK, &m_downtimeWeek);
+       m_uptimeMonth   = getUptimeFromDBFor(MONTH, &m_downtimeMonth);
+}
+
+
+double BusinessService::getUptimeFromDBFor(Period period, LONG *downtime)
+{
+       time_t beginTime;
+       LONG timediffTillNow    = BusinessService::getSecondsSinceBeginningOf(period, &beginTime);
+       double percentage = 0.;
+
+       DB_STATEMENT hStmt = DBPrepare(g_hCoreDB, _T("SELECT change_timestamp,new_status FROM slm_service_history ")
+                                                                                         _T("WHERE service_id=? AND change_timestamp>?"));
+       if (hStmt != NULL)
+       {
+               time_t changeTimestamp, prevChangeTimestamp;
+               int newStatus;
+               DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
+               DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, INT64(beginTime));
+               DB_RESULT hResult = DBSelectPrepared(hStmt);
+               if (hResult == NULL)
+               {
+                       DBFreeStatement(hStmt);
+                       return percentage;
+               }
+               int numRows = DBGetNumRows(hResult);
+               *downtime = 0;
+               prevChangeTimestamp = beginTime;
+               if (numRows > 0) // if <= 0 then assume zero downtime
+               {
+                       for (int i = 0; i < numRows; i++)
+                       {
+                               changeTimestamp = DBGetFieldLong(hResult, i, 0);
+                               newStatus = DBGetFieldLong(hResult, i, 1);
+                               if (newStatus == STATUS_NORMAL)
+                                       *downtime += LONG(changeTimestamp - prevChangeTimestamp);
+                               else 
+                                       prevChangeTimestamp = changeTimestamp;
+                       }
+                       if (newStatus == STATUS_CRITICAL) // the service is still down, add period till now
+                               *downtime += LONG(time(NULL) - prevChangeTimestamp);
+                       DBFreeResult(hResult);
+                       DBFreeStatement(hStmt);
+               }
+               percentage = 100. - *downtime * 100 / timediffTillNow;
+       }
+       
+       return percentage;
+}
+
+//
+// Update uptime counters 
+//
+
+void BusinessService::updateUptimeStats()
+{
+       LONG timediffTillNow;
+       LONG downtimeBetweenPolls = 0;
+
+       if (m_iStatus == STATUS_CRITICAL && m_lastPollStatus == STATUS_CRITICAL)
+               downtimeBetweenPolls = LONG(time(NULL) - m_lastPollTime);               
+
+       timediffTillNow = BusinessService::getSecondsSinceBeginningOf(DAY, NULL);
+       m_downtimeDay += downtimeBetweenPolls;
+       if (timediffTillNow < m_prevDiffDay)
+               m_downtimeDay = 0;
+       m_uptimeDay = 100 - m_downtimeDay * 100 / timediffTillNow;
+       m_prevDiffDay = timediffTillNow;
+
+       timediffTillNow = BusinessService::getSecondsSinceBeginningOf(WEEK, NULL);
+       m_downtimeWeek += downtimeBetweenPolls;
+       if (timediffTillNow < m_prevDiffWeek)
+               m_downtimeWeek = 0;
+       m_uptimeWeek = 100 - m_downtimeWeek * 100 / timediffTillNow;
+       m_prevDiffWeek = timediffTillNow;
+
+       timediffTillNow = BusinessService::getSecondsSinceBeginningOf(MONTH, NULL);
+       m_downtimeMonth += downtimeBetweenPolls;
+       if (timediffTillNow < m_prevDiffMonth)
+               m_downtimeMonth = 0;
+       m_uptimeMonth = 100 - m_downtimeMonth * 100 / timediffTillNow;
+       m_prevDiffMonth = timediffTillNow;
+}
+
+/* static */ LONG BusinessService::getSecondsSinceBeginningOf(Period period, time_t *beginTime /* = NULL */)
+{
+       time_t curTime = time(NULL);
+       struct tm *tms;
+       struct tm tmBuffer;
+
+#if HAVE_LOCALTIME_R
+       tms = localtime_r(&curTime, &tmBuffer);
+#else
+       tms = localtime(&curTime);
+       memcpy((void*)&tmBuffer, (void*)tms, sizeof(struct tm));
+#endif
+
+       tmBuffer.tm_hour = 0;
+       tmBuffer.tm_min = 0;
+       tmBuffer.tm_sec = 0;
+       if (period == MONTH)
+               tmBuffer.tm_mday = 1;
+       time_t beginTimeL = mktime(&tmBuffer);
+       if (period == WEEK)
+       {
+               if (tmBuffer.tm_wday == 0)
+                       tmBuffer.tm_wday = 7;
+               tmBuffer.tm_wday--;
+               beginTimeL -= 3600 * 24 * tmBuffer.tm_wday;
+       }
+
+       if (beginTime != NULL)
+               *beginTime = beginTimeL;
+
+       return LONG(curTime - beginTimeL);
+}
\ No newline at end of file
index 2a61e51..f6c0e11 100644 (file)
@@ -3899,6 +3899,7 @@ void ClientSession::createObject(CSCPMessage *pRequest)
                                                                {
                                                                        pObject = new NodeLink(szObjectName, nodeId);
                                                                        NetObjInsert(pObject, TRUE);
+                                                                       ((NodeLink*)pObject)->applyTemplates();
                                                                }
                                                                else
                                                                {
index 5088fab..19dd4de 100644 (file)
@@ -1644,11 +1644,29 @@ public:
 
 class NXCORE_EXPORTABLE BusinessService : public Container
 {
+       enum Period { DAY, WEEK, MONTH };
+
 protected:
        bool m_busy;
        time_t m_lastPollTime;
+       int m_lastPollStatus;
+       double m_uptimeDay;
+       double m_uptimeWeek;
+       double m_uptimeMonth;
+       LONG m_downtimeDay;
+       LONG m_downtimeWeek;
+       LONG m_downtimeMonth;
+       LONG m_prevDiffDay;
+       LONG m_prevDiffWeek;
+       LONG m_prevDiffMonth;
 
        static LONG logRecordId;
+       static LONG BusinessService::getSecondsSinceBeginningOf(Period period, time_t *beginTime = NULL);
+
+       BOOL addHistoryRecord();
+       void initUptimeStats();
+       void updateUptimeStats();
+       double getUptimeFromDBFor(Period period, LONG *downtime);
 
 public:
        BusinessService();
@@ -1668,7 +1686,6 @@ public:
        bool isReadyForPolling();
        void lockForPolling();
        void poll(ClientSession *pSession, DWORD dwRqId, int nPoller);
-       BOOL addHistoryRecord();
 };