2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
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.
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.
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.
28 * Max syslog message length
30 #define MAX_SYSLOG_MSG_LEN 1024
33 * Queued syslog message structure
35 class QueuedSyslogMessage
38 InetAddress sourceAddr
;
42 QueuedSyslogMessage(const InetAddress
& addr
, char *msg
, int msgLen
) : sourceAddr(addr
)
44 message
= (char *)nx_memdup(msg
, msgLen
+ 1);
45 messageLength
= msgLen
;
48 ~QueuedSyslogMessage()
57 Queue
g_syslogProcessingQueue(1000, 100);
58 Queue
g_syslogWriteQueue(1000, 100);
61 * Total number of received syslog messages
63 UINT64 g_syslogMessagesReceived
= 0;
66 * Node matching policy
68 enum NodeMatchingPolicy
70 SOURCE_IP_THEN_HOSTNAME
= 0,
71 HOSTNAME_THEN_SOURCE_IP
= 1
77 static UINT64 s_msgId
= 1;
78 static LogParser
*s_parser
= NULL
;
79 static MUTEX s_parserLock
= INVALID_MUTEX_HANDLE
;
80 static NodeMatchingPolicy s_nodeMatchingPolicy
= SOURCE_IP_THEN_HOSTNAME
;
81 static THREAD s_receiverThread
= INVALID_THREAD_HANDLE
;
82 static bool s_running
= true;
83 static bool s_alwaysUseServerTime
= false;
86 * Parse timestamp field
88 static BOOL
ParseTimeStamp(char **ppStart
, int nMsgSize
, int *pnPos
, time_t *ptmTime
)
90 static char psMonth
[12][5] = { "Jan ", "Feb ", "Mar ", "Apr ",
91 "May ", "Jun ", "Jul ", "Aug ",
92 "Sep ", "Oct ", "Nov ", "Dec " };
95 char szBuffer
[16], *pCurr
= *ppStart
;
98 if (nMsgSize
- *pnPos
< 16)
99 return FALSE
; // Timestamp cannot be shorter than 16 bytes
101 // Prepare local time structure
103 memcpy(×tamp
, localtime(&t
), sizeof(struct tm
));
106 for(i
= 0; i
< 12; i
++)
107 if (!memcmp(pCurr
, psMonth
[i
], 4))
109 timestamp
.tm_mon
= i
;
119 timestamp
.tm_mday
= *pCurr
- '0';
124 return FALSE
; // Invalid day of month
125 timestamp
.tm_mday
= 0;
130 timestamp
.tm_mday
= timestamp
.tm_mday
* 10 + (*pCurr
- '0');
134 return FALSE
; // Invalid day of month
142 memcpy(szBuffer
, pCurr
, 8);
144 if (sscanf(szBuffer
, "%02d:%02d:%02d", ×tamp
.tm_hour
,
145 ×tamp
.tm_min
, ×tamp
.tm_sec
) != 3)
146 return FALSE
; // Invalid time format
149 // Check for Cisco variant - HH:MM:SS.nnn
162 return FALSE
; // Space should follow timestamp
165 // Convert to system time
166 *ptmTime
= mktime(×tamp
);
167 if (*ptmTime
== ((time_t)-1))
170 // Adjust current position
171 *pnPos
+= (int)(pCurr
- *ppStart
);
177 * Parse syslog message
179 static BOOL
ParseSyslogMessage(char *psMsg
, int nMsgLen
, NX_SYSLOG_RECORD
*pRec
)
181 int i
, nLen
, nPos
= 0;
184 memset(pRec
, 0, sizeof(NX_SYSLOG_RECORD
));
189 int nPri
= 0, nCount
= 0;
191 for(pCurr
++, nPos
++; isdigit(*pCurr
) && (nPos
< nMsgLen
); pCurr
++, nPos
++, nCount
++)
192 nPri
= nPri
* 10 + (*pCurr
- '0');
194 return FALSE
; // Unexpected end of message
196 if ((*pCurr
== '>') && (nCount
> 0) && (nCount
<4))
198 pRec
->nFacility
= nPri
/ 8;
199 pRec
->nSeverity
= nPri
% 8;
205 return FALSE
; // Invalid message
210 // Set default PRI of 13
212 pRec
->nSeverity
= SYSLOG_SEVERITY_NOTICE
;
216 if (ParseTimeStamp(&pCurr
, nMsgLen
, &nPos
, &pRec
->tmTimeStamp
))
218 // Use server time if configured
219 // We still had to parse timestamp to get correct start position for MSG part
220 if (s_alwaysUseServerTime
)
222 pRec
->tmTimeStamp
= time(NULL
);
226 for(i
= 0; (*pCurr
>= 33) && (*pCurr
<= 126) && (i
< MAX_SYSLOG_HOSTNAME_LEN
- 1) && (nPos
< nMsgLen
); i
++, nPos
++, pCurr
++)
227 pRec
->szHostName
[i
] = *pCurr
;
228 if ((nPos
>= nMsgLen
) || (*pCurr
!= ' '))
230 // Not a valid hostname, assuming to be a part of message
233 pRec
->szHostName
[0] = 0;
243 pRec
->tmTimeStamp
= time(NULL
);
247 for(i
= 0; isalnum(*pCurr
) && (i
< MAX_SYSLOG_TAG_LEN
) && (nPos
< nMsgLen
); i
++, nPos
++, pCurr
++)
248 pRec
->szTag
[i
] = *pCurr
;
249 if ((i
== MAX_SYSLOG_TAG_LEN
) || (nPos
>= nMsgLen
))
251 // Too long tag, assuming that it's a part of message
256 nLen
= min(nMsgLen
- nPos
, MAX_LOG_MSG_LENGTH
);
257 memcpy(pRec
->szMessage
, pCurr
, nLen
);
263 * Find node by host name
265 static Node
*FindNodeByHostname(const char *hostName
)
267 if (hostName
[0] == 0)
271 InetAddress ipAddr
= InetAddress::resolveHostName(hostName
);
272 if (ipAddr
.isValidUnicast())
274 node
= FindNodeByIP((g_flags
& AF_TRAP_SOURCES_IN_ALL_ZONES
) ? ALL_ZONES
: 0, ipAddr
);
280 WCHAR wname
[MAX_OBJECT_NAME
];
281 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, hostName
, -1, wname
, MAX_OBJECT_NAME
);
282 wname
[MAX_OBJECT_NAME
- 1] = 0;
283 node
= (Node
*)FindObjectByName(wname
, OBJECT_NODE
);
285 node
= (Node
*)FindObjectByName(hostName
, OBJECT_NODE
);
292 * Bind syslog message to NetXMS node object
293 * sourceAddr is an IP address from which we receive message
295 static Node
*BindMsgToNode(NX_SYSLOG_RECORD
*pRec
, const InetAddress
& sourceAddr
)
299 if (s_nodeMatchingPolicy
== SOURCE_IP_THEN_HOSTNAME
)
301 node
= FindNodeByIP((g_flags
& AF_TRAP_SOURCES_IN_ALL_ZONES
) ? ALL_ZONES
: 0, sourceAddr
);
304 node
= FindNodeByHostname(pRec
->szHostName
);
309 node
= FindNodeByHostname(pRec
->szHostName
);
312 node
= FindNodeByIP((g_flags
& AF_TRAP_SOURCES_IN_ALL_ZONES
) ? ALL_ZONES
: 0, sourceAddr
);
318 node
->incSyslogMessageCount();
319 pRec
->dwSourceObject
= node
->getId();
320 if (pRec
->szHostName
[0] == 0)
323 WideCharToMultiByte(CP_ACP
, WC_DEFAULTCHAR
| WC_COMPOSITECHECK
, node
->getName(), -1, pRec
->szHostName
, MAX_SYSLOG_HOSTNAME_LEN
, NULL
, NULL
);
324 pRec
->szHostName
[MAX_SYSLOG_HOSTNAME_LEN
- 1] = 0;
326 nx_strncpy(pRec
->szHostName
, node
->getName(), MAX_SYSLOG_HOSTNAME_LEN
);
332 if (pRec
->szHostName
[0] == 0)
334 sourceAddr
.toStringA(pRec
->szHostName
);
342 * Handler for EnumerateSessions()
344 static void BroadcastSyslogMessage(ClientSession
*pSession
, void *pArg
)
346 if (pSession
->isAuthenticated())
347 pSession
->onSyslogMessage((NX_SYSLOG_RECORD
*)pArg
);
351 * Syslog writer thread
353 static THREAD_RESULT THREAD_CALL
SyslogWriterThread(void *arg
)
355 DbgPrintf(1, _T("Syslog writer thread started"));
358 NX_SYSLOG_RECORD
*r
= (NX_SYSLOG_RECORD
*)g_syslogWriteQueue
.getOrBlock();
359 if (r
== INVALID_POINTER_VALUE
)
362 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
364 DB_STATEMENT hStmt
= DBPrepare(hdb
, _T("INSERT INTO syslog (msg_id,msg_timestamp,facility,severity,source_object_id,hostname,msg_tag,msg_text) VALUES (?,?,?,?,?,?,?,?)"));
368 DBConnectionPoolReleaseConnection(hdb
);
376 DBBind(hStmt
, 1, DB_SQLTYPE_BIGINT
, r
->qwMsgId
);
377 DBBind(hStmt
, 2, DB_SQLTYPE_INTEGER
, (INT32
)r
->tmTimeStamp
);
378 DBBind(hStmt
, 3, DB_SQLTYPE_INTEGER
, r
->nFacility
);
379 DBBind(hStmt
, 4, DB_SQLTYPE_INTEGER
, r
->nSeverity
);
380 DBBind(hStmt
, 5, DB_SQLTYPE_INTEGER
, r
->dwSourceObject
);
382 DBBind(hStmt
, 6, DB_SQLTYPE_VARCHAR
, WideStringFromMBString(r
->szHostName
), DB_BIND_DYNAMIC
);
383 DBBind(hStmt
, 7, DB_SQLTYPE_VARCHAR
, WideStringFromMBString(r
->szTag
), DB_BIND_DYNAMIC
);
384 DBBind(hStmt
, 8, DB_SQLTYPE_VARCHAR
, WideStringFromMBString(r
->szMessage
), DB_BIND_DYNAMIC
);
386 DBBind(hStmt
, 6, DB_SQLTYPE_VARCHAR
, r
->szHostName
, DB_BIND_STATIC
);
387 DBBind(hStmt
, 7, DB_SQLTYPE_VARCHAR
, r
->szTag
, DB_BIND_STATIC
);
388 DBBind(hStmt
, 8, DB_SQLTYPE_VARCHAR
, r
->szMessage
, DB_BIND_STATIC
);
391 if (!DBExecute(hStmt
))
400 r
= (NX_SYSLOG_RECORD
*)g_syslogWriteQueue
.get();
401 if ((r
== NULL
) || (r
== INVALID_POINTER_VALUE
))
405 DBFreeStatement(hStmt
);
406 DBConnectionPoolReleaseConnection(hdb
);
407 if (r
== INVALID_POINTER_VALUE
)
410 DbgPrintf(1, _T("Syslog writer thread stopped"));
415 * Process syslog message
417 static void ProcessSyslogMessage(char *psMsg
, int nMsgLen
, const InetAddress
& sourceAddr
)
419 NX_SYSLOG_RECORD record
;
421 DbgPrintf(6, _T("ProcessSyslogMessage: Raw syslog message to process:\n%hs"), psMsg
);
422 if (ParseSyslogMessage(psMsg
, nMsgLen
, &record
))
424 g_syslogMessagesReceived
++;
426 record
.qwMsgId
= s_msgId
++;
427 Node
*node
= BindMsgToNode(&record
, sourceAddr
);
429 g_syslogWriteQueue
.put(nx_memdup(&record
, sizeof(NX_SYSLOG_RECORD
)));
431 // Send message to all connected clients
432 EnumerateClientSessions(BroadcastSyslogMessage
, &record
);
435 DbgPrintf(6, _T("Syslog message: ipAddr=%s objectId=%d tag=\"%hs\" msg=\"%hs\""),
436 sourceAddr
.toString(ipAddr
), record
.dwSourceObject
, record
.szTag
, record
.szMessage
);
438 MutexLock(s_parserLock
);
439 if ((record
.dwSourceObject
!= 0) && (s_parser
!= NULL
) &&
440 ((node
->getStatus() != STATUS_UNMANAGED
) || (g_flags
& AF_TRAPS_FROM_UNMANAGED_NODES
)))
443 WCHAR wtag
[MAX_SYSLOG_TAG_LEN
];
444 WCHAR wmsg
[MAX_LOG_MSG_LENGTH
];
445 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, record
.szTag
, -1, wtag
, MAX_SYSLOG_TAG_LEN
);
446 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, record
.szMessage
, -1, wmsg
, MAX_LOG_MSG_LENGTH
);
447 s_parser
->matchEvent(wtag
, record
.nFacility
, 1 << record
.nSeverity
, wmsg
, record
.dwSourceObject
);
449 s_parser
->matchEvent(record
.szTag
, record
.nFacility
, 1 << record
.nSeverity
, record
.szMessage
, record
.dwSourceObject
);
452 MutexUnlock(s_parserLock
);
456 DbgPrintf(6, _T("ProcessSyslogMessage: Cannot parse syslog message"));
461 * Syslog processing thread
463 static THREAD_RESULT THREAD_CALL
SyslogProcessingThread(void *pArg
)
465 QueuedSyslogMessage
*msg
;
469 msg
= (QueuedSyslogMessage
*)g_syslogProcessingQueue
.getOrBlock();
470 if (msg
== INVALID_POINTER_VALUE
)
473 ProcessSyslogMessage(msg
->message
, msg
->messageLength
, msg
->sourceAddr
);
480 * Queue syslog message for processing
482 static void QueueSyslogMessage(char *msg
, int msgLen
, const InetAddress
& sourceAddr
)
484 g_syslogProcessingQueue
.put(new QueuedSyslogMessage(sourceAddr
, msg
, msgLen
));
488 * Callback for syslog parser
490 static void SyslogParserCallback(UINT32 eventCode
, const TCHAR
*eventName
, const TCHAR
*line
,
491 const TCHAR
*source
, UINT32 facility
, UINT32 severity
,
492 int paramCount
, TCHAR
**params
, UINT32 objectId
, int repeatCount
,
495 char format
[] = "sssssssssssssssssssssssssssssssss";
497 TCHAR repeatCountText
[16];
499 int count
= min(paramCount
, 32);
500 format
[count
+ 1] = 0;
501 for(int i
= 0; i
< count
; i
++)
502 plist
[i
] = params
[i
];
503 _sntprintf(repeatCountText
, 16, _T("%d"), repeatCount
);
504 plist
[count
] = repeatCountText
;
505 PostEvent(eventCode
, objectId
, format
,
506 plist
[0], plist
[1], plist
[2], plist
[3],
507 plist
[4], plist
[5], plist
[6], plist
[7],
508 plist
[8], plist
[9], plist
[10], plist
[11],
509 plist
[12], plist
[13], plist
[14], plist
[15],
510 plist
[16], plist
[17], plist
[18], plist
[19],
511 plist
[20], plist
[21], plist
[22], plist
[23],
512 plist
[24], plist
[25], plist
[26], plist
[27],
513 plist
[28], plist
[29], plist
[30], plist
[31]);
517 * Event name resolver
519 static bool EventNameResolver(const TCHAR
*name
, UINT32
*code
)
521 bool success
= false;
522 EventTemplate
*event
= FindEventTemplateByName(name
);
525 *code
= event
->getCode();
526 event
->decRefCount();
533 * Create syslog parser from config
535 static void CreateParserFromConfig()
539 MutexLock(s_parserLock
);
540 delete_and_null(s_parser
);
542 WCHAR
*wxml
= ConfigReadCLOB(_T("SyslogParser"), _T("<parser></parser>"));
545 xml
= UTF8StringFromWideString(wxml
);
553 xml
= ConfigReadCLOB("SyslogParser", "<parser></parser>");
557 TCHAR parseError
[256];
558 ObjectArray
<LogParser
> *parsers
= LogParser::createFromXml(xml
, -1, parseError
, 256, EventNameResolver
);
559 if ((parsers
!= NULL
) && (parsers
->size() > 0))
561 s_parser
= parsers
->get(0);
562 s_parser
->setCallback(SyslogParserCallback
);
563 DbgPrintf(3, _T("syslogd: parser successfully created from config"));
567 nxlog_write(MSG_SYSLOG_PARSER_INIT_FAILED
, EVENTLOG_ERROR_TYPE
, "s", parseError
);
572 MutexUnlock(s_parserLock
);
576 * Syslog messages receiver thread
578 static THREAD_RESULT THREAD_CALL
SyslogReceiver(void *pArg
)
580 SOCKET hSocket
= socket(AF_INET
, SOCK_DGRAM
, 0);
582 SOCKET hSocket6
= socket(AF_INET6
, SOCK_DGRAM
, 0);
584 if ((hSocket
== INVALID_SOCKET
)
586 && (hSocket6
== INVALID_SOCKET
)
590 nxlog_write(MSG_SOCKET_FAILED
, EVENTLOG_ERROR_TYPE
, "s", _T("SyslogReceiver"));
594 SetSocketExclusiveAddrUse(hSocket
);
595 SetSocketReuseFlag(hSocket
);
597 fcntl(hSocket
, F_SETFD
, fcntl(hSocket
, F_GETFD
) | FD_CLOEXEC
);
601 SetSocketExclusiveAddrUse(hSocket6
);
602 SetSocketReuseFlag(hSocket6
);
604 fcntl(hSocket6
, F_SETFD
, fcntl(hSocket6
, F_GETFD
) | FD_CLOEXEC
);
608 setsockopt(hSocket6
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&on
, sizeof(int));
612 // Get listen port number
613 int port
= ConfigReadInt(_T("SyslogListenPort"), 514);
614 if ((port
< 1) || (port
> 65535))
616 DbgPrintf(2, _T("Syslog: invalid listen port number %d, using default"), port
);
620 // Fill in local address structure
621 struct sockaddr_in servAddr
;
622 memset(&servAddr
, 0, sizeof(struct sockaddr_in
));
623 servAddr
.sin_family
= AF_INET
;
626 struct sockaddr_in6 servAddr6
;
627 memset(&servAddr6
, 0, sizeof(struct sockaddr_in6
));
628 servAddr6
.sin6_family
= AF_INET6
;
631 if (!_tcscmp(g_szListenAddress
, _T("*")))
633 servAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
635 memset(servAddr6
.sin6_addr
.s6_addr
, 0, 16);
640 InetAddress bindAddress
= InetAddress::resolveHostName(g_szListenAddress
, AF_INET
);
641 if (bindAddress
.isValid() && (bindAddress
.getFamily() == AF_INET
))
643 servAddr
.sin_addr
.s_addr
= htonl(bindAddress
.getAddressV4());
647 servAddr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
650 bindAddress
= InetAddress::resolveHostName(g_szListenAddress
, AF_INET6
);
651 if (bindAddress
.isValid() && (bindAddress
.getFamily() == AF_INET6
))
653 memcpy(servAddr6
.sin6_addr
.s6_addr
, bindAddress
.getAddressV6(), 16);
657 memset(servAddr6
.sin6_addr
.s6_addr
, 0, 15);
658 servAddr6
.sin6_addr
.s6_addr
[15] = 1;
662 servAddr
.sin_port
= htons((UINT16
)port
);
664 servAddr6
.sin6_port
= htons((UINT16
)port
);
669 int bindFailures
= 0;
670 DbgPrintf(5, _T("Trying to bind on UDP %s:%d"), SockaddrToStr((struct sockaddr
*)&servAddr
, buffer
), ntohs(servAddr
.sin_port
));
671 if (bind(hSocket
, (struct sockaddr
*)&servAddr
, sizeof(struct sockaddr_in
)) != 0)
673 nxlog_write(MSG_BIND_ERROR
, EVENTLOG_ERROR_TYPE
, "dse", port
, _T("SyslogReceiver"), WSAGetLastError());
675 closesocket(hSocket
);
676 hSocket
= INVALID_SOCKET
;
680 DbgPrintf(5, _T("Trying to bind on UDP [%s]:%d"), SockaddrToStr((struct sockaddr
*)&servAddr6
, buffer
), ntohs(servAddr6
.sin6_port
));
681 if (bind(hSocket6
, (struct sockaddr
*)&servAddr6
, sizeof(struct sockaddr_in6
)) != 0)
683 nxlog_write(MSG_BIND_ERROR
, EVENTLOG_ERROR_TYPE
, "dse", port
, _T("SyslogReceiver"), WSAGetLastError());
685 closesocket(hSocket6
);
686 hSocket6
= INVALID_SOCKET
;
692 // Abort if cannot bind to at least one socket
693 if (bindFailures
== 2)
695 DbgPrintf(1, _T("Syslog receiver aborted - cannot bind at least one socket"));
699 if (hSocket
!= INVALID_SOCKET
)
700 nxlog_write(MSG_LISTENING_FOR_SYSLOG
, EVENTLOG_INFORMATION_TYPE
, "ad", ntohl(servAddr
.sin_addr
.s_addr
), port
);
702 if (hSocket6
!= INVALID_SOCKET
)
703 nxlog_write(MSG_LISTENING_FOR_SYSLOG
, EVENTLOG_INFORMATION_TYPE
, "Hd", servAddr6
.sin6_addr
.s6_addr
, port
);
706 SetLogParserTraceCallback(nxlog_debug2
);
707 InitLogParserLibrary();
709 // Create message parser
710 s_parserLock
= MutexCreate();
711 CreateParserFromConfig();
713 // Start processing thread
714 THREAD hProcessingThread
= ThreadCreateEx(SyslogProcessingThread
, 0, NULL
);
715 THREAD hWriterThread
= ThreadCreateEx(SyslogWriterThread
, 0, NULL
);
717 DbgPrintf(1, _T("Syslog receiver thread started"));
728 if (hSocket
!= INVALID_SOCKET
)
729 FD_SET(hSocket
, &rdfs
);
731 if (hSocket6
!= INVALID_SOCKET
)
732 FD_SET(hSocket6
, &rdfs
);
735 #if defined(WITH_IPV6) && !defined(_WIN32)
737 if (hSocket
!= INVALID_SOCKET
)
739 if ((hSocket6
!= INVALID_SOCKET
) && (hSocket6
> nfds
))
741 int rc
= select(SELECT_NFDS(nfds
+ 1), &rdfs
, NULL
, NULL
, &tv
);
743 int rc
= select(SELECT_NFDS(hSocket
+ 1), &rdfs
, NULL
, NULL
, &tv
);
747 char syslogMessage
[MAX_SYSLOG_MSG_LEN
+ 1];
749 socklen_t addrLen
= sizeof(SockAddrBuffer
);
751 SOCKET s
= FD_ISSET(hSocket
, &rdfs
) ? hSocket
: hSocket6
;
755 int bytes
= recvfrom(s
, syslogMessage
, MAX_SYSLOG_MSG_LEN
, 0, (struct sockaddr
*)&addr
, &addrLen
);
758 syslogMessage
[bytes
] = 0;
759 QueueSyslogMessage(syslogMessage
, bytes
, InetAddress::createFromSockaddr((struct sockaddr
*)&addr
));
774 // Stop processing thread
775 g_syslogProcessingQueue
.put(INVALID_POINTER_VALUE
);
776 ThreadJoin(hProcessingThread
);
778 // Stop writer thread - it must be done after processing thread already finished
779 g_syslogWriteQueue
.put(INVALID_POINTER_VALUE
);
780 ThreadJoin(hWriterThread
);
783 CleanupLogParserLibrary();
785 DbgPrintf(1, _T("Syslog receiver thread stopped"));
790 * Start built-in syslog server
792 void StartSyslogServer()
794 s_nodeMatchingPolicy
= (NodeMatchingPolicy
)ConfigReadInt(_T("SyslogNodeMatchingPolicy"), SOURCE_IP_THEN_HOSTNAME
);
795 s_alwaysUseServerTime
= ConfigReadInt(_T("SyslogIgnoreMessageTimestamp"), 0) ? true : false;
797 // Determine first available message id
798 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
799 DB_RESULT hResult
= DBSelect(hdb
, _T("SELECT max(msg_id) FROM syslog"));
802 if (DBGetNumRows(hResult
) > 0)
804 s_msgId
= max(DBGetFieldUInt64(hResult
, 0, 0) + 1, s_msgId
);
806 DBFreeResult(hResult
);
808 DBConnectionPoolReleaseConnection(hdb
);
810 s_receiverThread
= ThreadCreateEx(SyslogReceiver
, 0, NULL
);
814 * Stop built-in syslog server
816 void StopSyslogServer()
819 ThreadJoin(s_receiverThread
);
823 * Create NXCP message from NX_SYSLOG_RECORD structure
825 void CreateMessageFromSyslogMsg(NXCPMessage
*pMsg
, NX_SYSLOG_RECORD
*pRec
)
827 UINT32 dwId
= VID_SYSLOG_MSG_BASE
;
829 pMsg
->setField(VID_NUM_RECORDS
, (UINT32
)1);
830 pMsg
->setField(dwId
++, pRec
->qwMsgId
);
831 pMsg
->setField(dwId
++, (UINT32
)pRec
->tmTimeStamp
);
832 pMsg
->setField(dwId
++, (WORD
)pRec
->nFacility
);
833 pMsg
->setField(dwId
++, (WORD
)pRec
->nSeverity
);
834 pMsg
->setField(dwId
++, pRec
->dwSourceObject
);
835 pMsg
->setFieldFromMBString(dwId
++, pRec
->szHostName
);
836 pMsg
->setFieldFromMBString(dwId
++, pRec
->szTag
);
837 pMsg
->setFieldFromMBString(dwId
++, pRec
->szMessage
);
841 * Reinitialize parser on configuration change
843 void ReinitializeSyslogParser()
845 if (s_parserLock
== INVALID_MUTEX_HANDLE
)
846 return; // Syslog daemon not initialized
847 CreateParserFromConfig();
851 * Handler for syslog related configuration changes
853 void OnSyslogConfigurationChange(const TCHAR
*name
, const TCHAR
*value
)
855 if (!_tcscmp(name
, _T("SyslogIgnoreMessageTimestamp")))
857 s_alwaysUseServerTime
= _tcstol(value
, NULL
, 0) ? true : false;
858 nxlog_debug(4, _T("Syslog: ignore message timestamp option set to %s"), s_alwaysUseServerTime
? _T("ON") : _T("OFF"));