Implemented Debug Tag functionality
authorEriks Jenkevics <eriks@netxms.org>
Thu, 31 Aug 2017 05:28:14 +0000 (08:28 +0300)
committerEriks Jenkevics <eriks@netxms.org>
Thu, 14 Sep 2017 05:21:03 +0000 (08:21 +0300)
20 files changed:
include/nms_util.h
src/agent/core/messages.mc
src/agent/core/nxagentd.cpp
src/client/nxshell/nxshell.cpp
src/db/libnxdb/dbcp.cpp
src/db/libnxdb/main.cpp
src/db/libnxdb/session.cpp
src/libnetxms/Makefile.am
src/libnetxms/config.cpp
src/libnetxms/debug_tag_tree.cpp [new file with mode: 0644]
src/libnetxms/debug_tag_tree.h [new file with mode: 0644]
src/libnetxms/log.cpp
src/server/core/config.cpp
src/server/core/console.cpp
src/server/core/main.cpp
src/server/libnxsrv/messages.mc
src/server/netxmsd/netxmsd.cpp
src/server/tools/nxget/nxget.cpp
tests/test-libnetxms/.cproject
tests/test-libnetxms/test-libnetxms.cpp

index b39bcb1..68476df 100644 (file)
@@ -2449,18 +2449,21 @@ TCHAR LIBNETXMS_EXPORTABLE *safe_fgetts(TCHAR *buffer, int len, FILE *f);
 
 bool LIBNETXMS_EXPORTABLE nxlog_open(const TCHAR *logName, UINT32 flags, const TCHAR *msgModule,
                                      unsigned int msgCount, const TCHAR **messages,
-                                     DWORD debugMsg, DWORD genericMsg);
+                                     DWORD debugMsg, DWORD debugMsgTag, DWORD genericMsg);
 void LIBNETXMS_EXPORTABLE nxlog_close();
 void LIBNETXMS_EXPORTABLE nxlog_write(DWORD msg, WORD wType, const char *format, ...);
 void LIBNETXMS_EXPORTABLE nxlog_write_generic(WORD type, const TCHAR *format, ...);
 void LIBNETXMS_EXPORTABLE nxlog_debug(int level, const TCHAR *format, ...);
+void LIBNETXMS_EXPORTABLE nxlog_debug_tag(const TCHAR *tag, int level, const TCHAR *format, ...);
 void LIBNETXMS_EXPORTABLE nxlog_debug2(int level, const TCHAR *format, va_list args);
 bool LIBNETXMS_EXPORTABLE nxlog_set_rotation_policy(int rotationMode, UINT64 maxLogSize, int historySize, const TCHAR *dailySuffix);
 bool LIBNETXMS_EXPORTABLE nxlog_rotate();
 void LIBNETXMS_EXPORTABLE nxlog_set_debug_level(int level);
+void LIBNETXMS_EXPORTABLE nxlog_set_debug_level_tag(const TCHAR *tags, int level);
 int LIBNETXMS_EXPORTABLE nxlog_get_debug_level();
+int LIBNETXMS_EXPORTABLE nxlog_get_debug_level_tag(const TCHAR *tag);
 
-typedef void (*NxLogDebugWriter)(const TCHAR *);
+typedef void (*NxLogDebugWriter)(const TCHAR *, const TCHAR *);
 void LIBNETXMS_EXPORTABLE nxlog_set_debug_writer(NxLogDebugWriter writer);
 
 typedef void (*NxLogConsoleWriter)(const TCHAR *, ...);
index 1961ab7..2e089c9 100644 (file)
@@ -356,4 +356,10 @@ Language=English
 Core agent version %1
 .
 
+MessageId=
+SymbolicName=MSG_DEBUG_TAG
+Language=English
+<%1> %2
+.
+
 ;#endif
index 79606ba..4bd3ba7 100644 (file)
@@ -232,6 +232,7 @@ static UINT32 s_logRotationMode = NXLOG_ROTATION_BY_SIZE;
 static TCHAR s_dailyLogFileSuffix[64] = _T("");
 static TCHAR s_executableName[MAX_PATH];
 static UINT32 s_debugLevel = (UINT32)NXCONFIG_UNINITIALIZED_VALUE;
+static TCHAR *s_debugTags = NULL;
 
 static CONDITION s_subAgentsStopCondition = INVALID_CONDITION_HANDLE;
 #if defined(_WIN32)
@@ -259,6 +260,7 @@ static NX_CFG_TEMPLATE m_cfgTemplate[] =
    { _T("DataReconciliationTimeout"), CT_LONG, 0, 0, 0, 0, &g_dcReconciliationTimeout, NULL },
    { _T("DailyLogFileSuffix"), CT_STRING, 0, 0, 64, 0, s_dailyLogFileSuffix, NULL },
        { _T("DebugLevel"), CT_LONG, 0, 0, 0, 0, &s_debugLevel, &s_debugLevel },
+   { _T("DebugTags"), CT_STRING_LIST, ',', 0, 0, 0, &s_debugTags, NULL },
    { _T("DisableIPv4"), CT_BOOLEAN, 0, 0, AF_DISABLE_IPV4, 0, &g_dwFlags, NULL },
    { _T("DisableIPv6"), CT_BOOLEAN, 0, 0, AF_DISABLE_IPV6, 0, &g_dwFlags, NULL },
    { _T("DumpDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, s_dumpDir, NULL },
@@ -720,9 +722,9 @@ BOOL Initialize()
                    ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
                        _T("NXAGENTD.EXE"),
 #ifdef _WIN32
-                       0, NULL, MSG_DEBUG, MSG_SUBAGENT_MSG))
+                       0, NULL, MSG_DEBUG, MSG_DEBUG_TAG, MSG_SUBAGENT_MSG))
 #else
-                       g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_SUBAGENT_MSG))
+                       g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_DEBUG_TAG, MSG_SUBAGENT_MSG))
 #endif
        {
           //TODO: set flag that log have been opened with errors
@@ -733,9 +735,9 @@ BOOL Initialize()
                   ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
                       _T("NXAGENTD.EXE"),
 #ifdef _WIN32
-                      0, NULL, MSG_DEBUG, MSG_SUBAGENT_MSG);
+                      0, NULL, MSG_DEBUG, MSG_DEBUG_TAG, MSG_SUBAGENT_MSG);
 #else
-                      g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_SUBAGENT_MSG);
+                      g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_DEBUG_TAG, MSG_SUBAGENT_MSG);
 #endif
                _ftprintf(stderr, _T("ERROR: Cannot open log file, logs will be written to syslog with debug level 1\n"));
 
@@ -752,6 +754,29 @@ BOOL Initialize()
        nxlog_write(MSG_AGENT_VERSION, NXLOG_INFO, "s", NETXMS_BUILD_TAG);
        nxlog_write(MSG_USE_CONFIG_D, NXLOG_INFO, "s", g_szConfigIncludeDir);
        nxlog_write(MSG_DEBUG_LEVEL, NXLOG_INFO, "d", s_debugLevel);
+
+       int numTags = 0, lvl = 0;
+   TCHAR tagBuffer[254], lvlBuffer[2];
+   TCHAR const *ptr;
+
+   _tprintf(_T("Taglist: %s\n"), s_debugTags);
+   TCHAR **tagList = SplitString(s_debugTags, _T(','), &numTags);
+   if (tagList != NULL)
+   {
+      for(int i = 0; i < numTags; i++)
+      {
+         ptr = ExtractWord(tagList[i], tagBuffer);
+         ExtractWord(ptr, lvlBuffer);
+         lvl = _tcstol(lvlBuffer, NULL, 0);
+
+         if(lvl != 0 && tagBuffer != NULL)
+            nxlog_set_debug_level_tag(tagBuffer, lvl);
+      }
+   }
+
+   free(s_debugTags);
+   free(tagList);
+
        nxlog_set_debug_level(s_debugLevel);
 
        if (_tcscmp(g_masterAgent, _T("not_set")))
@@ -1831,7 +1856,8 @@ int main(int argc, char *argv[])
 
                                if (g_config->parseTemplate(configSection, m_cfgTemplate))
                                {
-               DecryptPassword(_T("netxms"), g_szSharedSecret, g_szSharedSecret, MAX_SECRET_LENGTH);
+                                  _tprintf(_T("Taglist main: %s\n"), s_debugTags);
+                                  DecryptPassword(_T("netxms"), g_szSharedSecret, g_szSharedSecret, MAX_SECRET_LENGTH);
 
                // try to guess executable path
 #ifdef _WIN32
index 788ed9d..3ec37e4 100644 (file)
@@ -177,9 +177,12 @@ static void usage(bool showVersion)
 /**
  * Debug writer
  */
-static void DebugWriter(const TCHAR *msg)
+static void DebugWriter(const TCHAR *tag, const TCHAR *msg)
 {
-   _tprintf(_T("DBG: %s\n"), msg);
+   if (tag == NULL)      
+      _tprintf(_T("DBG: %s\n"), msg);
+   else
+      _tprintf(_T("DBG: <%s> %s\n"), tag, msg);
 }
 
 /**
index 8dec714..5956bcb 100644 (file)
@@ -68,7 +68,7 @@ static bool DBConnectionPoolPopulate()
       }
       else
       {
-         nxlog_debug(3, _T("Database Connection Pool: cannot create DB connection %d (%s)"), i, errorText);
+         nxlog_debug_tag(_T("db.connection.poll"), 3, _T("Database Connection Pool: cannot create DB connection %d (%s)"), i, errorText);
          delete conn;
       }
        }
@@ -114,12 +114,12 @@ static bool ResetConnection(PoolConnectionInfo *conn)
                conn->lastAccessTime = now;
                conn->usageCount = 0;
 
-               nxlog_debug(3, _T("Database Connection Pool: connection %p reconnected"), conn->handle);
+               nxlog_debug_tag(_T("db.connection.poll"), 3, _T("Database Connection Pool: connection %p reconnected"), conn->handle);
                return true;
        }
    else
    {
-               nxlog_debug(3, _T("Database Connection Pool: connection %p reconnect failure (%s)"), conn->handle, errorText);
+               nxlog_debug_tag(_T("db.connection.poll"), 3, _T("Database Connection Pool: connection %p reconnect failure (%s)"), conn->handle, errorText);
                return false;
        }
 }
@@ -191,7 +191,7 @@ static void ResetExpiredConnections()
  */
 static THREAD_RESULT THREAD_CALL MaintenanceThread(void *arg)
 {
-       nxlog_debug(1, _T("Database Connection Pool maintenance thread started"));
+       nxlog_debug_tag(_T("db.connection.poll"), 1, _T("Database Connection Pool maintenance thread started"));
 
    while(!ConditionWait(m_condShutdown, (m_connectionTTL > 0) ? m_connectionTTL * 750 : 300000))
    {
@@ -202,7 +202,7 @@ static THREAD_RESULT THREAD_CALL MaintenanceThread(void *arg)
       }
    }
 
-       nxlog_debug(1, _T("Database Connection Pool maintenance thread stopped"));
+       nxlog_debug_tag(_T("db.connection.poll"), 1, _T("Database Connection Pool maintenance thread stopped"));
    return THREAD_OK;
 }
 
@@ -246,7 +246,7 @@ bool LIBNXDB_EXPORTABLE DBConnectionPoolStartup(DB_DRIVER driver, const TCHAR *s
    m_maintThread = ThreadCreateEx(MaintenanceThread, 0, NULL);
 
    s_initialized = true;
-       nxlog_debug(1, _T("Database Connection Pool initialized"));
+       nxlog_debug_tag(_T("db.connection.poll"), 1, _T("Database Connection Pool initialized"));
 
        return true;
 }
@@ -274,7 +274,7 @@ void LIBNXDB_EXPORTABLE DBConnectionPoolShutdown()
    m_connections.clear();
 
    s_initialized = false;
-       nxlog_debug(1, _T("Database Connection Pool terminated"));
+       nxlog_debug_tag(_T("db.connection.poll"), 1, _T("Database Connection Pool terminated"));
 
 }
 
@@ -330,7 +330,7 @@ retry:
       }
       else
       {
-         nxlog_debug(3, _T("Database Connection Pool: cannot create additional DB connection (%s)"), errorText);
+         nxlog_debug_tag(_T("db.connection.poll"), 3, _T("Database Connection Pool: cannot create additional DB connection (%s)"), errorText);
          delete conn;
       }
        }
@@ -339,13 +339,13 @@ retry:
 
        if (handle == NULL)
        {
-       nxlog_debug(1, _T("Database Connection Pool exhausted (call from %hs:%d)"), srcFile, srcLine);
+       nxlog_debug_tag(_T("db.connection.poll"), 1, _T("Database Connection Pool exhausted (call from %hs:%d)"), srcFile, srcLine);
       ConditionWait(m_condRelease, 10000);
-      nxlog_debug(5, _T("Database Connection Pool: retry acquire connection (call from %hs:%d)"), srcFile, srcLine);
+      nxlog_debug_tag(_T("db.connection.poll"), 5, _T("Database Connection Pool: retry acquire connection (call from %hs:%d)"), srcFile, srcLine);
       goto retry;
        }
 
-   nxlog_debug(7, _T("Database Connection Pool: handle %p acquired (call from %hs:%d)"), handle, srcFile, srcLine);
+   nxlog_debug_tag(_T("db.connection.poll"), 7, _T("Database Connection Pool: handle %p acquired (call from %hs:%d)"), handle, srcFile, srcLine);
        return handle;
 }
 
@@ -371,7 +371,7 @@ void LIBNXDB_EXPORTABLE DBConnectionPoolReleaseConnection(DB_HANDLE handle)
 
        MutexUnlock(m_poolAccessMutex);
 
-   nxlog_debug(7, _T("Database Connection Pool: handle %p released"), handle);
+   nxlog_debug_tag(_T("db.connection.poll"), 7, _T("Database Connection Pool: handle %p released"), handle);
    ConditionPulse(m_condRelease);
 }
 
index d0692e7..1aa54f7 100644 (file)
@@ -43,7 +43,7 @@ void __DBWriteLog(WORD level, const TCHAR *format, ...)
 void LIBNXDB_EXPORTABLE DBSetLongRunningThreshold(UINT32 threshold)
 {
        g_sqlQueryExecTimeThreshold = threshold;
-   nxlog_debug(3, _T("DB Library: long running query threshold set to %u"), threshold);
+   nxlog_debug_tag(_T("db.query"), 3, _T("DB Library: long running query threshold set to %u"), threshold);
 }
 
 #ifdef _WIN32
index 6233e94..243edca 100644 (file)
@@ -66,7 +66,7 @@ DB_HANDLE LIBNXDB_EXPORTABLE DBConnect(DB_DRIVER driver, const TCHAR *server, co
    DBDRV_CONNECTION hDrvConn;
    DB_HANDLE hConn = NULL;
 
-       nxlog_debug(8, _T("DBConnect: server=%s db=%s login=%s schema=%s"), CHECK_NULL(server), CHECK_NULL(dbName), CHECK_NULL(login), CHECK_NULL(schema));
+       nxlog_debug_tag(_T("db.connect"), 8, _T("DBConnect: server=%s db=%s login=%s schema=%s"), CHECK_NULL(server), CHECK_NULL(dbName), CHECK_NULL(login), CHECK_NULL(schema));
 #ifdef UNICODE
        char *mbServer = (server == NULL) ? NULL : MBStringFromWideString(server);
        char *mbDatabase = (dbName == NULL) ? NULL : MBStringFromWideString(dbName);
@@ -108,7 +108,7 @@ DB_HANDLE LIBNXDB_EXPORTABLE DBConnect(DB_DRIVER driver, const TCHAR *server, co
 #endif
          if (driver->m_fpDrvSetPrefetchLimit != NULL)
             driver->m_fpDrvSetPrefetchLimit(hDrvConn, driver->m_defaultPrefetchLimit);
-                  nxlog_debug(4, _T("New DB connection opened: handle=%p"), hConn);
+                  nxlog_debug_tag(_T("db.connect"), 4, _T("New DB connection opened: handle=%p"), hConn);
          if (s_sessionInitCb != NULL)
             s_sessionInitCb(hConn);
       }
@@ -138,7 +138,7 @@ void LIBNXDB_EXPORTABLE DBDisconnect(DB_HANDLE hConn)
    if (hConn == NULL)
       return;
 
-   nxlog_debug(4, _T("DB connection %p closed"), hConn);
+   nxlog_debug_tag(_T("db.connect"), 4, _T("DB connection %p closed"), hConn);
    
    InvalidatePreparedStatements(hConn);
 
@@ -172,7 +172,7 @@ static void DBReconnect(DB_HANDLE hConn)
    int nCount;
        WCHAR errorText[DBDRV_MAX_ERROR_TEXT];
 
-   nxlog_debug(4, _T("DB reconnect: handle=%p"), hConn);
+   nxlog_debug_tag(_T("db.connection"), 4, _T("DB reconnect: handle=%p"), hConn);
 
    InvalidatePreparedStatements(hConn);
        hConn->m_driver->m_fpDrvDisconnect(hConn->m_connection);
@@ -264,11 +264,11 @@ bool LIBNXDB_EXPORTABLE DBQueryEx(DB_HANDLE hConn, const TCHAR *szQuery, TCHAR *
    ms = GetCurrentTimeMs() - ms;
    if (hConn->m_driver->m_dumpSql)
    {
-      nxlog_debug(9, _T("%s sync query: \"%s\" [%d ms]"), (dwResult == DBERR_SUCCESS) ? _T("Successful") : _T("Failed"), szQuery, ms);
+      nxlog_debug_tag(_T("db.query"), 9, _T("%s sync query: \"%s\" [%d ms]"), (dwResult == DBERR_SUCCESS) ? _T("Successful") : _T("Failed"), szQuery, ms);
    }
    if ((dwResult == DBERR_SUCCESS) && ((UINT32)ms > g_sqlQueryExecTimeThreshold))
    {
-      nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms);
       s_perfLongRunningQueries++;
    }
    
@@ -335,11 +335,11 @@ DB_RESULT LIBNXDB_EXPORTABLE DBSelectEx(DB_HANDLE hConn, const TCHAR *szQuery, T
    ms = GetCurrentTimeMs() - ms;
    if (hConn->m_driver->m_dumpSql)
    {
-      nxlog_debug(9, _T("%s sync query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 9, _T("%s sync query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (int)ms);
    }
    if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold))
    {
-      nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms);
       s_perfLongRunningQueries++;
    }
    MutexUnlock(hConn->m_mutexTransLock);
@@ -816,11 +816,11 @@ DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE DBSelectUnbufferedEx(DB_HANDLE hConn, co
    ms = GetCurrentTimeMs() - ms;
    if (hConn->m_driver->m_dumpSql)
    {
-      nxlog_debug(9, _T("%s unbuffered query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 9, _T("%s unbuffered query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (int)ms);
    }
    if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold))
    {
-      nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms);
       s_perfLongRunningQueries++;
    }
    if (hResult == NULL)
@@ -1163,7 +1163,7 @@ DB_STATEMENT LIBNXDB_EXPORTABLE DBPrepareEx(DB_HANDLE hConn, const TCHAR *query,
    if (hConn->m_driver->m_dumpSql)
    {
       ms = GetCurrentTimeMs() - ms;
-               nxlog_debug(9, _T("{%p} %s prepare: \"%s\" [%d ms]"), result, (result != NULL) ? _T("Successful") : _T("Failed"), query, ms);
+               nxlog_debug_tag(_T("db.query"), 9, _T("{%p} %s prepare: \"%s\" [%d ms]"), result, (result != NULL) ? _T("Successful") : _T("Failed"), query, ms);
        }
 
 #ifndef UNICODE
@@ -1245,11 +1245,11 @@ void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, int cTy
    {
                if (cType == DB_CTYPE_STRING)
                {
-                       nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt, pos, buffer);
+                       nxlog_debug_tag(_T("db.query"), 9, _T("{%p} bind at pos %d: \"%s\""), hStmt, pos, buffer);
                }
                else if (cType == DB_CTYPE_UTF8_STRING)
       {
-         nxlog_debug(9, _T("{%p} bind at pos %d (UTF-8): \"%hs\""), hStmt, pos, buffer);
+         nxlog_debug_tag(_T("db.query"), 9, _T("{%p} bind at pos %d (UTF-8): \"%hs\""), hStmt, pos, buffer);
       }
                else
                {
@@ -1272,7 +1272,7 @@ void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, int cTy
                                        _sntprintf(text, 64, _T("%f"), *((double *)buffer));
                                        break;
                        }
-                       nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt, pos, text);
+                       nxlog_debug_tag(_T("db.query"), 9, _T("{%p} bind at pos %d: \"%s\""), hStmt, pos, text);
                }
        }
 
@@ -1431,11 +1431,11 @@ bool LIBNXDB_EXPORTABLE DBExecuteEx(DB_STATEMENT hStmt, TCHAR *errorText)
    ms = GetCurrentTimeMs() - ms;
    if (hConn->m_driver->m_dumpSql)
    {
-      nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"), (dwResult == DBERR_SUCCESS) ? _T("Successful") : _T("Failed"), hStmt->m_query, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 9, _T("%s prepared sync query: \"%s\" [%d ms]"), (dwResult == DBERR_SUCCESS) ? _T("Successful") : _T("Failed"), hStmt->m_query, (int)ms);
    }
    if ((dwResult == DBERR_SUCCESS) && ((UINT32)ms > g_sqlQueryExecTimeThreshold))
    {
-      nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms);
       s_perfLongRunningQueries++;
    }
 
@@ -1514,12 +1514,12 @@ DB_RESULT LIBNXDB_EXPORTABLE DBSelectPreparedEx(DB_STATEMENT hStmt, TCHAR *error
    ms = GetCurrentTimeMs() - ms;
    if (hConn->m_driver->m_dumpSql)
    {
-      nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"),
+      nxlog_debug_tag(_T("db.query"), 9, _T("%s prepared sync query: \"%s\" [%d ms]"),
                              (hResult != NULL) ? _T("Successful") : _T("Failed"), hStmt->m_query, (int)ms);
    }
    if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold))
    {
-      nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms);
       s_perfLongRunningQueries++;
    }
 
@@ -1606,12 +1606,12 @@ DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE DBSelectPreparedUnbufferedEx(DB_STATEMEN
    ms = GetCurrentTimeMs() - ms;
    if (hConn->m_driver->m_dumpSql)
    {
-      nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"),
+      nxlog_debug_tag(_T("db.query"), 9, _T("%s prepared sync query: \"%s\" [%d ms]"),
                     (hResult != NULL) ? _T("Successful") : _T("Failed"), hStmt->m_query, (int)ms);
    }
    if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold))
    {
-      nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms);
+      nxlog_debug_tag(_T("db.query"), 3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms);
       s_perfLongRunningQueries++;
    }
 
@@ -1688,19 +1688,19 @@ bool LIBNXDB_EXPORTABLE DBBegin(DB_HANDLE hConn)
       {
          hConn->m_transactionLevel++;
          bRet = true;
-                       nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel);
+                       nxlog_debug_tag(_T("db.query"), 9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel);
       }
       else
       {
          MutexUnlock(hConn->m_mutexTransLock);
-                       nxlog_debug(9, _T("BEGIN TRANSACTION failed"), hConn->m_transactionLevel);
+                       nxlog_debug_tag(_T("db.query"), 9, _T("BEGIN TRANSACTION failed"), hConn->m_transactionLevel);
       }
    }
    else
    {
       hConn->m_transactionLevel++;
       bRet = true;
-               nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel);
+               nxlog_debug_tag(_T("db.query"), 9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel);
    }
    return bRet;
 }
@@ -1720,7 +1720,7 @@ bool LIBNXDB_EXPORTABLE DBCommit(DB_HANDLE hConn)
          bRet = (hConn->m_driver->m_fpDrvCommit(hConn->m_connection) == DBERR_SUCCESS);
       else
          bRet = true;
-               nxlog_debug(9, _T("COMMIT TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel);
+               nxlog_debug_tag(_T("db.query"), 9, _T("COMMIT TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel);
       MutexUnlock(hConn->m_mutexTransLock);
    }
    MutexUnlock(hConn->m_mutexTransLock);
@@ -1742,7 +1742,7 @@ bool LIBNXDB_EXPORTABLE DBRollback(DB_HANDLE hConn)
          bRet = (hConn->m_driver->m_fpDrvRollback(hConn->m_connection) == DBERR_SUCCESS);
       else
          bRet = true;
-               nxlog_debug(9, _T("ROLLBACK TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel);
+               nxlog_debug_tag(_T("db.query"), 9, _T("ROLLBACK TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel);
       MutexUnlock(hConn->m_mutexTransLock);
    }
    MutexUnlock(hConn->m_mutexTransLock);
index cd89143..81acf9e 100644 (file)
@@ -1,5 +1,5 @@
 SOURCES = array.cpp base64.cpp bytestream.cpp cc_mb.cpp cc_ucs2.cpp \
-          cc_ucs4.cpp cc_utf8.cpp cch.cpp config.cpp crypto.cpp diff.cpp \
+          cc_ucs4.cpp cc_utf8.cpp cch.cpp config.cpp crypto.cpp debug_tag_tree.cpp diff.cpp \
          dirw_unix.c geolocation.cpp getopt.c dload.cpp hash.cpp \
          hashmapbase.cpp ice.c icmp.cpp icmp6.cpp iconv.cpp inet_pton.c \
          inetaddr.cpp log.cpp lz4.c main.cpp macaddr.cpp md5.cpp message.cpp \
index 92619fc..f1c9f84 100644 (file)
@@ -845,7 +845,7 @@ bool Config::parseTemplate(const TCHAR *section, NX_CFG_TEMPLATE *cfgTemplate)
                   *curr = cfgTemplate[i].separator;
                   curr++;
                }
-               *curr = 0;
+               *--curr = 0;
                break;
             case CT_SIZE_BYTES:
                if ((cfgTemplate[i].overrideIndicator != NULL) &&
diff --git a/src/libnetxms/debug_tag_tree.cpp b/src/libnetxms/debug_tag_tree.cpp
new file mode 100644 (file)
index 0000000..d7bb833
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+** NetXMS - Network Management System
+** Utility Library
+** Copyright (C) 2003-2017 Raden Solutions
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published
+** by the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: debug_tag_tree.cpp
+**
+**/
+#include "debug_tag_tree.h"
+
+/**
+ * Create new tree node
+ */
+DebugTagTreeNode::DebugTagTreeNode(const TCHAR *value)
+{
+   m_value = new String(value);
+   m_direct = false;
+   m_directLvL = 0;
+   m_asterisk = false;
+   m_asteriskLvL = 0;
+   m_children = new StringObjectMap<DebugTagTreeNode>(true);
+}
+
+/**
+ * Get debug LvL from tree node, returns longest match (recursive)
+ */
+int DebugTagTreeNode::getDebugLvl(const StringList *tags, UINT32 pos)
+{
+   if ((tags->size() == pos) && m_direct)
+      return m_directLvL;
+
+   int result = -1;
+   DebugTagTreeNode *child = m_children->get(tags->get(pos));
+   if (child != NULL)
+      result = child->getDebugLvl(tags, pos+1);
+
+   if (result == -1 && tags->size() > pos && m_asterisk)
+      return m_asteriskLvL;
+
+   return result;
+}
+
+/**
+ * Add new tree node to its children and grand children etc... (recursive)
+ */
+void DebugTagTreeNode::add(const StringList *tags, UINT32 pos, UINT32 lvl)
+{
+   if (tags->size() == pos)
+   {
+      if (!m_direct)
+         m_direct = true;
+      m_directLvL = lvl;
+
+      return;
+   }
+
+   DebugTagTreeNode *child = m_children->get(tags->get(pos));
+   if (child != NULL)
+      child->add(tags, pos+1, lvl);
+   else
+   {
+      if (tags->size() > pos && !_tcscmp(tags->get(pos), _T("*")))
+      {
+         if (!m_asterisk)
+            m_asterisk = true;
+         m_asteriskLvL = lvl;
+      }
+      else
+      {
+         child = new DebugTagTreeNode(tags->get(pos));
+         m_children->set(tags->get(pos), child);
+         child->add(tags, pos+1, lvl);
+      }
+   }
+}
+
+/**
+ * Remove entry from child list (recursive)
+ */
+bool DebugTagTreeNode::remove(const StringList *tags, UINT32 pos)
+{
+   DebugTagTreeNode *child = m_children->get(tags->get(pos));
+   if (child != NULL && child->remove(tags, pos+1))
+      m_children->remove(tags->get(pos));
+
+   if ((tags->size() == pos+1) && (!_tcscmp(tags->get(pos), _T("*"))))
+   {
+      m_asterisk = false;
+      m_asteriskLvL = -1;
+   }
+   else if ((tags->size() == pos) && m_direct)
+   {
+      m_direct = false;
+      m_directLvL = -1;
+   }
+
+   if ((m_children->size() == 0) && !m_asterisk)
+      return true;
+
+   return false;
+}
+
+/**
+ * Get debug LvL from tree, returns longest match (recursive)
+ */
+int DebugTagTree::getDebugLvl(const TCHAR *tags)
+{
+   String s(tags);
+   StringList *tagList = s.split(_T("."));
+   if (tagList->size() == 0)
+      tagList->add(_T("*"));
+
+   int result = m_root->getDebugLvl(tagList, 0);
+
+   delete(tagList);
+   if (result == -1)
+      return 0;
+   return result;
+}
+
+/**
+ * Add new entry to the tree (recursive)
+ */
+void DebugTagTree::add(const TCHAR *tags, UINT32 lvl)
+{
+   String s(tags);
+   StringList *tagList = s.split(_T("."));
+   if (tagList->size() == 0)
+      tagList->add(_T("*"));
+
+   m_root->add(tagList, 0, lvl);
+
+   delete(tagList);
+}
+
+/**
+ * Remove entry from the tree
+ */
+void DebugTagTree::remove(const TCHAR *tags)
+{
+   String s(tags);
+   StringList *tagList = s.split(_T("."));
+   if (tagList->size() == 0)
+      tagList->add(_T("*"));
+
+   m_root->remove(tagList, 0);
+}
diff --git a/src/libnetxms/debug_tag_tree.h b/src/libnetxms/debug_tag_tree.h
new file mode 100644 (file)
index 0000000..d2ebbb5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+** NetXMS - Network Management System
+** Utility Library
+** Copyright (C) 2003-2017 Raden Solutions
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published
+** by the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: debug_tag_tree.h
+**
+**
+*/
+#include <nms_util.h>
+
+class DebugTagTreeNode
+{
+   friend class DebugTagTree;
+
+private:
+   String *m_value;
+   StringObjectMap<DebugTagTreeNode> *m_children;
+   bool m_direct;
+   bool m_asterisk;
+   int m_directLvL;
+   int m_asteriskLvL;
+
+   DebugTagTreeNode(const TCHAR *value);
+
+   int getDebugLvl(const StringList *tags, UINT32 pos);
+   void add(const StringList *tags, UINT32 pos, UINT32 lvl);
+   bool remove(const StringList *tags, UINT32 pos);
+
+public:
+   ~DebugTagTreeNode() { delete(m_value); delete(m_children); }
+};
+
+class DebugTagTree
+{
+private:
+   DebugTagTreeNode *m_root;
+
+public:
+   DebugTagTree() { m_root = new DebugTagTreeNode(_T("")); }
+   ~DebugTagTree() { delete(m_root); }
+
+   void add(const TCHAR *tags, UINT32 lvl);
+   void remove(const TCHAR *tags);
+   int getDebugLvl(const TCHAR *tags);
+};
index d5618bd..f66304d 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "libnetxms.h"
 #include <nxstat.h>
+#include "debug_tag_tree.h"
 
 #if HAVE_SYSLOG_H
 #include <syslog.h>
@@ -45,8 +46,8 @@ static TCHAR m_logFileName[MAX_PATH] = _T("");
 static FILE *m_logFileHandle = NULL;
 static MUTEX m_mutexLogAccess = INVALID_MUTEX_HANDLE;
 static UINT32 s_flags = 0;
-static int s_debugLevel = 0;
 static DWORD s_debugMsg = 0;
+static DWORD s_debugMsgTag = 0;
 static DWORD s_genericMsg = 0;
 static int s_rotationMode = NXLOG_ROTATION_BY_SIZE;
 static UINT64 s_maxLogSize = 4096 * 1024;      // 4 MB
@@ -58,14 +59,34 @@ static String s_logBuffer;
 static THREAD s_writerThread = INVALID_THREAD_HANDLE;
 static CONDITION s_writerStopCondition = INVALID_CONDITION_HANDLE;
 static NxLogDebugWriter s_debugWriter = NULL;
+static DebugTagTree tagTree;
+static MUTEX m_mutexDebugTagTreeAccess = INVALID_MUTEX_HANDLE;
 
 /**
  * Set debug level
  */
 void LIBNETXMS_EXPORTABLE nxlog_set_debug_level(int level)
 {
+   MutexLock(m_mutexDebugTagTreeAccess);
    if ((level >= 0) && (level <= 9))
-      s_debugLevel = level;
+      tagTree.add(_T("*"), level);
+   MutexUnlock(m_mutexDebugTagTreeAccess);
+}
+
+/**
+ * Set debug level for tag
+ */
+void LIBNETXMS_EXPORTABLE nxlog_set_debug_level_tag(const TCHAR *tag, int level)
+{
+   if (tag != NULL)
+   {
+      MutexLock(m_mutexDebugTagTreeAccess);
+      if((level >= 0) && (level <= 9))
+         tagTree.add(tag, level);
+      else if (level < 0)
+         tagTree.remove(tag);
+      MutexUnlock(m_mutexDebugTagTreeAccess);
+   }
 }
 
 /**
@@ -73,7 +94,23 @@ void LIBNETXMS_EXPORTABLE nxlog_set_debug_level(int level)
  */
 int LIBNETXMS_EXPORTABLE nxlog_get_debug_level()
 {
-   return s_debugLevel;
+   int level;
+   MutexLock(m_mutexDebugTagTreeAccess);
+   level = tagTree.getDebugLvl(_T("*"));
+   MutexUnlock(m_mutexDebugTagTreeAccess);
+   return level;
+}
+
+/**
+ * Get current debug level for tag
+ */
+int LIBNETXMS_EXPORTABLE nxlog_get_debug_level_tag(const TCHAR *tag)
+{
+   int level;
+   MutexLock(m_mutexDebugTagTreeAccess);
+   level = tagTree.getDebugLvl(tag);
+   MutexUnlock(m_mutexDebugTagTreeAccess);
+   return level;
 }
 
 /**
@@ -352,7 +389,7 @@ static THREAD_RESULT THREAD_CALL BackgroundWriterThread(void *arg)
  */
 bool LIBNETXMS_EXPORTABLE nxlog_open(const TCHAR *logName, UINT32 flags,
                                      const TCHAR *msgModule, unsigned int msgCount, const TCHAR **messages,
-                                     DWORD debugMsg, DWORD genericMsg)
+                                     DWORD debugMsg, DWORD debugMsgTag, DWORD genericMsg)
 {
        s_flags = flags & 0x7FFFFFFF;
 #ifdef _WIN32
@@ -362,6 +399,7 @@ bool LIBNETXMS_EXPORTABLE nxlog_open(const TCHAR *logName, UINT32 flags,
        m_messages = messages;
 #endif
        s_debugMsg = debugMsg;
+   s_debugMsgTag = debugMsgTag;
        s_genericMsg = genericMsg;
 
    if (s_flags & NXLOG_USE_SYSLOG)
@@ -412,6 +450,7 @@ bool LIBNETXMS_EXPORTABLE nxlog_open(const TCHAR *logName, UINT32 flags,
       }
 
       m_mutexLogAccess = MutexCreate();
+      m_mutexDebugTagTreeAccess = MutexCreate();
                SetDayStart();
    }
        return (s_flags & NXLOG_IS_OPEN) ? true : false;
@@ -444,6 +483,8 @@ void LIBNETXMS_EXPORTABLE nxlog_close()
             fclose(m_logFileHandle);
          if (m_mutexLogAccess != INVALID_MUTEX_HANDLE)
             MutexDestroy(m_mutexLogAccess);
+         if (m_mutexDebugTagTreeAccess != INVALID_MUTEX_HANDLE)
+            MutexDestroy(m_mutexDebugTagTreeAccess);
       }
           s_flags &= ~NXLOG_IS_OPEN;
    }
@@ -817,7 +858,7 @@ void LIBNETXMS_EXPORTABLE nxlog_write_generic(WORD type, const TCHAR *format, ..
  */
 void LIBNETXMS_EXPORTABLE nxlog_debug(int level, const TCHAR *format, ...)
 {
-   if (level > s_debugLevel)
+   if (level > nxlog_get_debug_level_tag(_T("*")))
       return;
 
    va_list args;
@@ -828,7 +869,7 @@ void LIBNETXMS_EXPORTABLE nxlog_debug(int level, const TCHAR *format, ...)
    nxlog_write(s_debugMsg, NXLOG_DEBUG, "s", buffer);
 
    if (s_debugWriter != NULL)
-      s_debugWriter(buffer);
+      s_debugWriter(NULL, buffer);
 }
 
 /**
@@ -836,7 +877,7 @@ void LIBNETXMS_EXPORTABLE nxlog_debug(int level, const TCHAR *format, ...)
  */
 void LIBNETXMS_EXPORTABLE nxlog_debug2(int level, const TCHAR *format, va_list args)
 {
-   if (level > s_debugLevel)
+   if (level > nxlog_get_debug_level_tag(_T("*")))
       return;
 
    TCHAR buffer[8192];
@@ -844,5 +885,24 @@ void LIBNETXMS_EXPORTABLE nxlog_debug2(int level, const TCHAR *format, va_list a
    nxlog_write(s_debugMsg, NXLOG_DEBUG, "s", buffer);
 
    if (s_debugWriter != NULL)
-      s_debugWriter(buffer);
+      s_debugWriter(NULL, buffer);
+}
+
+/**
+ * Write debug message with tag
+ */
+void LIBNETXMS_EXPORTABLE nxlog_debug_tag(const TCHAR *tag, int level, const TCHAR *format, ...)
+{
+   if (level > nxlog_get_debug_level_tag(tag))
+      return;
+
+   va_list args;
+   va_start(args, format);
+   TCHAR buffer[8192];
+   _vsntprintf(buffer, 8192, format, args);
+   va_end(args);
+   nxlog_write(s_debugMsgTag, NXLOG_DEBUG, "ss", tag, buffer);
+
+   if (s_debugWriter != NULL)
+      s_debugWriter(tag, buffer);
 }
index 216d690..edc54ff 100644 (file)
@@ -52,6 +52,11 @@ TCHAR g_szDbSchema[MAX_DB_NAME] = _T("");
 static UINT32 s_debugLevel = (UINT32)NXCONFIG_UNINITIALIZED_VALUE;
 
 /**
+ * Debug tags from config
+ */
+static TCHAR *s_debugTags = NULL;
+
+/**
  * Peer node information
  */
 static TCHAR s_peerNode[MAX_DB_STRING];
@@ -75,6 +80,7 @@ static NX_CFG_TEMPLATE m_cfgTemplate[] =
    { _T("DBSchema"), CT_STRING, 0, 0, MAX_DB_NAME, 0, g_szDbSchema, NULL },
    { _T("DBServer"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDbServer, NULL },
    { _T("DebugLevel"), CT_LONG, 0, 0, 0, 0, &s_debugLevel, &s_debugLevel },
+   { _T("DebugTags"), CT_STRING_LIST, ',', 0, 0, 0, &s_debugTags, NULL },
    { _T("DumpDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDumpDir, NULL },
    { _T("EnableServerConsole"), CT_BOOLEAN64, 0, 0, AF_ENABLE_LOCAL_CONSOLE, 0, &g_flags, NULL },
    { _T("FullCrashDumps"), CT_BOOLEAN64, 0, 0, AF_WRITE_FULL_DUMP, 0, &g_flags, NULL },
@@ -172,6 +178,27 @@ stop_search:
        if (*debugLevel == NXCONFIG_UNINITIALIZED_VALUE)
           *debugLevel = (int)s_debugLevel;
 
+   int numTags = 0, lvl = 0;
+   TCHAR tagBuffer[254], lvlBuffer[2];
+   TCHAR const *ptr;
+
+   TCHAR **tagList = SplitString(s_debugTags, _T(','), &numTags);
+   if (tagList != NULL)
+   {
+      for(int i = 0; i < numTags; i++)
+      {
+         ptr = ExtractWord(tagList[i], tagBuffer);
+         ExtractWord(ptr, lvlBuffer);
+         lvl = _tcstol(lvlBuffer, NULL, 0);
+
+         if(lvl != 0 && tagBuffer != NULL)
+            nxlog_set_debug_level_tag(tagBuffer, lvl);
+      }
+   }
+
+   free(s_debugTags);
+   free(tagList);
+
        // Decrypt password
    DecryptPassword(g_szDbLogin, g_szDbPassword, g_szDbPassword, MAX_PASSWORD);
 
index 4b52776..aaea979 100644 (file)
@@ -121,12 +121,20 @@ int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
    }
    else if (IsCommand(_T("DEBUG"), szBuffer, 2))
    {
-      // Get argument
-      ExtractWord(pArg, szBuffer);
-      int level = (int)_tcstol(szBuffer, &eptr, 0);
+      StringList *list = ParseCommandLine(pArg);
+
+      int level;
+      if (list->size() == 1)
+         level = (int)_tcstol(list->get(0), &eptr, 0);
+      else if (list->size() == 2)
+         level = (int)_tcstol(list->get(1), &eptr, 0);
+
       if ((*eptr == 0) && (level >= 0) && (level <= 9))
       {
-         nxlog_set_debug_level(level);
+         if (list->size() == 1)
+            nxlog_set_debug_level(level);
+         else if (list->size() == 2)
+            nxlog_set_debug_level_tag(list->get(1), level);
          ConsolePrintf(pCtx, (level == 0) ? _T("Debug mode turned off\n") : _T("Debug level set to %d\n"), level);
       }
       else if (IsCommand(_T("OFF"), szBuffer, 2))
@@ -141,6 +149,7 @@ int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
          else
             ConsoleWrite(pCtx, _T("ERROR: Invalid debug level\n\n"));
       }
+      delete(list);
    }
    else if (IsCommand(_T("DOWN"), szBuffer, 4))
    {
index efd6b83..37e1d71 100644 (file)
@@ -640,9 +640,9 @@ BOOL NXCORE_EXPORTABLE Initialize()
                    ((g_flags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
                    _T("LIBNXSRV.DLL"),
 #ifdef _WIN32
-                                      0, NULL, MSG_DEBUG, MSG_OTHER))
+                                      0, NULL, MSG_DEBUG, MSG_DEBUG_TAG, MSG_OTHER))
 #else
-                                      g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_OTHER))
+                                      g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_DEBUG_TAG, MSG_OTHER))
 #endif
    {
                _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
index ad80d7f..b9cb97b 100644 (file)
@@ -1076,4 +1076,10 @@ Language=English
 Failed to load sensor object with id %1 from database
 .
 
+MessageId=
+SymbolicName=MSG_DEBUG_TAG
+Language=English
+<%1> %2
+.
+
 ;#endif
index 7285811..8829b80 100644 (file)
@@ -44,6 +44,7 @@ BOOL g_bCheckDB = FALSE;
  * Debug level
  */
 static int s_debugLevel = NXCONFIG_UNINITIALIZED_VALUE;
+static TCHAR *s_debugTags = NULL;
 
 /**
  * Help text
@@ -359,6 +360,7 @@ int main(int argc, char* argv[])
    if (s_debugLevel == NXCONFIG_UNINITIALIZED_VALUE)
       s_debugLevel = 0;
    nxlog_set_debug_level(s_debugLevel);
+   free(s_debugTags);
 
        // Set exception handler
 #ifdef _WIN32
index 755cc21..028f2fd 100644 (file)
@@ -49,9 +49,12 @@ enum Operation
 /**
  * Debug writer
  */
-static void DebugWriter(const TCHAR *text)
+static void DebugWriter(const TCHAR *tag, const TCHAR *text)
 {
-   _tprintf(_T("%s\n"), text);
+   if (tag == NULL)      
+      _tprintf(_T("%s\n"), tag);
+   else
+      _tprintf(_T("<%s> %s\n"), tag, text);
 }
 
 /**
index 05481f0..0f8aeb6 100644 (file)
@@ -5,12 +5,12 @@
                        <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.746329184" moduleId="org.eclipse.cdt.core.settings" name="Default">
                                <externalSettings/>
                                <extensions>
+                                       <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
                                        <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
                                        <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
                                        <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
                                        <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
                                        <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
                                </extensions>
                        </storageModule>
                        <storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -25,6 +25,7 @@
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}&quot;"/>
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/include&quot;"/>
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/tests/include&quot;"/>
+                                                                       <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/src/server/include&quot;"/>
                                                                </option>
                                                                <option id="gnu.cpp.compiler.option.preprocessor.def.1860311775" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
                                                                        <listOptionValue builtIn="false" value="_THREAD_SAFE"/>
@@ -39,6 +40,7 @@
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}&quot;"/>
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/include&quot;"/>
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/tests/include&quot;"/>
+                                                                       <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/src/server/include&quot;"/>
                                                                </option>
                                                                <option id="gnu.c.compiler.option.preprocessor.def.symbols.710525206" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
                                                                        <listOptionValue builtIn="false" value="_THREAD_SAFE"/>
@@ -60,6 +62,7 @@
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}&quot;"/>
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/include&quot;"/>
                                                                        <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/tests/include&quot;"/>
+                                                                       <listOptionValue builtIn="false" value="&quot;${NETXMS_BASE}/src/server/include&quot;"/>
                                                                </option>
                                                                <inputType id="cdt.managedbuild.tool.gnu.assembler.input.360348570" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
                                                        </tool>
@@ -83,4 +86,5 @@
                        <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
                </scannerConfigBuildInfo>
        </storageModule>
+       <storageModule moduleId="refreshScope"/>
 </cproject>
index 70c9103..c0482da 100644 (file)
@@ -973,6 +973,146 @@ static void TestRingBuffer()
    EndTest();
 }
 
+static void TestDebugTags()
+{
+   StartTest(_T("Default debug level"));
+   AssertEquals(nxlog_get_debug_level(), 0);
+   AssertEquals(nxlog_get_debug_level_tag(_T("server.db")), 0);
+   EndTest();
+
+   StartTest(_T("Debug Tags"));
+   nxlog_set_debug_level_tag(_T("*"), 1);
+   nxlog_set_debug_level_tag(_T("db"), 2);
+   nxlog_set_debug_level_tag(_T("db.*"), 3);
+   nxlog_set_debug_level_tag(_T("db.local"), 4);
+   nxlog_set_debug_level_tag(_T("db.local.*"), 5);
+   nxlog_set_debug_level_tag(_T("db.local.sql"), 6);
+   nxlog_set_debug_level_tag(_T("db.local.sql.*"), 7);
+   nxlog_set_debug_level_tag(_T("db.local.sql.testing"), 8);
+   nxlog_set_debug_level_tag(_T("db.local.sql.testing.*"), 9);
+   nxlog_set_debug_level_tag(_T("server.objects.lock"), 9);
+
+   AssertEquals(nxlog_get_debug_level_tag(_T("server.objects.db")), 1);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("node")) == 1);
+   AssertTrue(nxlog_get_debug_level_tag(_T("node.status")) == 1);
+   AssertTrue(nxlog_get_debug_level_tag(_T("node.status.test")) == 1);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db")) == 2);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.status")) == 3);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.status.test")) == 3);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local")) == 4);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.server")) == 5);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.server.test")) == 5);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql")) == 6);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.server")) == 7);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.server.status")) == 7);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing")) == 8);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing.server")) == 9);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing.server.status")) == 9);
+   EndTest();
+
+   StartTest(_T("Debug Tags: change debug level"));
+   nxlog_set_debug_level_tag(_T("*"), 9);
+   nxlog_set_debug_level_tag(_T("db"), 8);
+   nxlog_set_debug_level_tag(_T("db.*"), 7);
+   nxlog_set_debug_level_tag(_T("db.local"), 6);
+   nxlog_set_debug_level_tag(_T("db.local.*"), 5);
+   nxlog_set_debug_level_tag(_T("db.local.sql"), 4);
+   nxlog_set_debug_level_tag(_T("db.local.sql.*"), 3);
+   nxlog_set_debug_level_tag(_T("db.local.sql.testing"), 2);
+   nxlog_set_debug_level_tag(_T("db.local.sql.testing.*"), 1);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("node")) == 9);
+   AssertTrue(nxlog_get_debug_level_tag(_T("node.status")) == 9);
+   AssertTrue(nxlog_get_debug_level_tag(_T("node.status.test")) == 9);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db")) == 8);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.status")) == 7);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.status.test")) == 7);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local")) == 6);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.server")) == 5);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.server.test")) == 5);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql")) == 4);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.server")) == 3);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.server.status")) == 3);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing")) == 2);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing.server")) == 1);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing.server.status")) == 1);
+   EndTest();
+
+   StartTest(_T("Debug Tags: remove"));
+   nxlog_set_debug_level_tag(_T("db.test.remove.*"), 4);
+   nxlog_set_debug_level_tag(_T("db.test.remove.child.tag"), 3);
+   nxlog_set_debug_level_tag(_T("db.local.child"), 2);
+   nxlog_set_debug_level_tag(_T("db.local.child.*"), 5);
+
+   nxlog_set_debug_level_tag(_T("*"), -1);
+   nxlog_set_debug_level_tag(_T("db"), -1);
+   nxlog_set_debug_level_tag(_T("db.*"), -1);
+   nxlog_set_debug_level_tag(_T("db.local"), -1);
+   nxlog_set_debug_level_tag(_T("db.local.*"), -1);
+   nxlog_set_debug_level_tag(_T("db.local.sql"), -1);
+   nxlog_set_debug_level_tag(_T("db.local.sql.*"), -1);;
+
+   nxlog_set_debug_level_tag(_T("*"), 9);
+   nxlog_set_debug_level_tag(_T("server"), 8);
+   nxlog_set_debug_level_tag(_T("server.*"), 7);
+   nxlog_set_debug_level_tag(_T("server.node"), 6);
+   nxlog_set_debug_level_tag(_T("server.node.*"), 5);
+   nxlog_set_debug_level_tag(_T("server.node.status"), 4);
+   nxlog_set_debug_level_tag(_T("server.node.status.*"), 3);
+   nxlog_set_debug_level_tag(_T("server.node.status.poll"), 2);
+   nxlog_set_debug_level_tag(_T("server.node.status.poll.*"), 1);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("node")) == 9);
+   AssertTrue(nxlog_get_debug_level_tag(_T("node.status")) == 9);
+   AssertTrue(nxlog_get_debug_level_tag(_T("node.status.test")) == 9);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("server")) == 8);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.object")) == 7);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.object.add")) == 7);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node")) == 6);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.add")) == 5);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.add.new")) == 5);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.status")) == 4);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.status.interface")) == 3);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.status.interface.state")) == 3);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.status.poll")) == 2);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.status.poll.time")) == 1);
+   AssertTrue(nxlog_get_debug_level_tag(_T("server.node.status.poll.time.ms")) == 1);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing")) == 2);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing.server")) == 1);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.sql.testing.server.status")) == 1);
+
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.test.remove.something")) == 4);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.test.remove.child.tag")) == 3);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.child")) == 2);
+   AssertTrue(nxlog_get_debug_level_tag(_T("db.local.child.remove.something.else")) == 5);
+
+   AssertFalse(nxlog_get_debug_level_tag(_T("db")) == 8);
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.status")) == 7);
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.status.test")) == 7);
+
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.local")) == 6);
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.local.server")) == 5);
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.local.server.test")) == 5);
+
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.local.sql")) == 4);
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.local.sql.server")) == 3);
+   AssertFalse(nxlog_get_debug_level_tag(_T("db.local.sql.server.status")) == 3);
+   EndTest();
+}
 /**
  * main()
  */
@@ -1002,6 +1142,7 @@ int main(int argc, char *argv[])
    TestByteSwap();
    TestDiff();
    TestRingBuffer();
+   TestDebugTags();
 
    MsgWaitQueue::shutdown();
    return 0;