Queue class can shrink buffer; cosmetic code refactoring
[public/netxms.git] / src / server / core / debug.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2012 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: debug.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 #ifdef _WIN32
26 #include <dbghelp.h>
27 #endif
28
29 /**
30 * Test read/write lock state and print to stdout
31 */
32 void DbgTestRWLock(RWLOCK hLock, const TCHAR *szName, CONSOLE_CTX console)
33 {
34 ConsolePrintf(console, _T(" %s: "), szName);
35 if (RWLockWriteLock(hLock, 100))
36 {
37 ConsolePrintf(console, _T("unlocked\n"));
38 RWLockUnlock(hLock);
39 }
40 else
41 {
42 if (RWLockReadLock(hLock, 100))
43 {
44 ConsolePrintf(console, _T("locked for reading\n"));
45 RWLockUnlock(hLock);
46 }
47 else
48 {
49 ConsolePrintf(console, _T("locked for writing\n"));
50 }
51 }
52 }
53
54 /**
55 * Print message to console, either local or remote
56 */
57 void ConsolePrintf(CONSOLE_CTX console, const TCHAR *pszFormat, ...)
58 {
59 va_list args;
60 TCHAR szBuffer[8192];
61
62 va_start(args, pszFormat);
63 _vsntprintf(szBuffer, 8191, pszFormat, args);
64 szBuffer[8191] = 0;
65 va_end(args);
66
67 if ((console->hSocket == -1) && (console->session == NULL) && (console->output == NULL))
68 {
69 WriteToTerminal(szBuffer);
70 }
71 else if (console->output != NULL)
72 {
73 // remove possible escape sequences
74 for(int i = 0; szBuffer[i] != 0; i++)
75 {
76 if (szBuffer[i] == 27)
77 {
78 int start = i++;
79 if (szBuffer[i] == '[')
80 {
81 for(i++; (szBuffer[i] != 0) && (szBuffer[i] != 'm'); i++);
82 if (szBuffer[i] == 'm')
83 i++;
84 }
85 memmove(&szBuffer[start], &szBuffer[i], (_tcslen(&szBuffer[i]) + 1) * sizeof(TCHAR));
86 i = start - 1;
87 }
88 }
89
90 MutexLock(console->socketMutex);
91 *console->output += szBuffer;
92 MutexUnlock(console->socketMutex);
93 }
94 else
95 {
96 console->pMsg->setField(VID_MESSAGE, szBuffer);
97 if (console->session != NULL)
98 {
99 console->session->postMessage(console->pMsg);
100 }
101 else
102 {
103 NXCP_MESSAGE *pRawMsg = console->pMsg->createMessage();
104 SendEx(console->hSocket, pRawMsg, ntohl(pRawMsg->size), 0, console->socketMutex);
105 free(pRawMsg);
106 }
107 }
108 }
109
110 /**
111 * Show server statistics
112 */
113 static void DciCountCallback(NetObj *object, void *data)
114 {
115 *((int *)data) += (int)((Node *)object)->getItemCount();
116 }
117
118 void ShowServerStats(CONSOLE_CTX console)
119 {
120 int dciCount = 0;
121 g_idxNodeById.forEach(DciCountCallback, &dciCount);
122 ConsolePrintf(console, _T("Total number of objects: %d\n")
123 _T("Number of monitored nodes: %d\n")
124 _T("Number of collectable DCIs: %d\n\n"),
125 g_idxObjectById.size(), g_idxNodeById.size(), dciCount);
126 }
127
128 /**
129 * Show queue stats
130 */
131 void ShowQueueStats(CONSOLE_CTX console, Queue *pQueue, const TCHAR *pszName)
132 {
133 if (pQueue != NULL)
134 ConsolePrintf(console, _T("%-32s : %d\n"), pszName, pQueue->size());
135 }
136
137 /**
138 * Show thread pool stats
139 */
140 void ShowThreadPool(CONSOLE_CTX console, ThreadPool *p)
141 {
142 ThreadPoolInfo info;
143 ThreadPoolGetInfo(p, &info);
144 ConsolePrintf(console, _T("\x1b[1m%s\x1b[0m\n")
145 _T(" Threads: %d (%d/%d)\n")
146 _T(" Load: %d%%\n")
147 _T(" Usage: %d%%\n")
148 _T(" Requests: %d\n\n"),
149 info.name, info.curThreads, info.minThreads, info.maxThreads, info.load, info.usage, info.activeRequests);
150 }
151
152 /**
153 * Write process coredump
154 */
155 #ifdef _WIN32
156
157 void DumpProcess(CONSOLE_CTX console)
158 {
159 STARTUPINFOA si;
160 PROCESS_INFORMATION pi;
161 char cmdLine[64];
162
163 ConsolePrintf(console, _T("Dumping process to disk...\n"));
164
165 sprintf(cmdLine, "netxmsd.exe --dump %d", GetCurrentProcessId());
166 memset(&si, 0, sizeof(STARTUPINFO));
167 si.cb = sizeof(STARTUPINFO);
168 if (CreateProcessA(NULL, cmdLine, NULL, NULL, FALSE,
169 (g_flags & AF_DAEMON) ? CREATE_NO_WINDOW : 0, NULL, NULL, &si, &pi))
170 {
171 WaitForSingleObject(pi.hProcess, INFINITE);
172 CloseHandle(pi.hThread);
173 CloseHandle(pi.hProcess);
174
175 ConsolePrintf(console, _T("Done.\n"));
176 }
177 else
178 {
179 TCHAR buffer[256];
180 ConsolePrintf(console, _T("Dump error: CreateProcess() failed (%s)\n"), GetSystemErrorText(GetLastError(), buffer, 256));
181 }
182 }
183
184 #else
185
186 void DumpProcess(CONSOLE_CTX console)
187 {
188 ConsolePrintf(console, _T("DUMP command is not supported for current operating system\n"));
189 }
190
191 #endif