ac7d6af31417df3a9d1e102772ee0b674233c60c
[public/netxms.git] / src / libnxlp / winfile.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Log Parsing Library
4 ** Copyright (C) 2008 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: winfile.cpp
21 **
22 **/
23
24 #include "libnxlp.h"
25
26 #define LOG if (logger != NULL) logger
27
28
29 //
30 // Constants
31 //
32
33 #define READ_BUFFER_SIZE 4096
34
35
36 //
37 // Parse new log records
38 //
39
40 static void ParseNewRecords(LogParser *parser, HANDLE hFile, void (*logger)(int, const TCHAR *, ...))
41 {
42 char *ptr, *eptr, buffer[READ_BUFFER_SIZE];
43 DWORD bytes, bufPos = 0;
44
45 do
46 {
47 if (ReadFile(hFile, &buffer[bufPos], READ_BUFFER_SIZE - bufPos, &bytes, NULL))
48 {
49 bytes += bufPos;
50 for(ptr = buffer;; ptr = eptr + 1)
51 {
52 bufPos = (DWORD)(ptr - buffer);
53 eptr = (char *)memchr(ptr, '\n', bytes - bufPos);
54 if (eptr == NULL)
55 {
56 bufPos = bytes - bufPos;
57 memmove(buffer, ptr, bufPos);
58 break;
59 }
60 if (*(eptr - 1) == '\r')
61 *(eptr - 1) = 0;
62 else
63 *eptr = 0;
64
65 parser->matchLine(ptr);
66 }
67 }
68 else
69 {
70 bytes = 0;
71 }
72 } while(bytes == READ_BUFFER_SIZE);
73 }
74
75
76 //
77 // Monitor file changes and parse line by line
78 //
79
80 bool LogParser::monitorFile(HANDLE stopEvent, void (*logger)(int, const TCHAR *, ...), bool readFromCurrPos)
81 {
82 HANDLE hFile, hChange, handles[2];
83 LARGE_INTEGER fp, fsnew;
84 TCHAR path[MAX_PATH], fname[MAX_PATH], *pch;
85 time_t t;
86 struct tm *ltm;
87
88 if ((m_fileName == NULL) || (stopEvent == NULL))
89 return FALSE;
90
91 nx_strncpy(path, m_fileName, MAX_PATH);
92 pch = _tcsrchr(path, _T('\\'));
93 if (pch != NULL)
94 *pch = 0;
95
96 t = time(NULL);
97 ltm = localtime(&t);
98 _tcsftime(fname, MAX_PATH, m_fileName, ltm);
99
100 hFile = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
101 NULL, OPEN_EXISTING, 0, NULL);
102 if (hFile != INVALID_HANDLE_VALUE)
103 {
104 if (!readFromCurrPos)
105 {
106 if (logger != NULL)
107 logger(EVENTLOG_DEBUG_TYPE, _T("LogParser: parsing existing records in file \"%s\""), m_fileName);
108 ParseNewRecords(this, hFile, logger);
109 }
110 GetFileSizeEx(hFile, &fp);
111 CloseHandle(hFile);
112
113 hChange = FindFirstChangeNotification(path, FALSE, FILE_NOTIFY_CHANGE_SIZE);
114 if (hChange != INVALID_HANDLE_VALUE)
115 {
116 LOG(EVENTLOG_DEBUG_TYPE, _T("LogParser: start tracking log file %s"), m_fileName);
117 handles[0] = hChange;
118 handles[1] = stopEvent;
119 while(1)
120 {
121 if (WaitForMultipleObjects(2, handles, FALSE, INFINITE) == WAIT_OBJECT_0 + 1)
122 break;
123
124 t = time(NULL);
125 ltm = localtime(&t);
126 _tcsftime(fname, MAX_PATH, m_fileName, ltm);
127
128 LOG(EVENTLOG_DEBUG_TYPE, _T("LogParser: new data in file %s"), fname);
129 hFile = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
130 NULL, OPEN_EXISTING, 0, NULL);
131 if (hFile != INVALID_HANDLE_VALUE)
132 {
133 GetFileSizeEx(hFile, &fsnew);
134 LOG(EVENTLOG_DEBUG_TYPE, _T("LogParser: file %s oldSize = %I64d newSize = %I64d"), fname, fp.QuadPart, fsnew.QuadPart);
135 if (fsnew.QuadPart != fp.QuadPart)
136 {
137 if (fsnew.QuadPart > fp.QuadPart)
138 {
139 SetFilePointerEx(hFile, fp, NULL, FILE_BEGIN);
140 }
141 else
142 {
143 // Assume that file was rewritten
144 fp.QuadPart = 0;
145 SetFilePointerEx(hFile, fp, NULL, FILE_BEGIN);
146 LOG(EVENTLOG_DEBUG_TYPE, _T("LogParser: file %s - assume overwrite"), fname);
147 }
148 ParseNewRecords(this, hFile, logger);
149 GetFileSizeEx(hFile, &fp);
150 LOG(EVENTLOG_DEBUG_TYPE, _T("LogParser: file %s size after parse is %I64d"), fname, fp.QuadPart);
151 }
152 CloseHandle(hFile);
153 }
154 FindNextChangeNotification(hChange);
155 }
156
157 FindCloseChangeNotification(hChange);
158 }
159 }
160 else
161 {
162 if (logger != NULL)
163 logger(EVENTLOG_ERROR_TYPE, _T("LogParser: Cannot open log file %s"), m_fileName);
164 }
165
166 return true;
167 }