Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/win32/project/Makefile_get.inc4
-rw-r--r--build/win32/project/Makefile_sender.inc4
-rw-r--r--include/common.h5
-rw-r--r--include/zbxtypes.h6
-rw-r--r--src/libs/zbxcommon/file.c139
-rw-r--r--src/libs/zbxregexp/zbxregexp.c74
-rw-r--r--src/zabbix_agent/active.c165
-rw-r--r--src/zabbix_agent/active.h1
-rw-r--r--src/zabbix_agent/logfiles.c627
-rw-r--r--src/zabbix_agent/logfiles.h15
10 files changed, 670 insertions, 370 deletions
diff --git a/build/win32/project/Makefile_get.inc b/build/win32/project/Makefile_get.inc
index 3172f7d8eaa..c136db6c04b 100644
--- a/build/win32/project/Makefile_get.inc
+++ b/build/win32/project/Makefile_get.inc
@@ -13,7 +13,6 @@ OBJS = ..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxcommon\str.o \
..\..\..\src\libs\zbxcommon\xml.o \
..\..\..\src\libs\zbxcommon\zbxgetopt.o \
- ..\..\..\src\libs\zbxcommon\file.o \
..\..\..\src\libs\zbxcomms\comms.o \
..\..\..\src\libs\zbxconf\cfg.o \
..\..\..\src\libs\zbxcrypto\base64.o \
@@ -55,9 +54,6 @@ $(RESOURCE_RES): $(RESOURCE_RC) $(RESOURCE_H) $(DESC_H)
..\..\..\src\libs\zbxcommon\zbxgetopt.o: ..\..\..\src\libs\zbxcommon\zbxgetopt.c
$(CC) ..\..\..\src\libs\zbxcommon\zbxgetopt.c /Fo"..\..\..\src\libs\zbxcommon\zbxgetopt.o" $(CFLAGS)
-..\..\..\src\libs\zbxcommon\file.o: ..\..\..\src\libs\zbxcommon\file.c
- $(CC) ..\..\..\src\libs\zbxcommon\file.c /Fo"..\..\..\src\libs\zbxcommon\file.o" $(CFLAGS)
-
..\..\..\src\libs\zbxcomms\comms.o: ..\..\..\src\libs\zbxcomms\comms.c
$(CC) ..\..\..\src\libs\zbxcomms\comms.c /Fo"..\..\..\src\libs\zbxcomms\comms.o" $(CFLAGS)
diff --git a/build/win32/project/Makefile_sender.inc b/build/win32/project/Makefile_sender.inc
index 2a699db7bab..836ee40de41 100644
--- a/build/win32/project/Makefile_sender.inc
+++ b/build/win32/project/Makefile_sender.inc
@@ -13,7 +13,6 @@ OBJS = ..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxcommon\str.o \
..\..\..\src\libs\zbxcommon\xml.o \
..\..\..\src\libs\zbxcommon\zbxgetopt.o \
- ..\..\..\src\libs\zbxcommon\file.o \
..\..\..\src\libs\zbxcomms\comms.o \
..\..\..\src\libs\zbxconf\cfg.o \
..\..\..\src\libs\zbxcrypto\base64.o \
@@ -60,9 +59,6 @@ $(RESOURCE_RES): $(RESOURCE_RC) $(RESOURCE_H) $(DESC_H)
..\..\..\src\libs\zbxcommon\zbxgetopt.o: ..\..\..\src\libs\zbxcommon\zbxgetopt.c
$(CC) ..\..\..\src\libs\zbxcommon\zbxgetopt.c /Fo"..\..\..\src\libs\zbxcommon\zbxgetopt.o" $(CFLAGS)
-..\..\..\src\libs\zbxcommon\file.o: ..\..\..\src\libs\zbxcommon\file.c
- $(CC) ..\..\..\src\libs\zbxcommon\file.c /Fo"..\..\..\src\libs\zbxcommon\file.o" $(CFLAGS)
-
..\..\..\src\libs\zbxcomms\comms.o: ..\..\..\src\libs\zbxcomms\comms.c
$(CC) ..\..\..\src\libs\zbxcomms\comms.c /Fo"..\..\..\src\libs\zbxcomms\comms.o" $(CFLAGS)
diff --git a/include/common.h b/include/common.h
index 54237db53b2..172ca462df9 100644
--- a/include/common.h
+++ b/include/common.h
@@ -1028,6 +1028,11 @@ double str2double(const char *str);
int __zbx_stat(const char *path, struct stat *buf);
int __zbx_open(const char *pathname, int flags);
#endif /* _WINDOWS && _UNICODE */
+
+typedef int (*zbx_process_value_func_t)(const char *, unsigned short, const char *, const char *, const char *,
+ zbx_uint64_t *, int *, unsigned long *, const char *, unsigned short *, unsigned long *, unsigned char);
+
+void find_cr_lf_szbyte(const char *encoding, const char **cr, const char **lf, size_t *szbyte);
int zbx_read(int fd, char *buf, size_t count, const char *encoding);
int zbx_is_regular_file(const char *path);
diff --git a/include/zbxtypes.h b/include/zbxtypes.h
index b3aaa71fe60..fa300cb9508 100644
--- a/include/zbxtypes.h
+++ b/include/zbxtypes.h
@@ -74,6 +74,9 @@
# define strcasecmp lstrcmpiA
+typedef __int64 zbx_offset_t;
+#define zbx_lseek(fd, offset, whence) _lseeki64(fd, (zbx_offset_t)(offset), whence)
+
#else /* _WINDOWS */
# define zbx_stat(path, buf) stat(path, buf)
@@ -110,6 +113,9 @@
# define PATH_SEPARATOR '/'
#endif
+typedef off_t zbx_offset_t;
+#define zbx_lseek(fd, offset, whence) lseek(fd, (zbx_offset_t)(offset), whence)
+
#endif /* _WINDOWS */
#define ZBX_FS_SIZE_T ZBX_FS_UI64
diff --git a/src/libs/zbxcommon/file.c b/src/libs/zbxcommon/file.c
index 22f45afe418..5f7aee9125d 100644
--- a/src/libs/zbxcommon/file.c
+++ b/src/libs/zbxcommon/file.c
@@ -45,69 +45,93 @@ int __zbx_open(const char *pathname, int flags)
}
#endif
-/*
- * Reads in at most one less than size characters from a file descriptor and stores them into the buffer pointed to by s.
- * Reading stops after a newline. If a newline is read, it is stored into the buffer.
- *
- * On success, the number of bytes read is returned (zero indicates end of file).
- * On error, -1 is returned, and errno is set appropriately.
- */
+void find_cr_lf_szbyte(const char *encoding, const char **cr, const char **lf, size_t *szbyte)
+{
+ /* default is single-byte character set */
+ *cr = "\r";
+ *lf = "\n";
+ *szbyte = 1;
+
+ if ('\0' != *encoding)
+ {
+ if (0 == strcasecmp(encoding, "UNICODE") || 0 == strcasecmp(encoding, "UNICODELITTLE") ||
+ 0 == strcasecmp(encoding, "UTF-16") || 0 == strcasecmp(encoding, "UTF-16LE") ||
+ 0 == strcasecmp(encoding, "UTF16") || 0 == strcasecmp(encoding, "UTF16LE"))
+ {
+ *cr = "\r\0";
+ *lf = "\n\0";
+ *szbyte = 2;
+ }
+ else if (0 == strcasecmp(encoding, "UNICODEBIG") || 0 == strcasecmp(encoding, "UNICODEFFFE") ||
+ 0 == strcasecmp(encoding, "UTF-16BE") || 0 == strcasecmp(encoding, "UTF16BE"))
+ {
+ *cr = "\0\r";
+ *lf = "\0\n";
+ *szbyte = 2;
+ }
+ else if (0 == strcasecmp(encoding, "UTF-32") || 0 == strcasecmp(encoding, "UTF-32LE") ||
+ 0 == strcasecmp(encoding, "UTF32") || 0 == strcasecmp(encoding, "UTF32LE"))
+ {
+ *cr = "\r\0\0\0";
+ *lf = "\n\0\0\0";
+ *szbyte = 4;
+ }
+ else if (0 == strcasecmp(encoding, "UTF-32BE") || 0 == strcasecmp(encoding, "UTF32BE"))
+ {
+ *cr = "\0\0\0\r";
+ *lf = "\0\0\0\n";
+ *szbyte = 4;
+ }
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_read *
+ * *
+ * Purpose: Read one text line from a file descriptor into buffer *
+ * *
+ * Parameters: fd - [IN] file descriptor to read from *
+ * buf - [IN] buffer to read into *
+ * count - [IN] buffer size in bytes *
+ * encoding - [IN] pointer to a text string describing encoding. *
+ * The following encodings are recognized: *
+ * "UNICODE" *
+ * "UNICODEBIG" *
+ * "UNICODEFFFE" *
+ * "UNICODELITTLE" *
+ * "UTF-16" "UTF16" *
+ * "UTF-16BE" "UTF16BE" *
+ * "UTF-16LE" "UTF16LE" *
+ * "UTF-32" "UTF32" *
+ * "UTF-32BE" "UTF32BE" *
+ * "UTF-32LE" "UTF32LE". *
+ * "" (empty string) means a single-byte character set.*
+ * *
+ * Return value: On success, the number of bytes read is returned (0 (zero) *
+ * indicates end of file). *
+ * On error, -1 is returned and errno is set appropriately. *
+ * *
+ * Comments: Reading stops after a newline. If the newline is read, it is *
+ * stored into the buffer. *
+ * *
+ ******************************************************************************/
int zbx_read(int fd, char *buf, size_t count, const char *encoding)
{
size_t i, szbyte;
const char *cr, *lf;
int nbytes;
-#ifdef _WINDOWS
- __int64 offset;
-#else
- off_t offset;
-#endif
+ zbx_offset_t offset;
-#ifdef _WINDOWS
- offset = _lseeki64(fd, 0, SEEK_CUR);
-#else
- offset = lseek(fd, 0, SEEK_CUR);
-#endif
+ if ((zbx_offset_t)-1 == (offset = zbx_lseek(fd, 0, SEEK_CUR)))
+ return -1;
if (0 >= (nbytes = (int)read(fd, buf, count)))
return nbytes;
- if (0 == strcasecmp(encoding, "UNICODE") || 0 == strcasecmp(encoding, "UNICODELITTLE") ||
- 0 == strcasecmp(encoding, "UTF-16") || 0 == strcasecmp(encoding, "UTF-16LE") ||
- 0 == strcasecmp(encoding, "UTF16") || 0 == strcasecmp(encoding, "UTF16LE"))
- {
- cr = "\r\0";
- lf = "\n\0";
- szbyte = 2;
- }
- else if (0 == strcasecmp(encoding, "UNICODEBIG") || 0 == strcasecmp(encoding, "UNICODEFFFE") ||
- 0 == strcasecmp(encoding, "UTF-16BE") || 0 == strcasecmp(encoding, "UTF16BE"))
- {
- cr = "\0\r";
- lf = "\0\n";
- szbyte = 2;
- }
- else if (0 == strcasecmp(encoding, "UTF-32") || 0 == strcasecmp(encoding, "UTF-32LE") ||
- 0 == strcasecmp(encoding, "UTF32") || 0 == strcasecmp(encoding, "UTF32LE"))
- {
- cr = "\r\0\0\0";
- lf = "\n\0\0\0";
- szbyte = 4;
- }
- else if (0 == strcasecmp(encoding, "UTF-32BE") || 0 == strcasecmp(encoding, "UTF32BE"))
- {
- cr = "\0\0\0\r";
- lf = "\0\0\0\n";
- szbyte = 4;
- }
- else /* Single or Multi Byte Character Sets */
- {
- cr = "\r";
- lf = "\n";
- szbyte = 1;
- }
+ find_cr_lf_szbyte(encoding, &cr, &lf, &szbyte);
- for (i = 0; i + szbyte <= (size_t)nbytes; i += szbyte)
+ for (i = 0; i <= (size_t)nbytes - szbyte; i += szbyte)
{
if (0 == memcmp(&buf[i], lf, szbyte)) /* LF (Unix) */
{
@@ -117,18 +141,17 @@ int zbx_read(int fd, char *buf, size_t count, const char *encoding)
if (0 == memcmp(&buf[i], cr, szbyte)) /* CR (Mac) */
{
- if (i + szbyte < (size_t)nbytes && 0 == memcmp(&buf[i + szbyte], lf, szbyte)) /* CR+LF (Windows) */
+ /* CR+LF (Windows) ? */
+ if (i < (size_t)nbytes - szbyte && 0 == memcmp(&buf[i + szbyte], lf, szbyte))
i += szbyte;
+
i += szbyte;
break;
}
}
-#ifdef _WINDOWS
- _lseeki64(fd, offset + i, SEEK_SET);
-#else
- lseek(fd, offset + i, SEEK_SET);
-#endif
+ if ((zbx_offset_t)-1 == zbx_lseek(fd, offset + (zbx_offset_t)i, SEEK_SET))
+ return -1;
return (int)i;
}
diff --git a/src/libs/zbxregexp/zbxregexp.c b/src/libs/zbxregexp/zbxregexp.c
index ec457f48a04..4964c45f3c0 100644
--- a/src/libs/zbxregexp/zbxregexp.c
+++ b/src/libs/zbxregexp/zbxregexp.c
@@ -27,28 +27,46 @@
static char *zbx_regexp(const char *string, const char *pattern, int *len, int flags)
{
char *c = NULL;
- regex_t re;
+ static char *old_pattern = NULL;
+ static int old_flags;
+ static regex_t re;
regmatch_t match;
if (NULL != len)
*len = 0;
- if (NULL != string)
- {
- if (0 == regcomp(&re, pattern, flags))
- {
- if (0 == regexec(&re, string, (size_t)1, &match, 0)) /* matched */
- {
- c = (char *)string + match.rm_so;
+ if (NULL == string)
+ goto out;
- if (NULL != len)
- *len = match.rm_eo - match.rm_so;
- }
+ /* performance optimization: if possible then reuse the last compiled regexp */
- regfree(&re);
- }
+ if (NULL == old_pattern)
+ goto compile;
+
+ if (0 != strcmp(old_pattern, pattern) || old_flags != flags)
+ regfree(&re);
+ else
+ goto execute;
+compile:
+ if (0 == regcomp(&re, pattern, flags))
+ {
+ old_pattern = zbx_strdup(old_pattern, pattern);
+ old_flags = flags;
+ }
+ else
+ {
+ zbx_free(old_pattern);
+ goto out;
}
+execute:
+ if (0 == regexec(&re, string, (size_t)1, &match, 0)) /* matched */
+ {
+ c = (char *)string + match.rm_so;
+ if (NULL != len)
+ *len = match.rm_eo - match.rm_so;
+ }
+out:
return c;
}
@@ -174,9 +192,11 @@ out:
*********************************************************************************/
static char *regexp_sub(const char *string, const char *pattern, const char *output_template, int flags)
{
- regex_t re;
- regmatch_t match[10];
+ static regex_t re;
+ regmatch_t match[10]; /* up to 10 capture groups in regexp */
char *ptr = NULL;
+ static char *old_pattern = NULL;
+ static int old_flags;
if (NULL == string)
return NULL;
@@ -184,14 +204,30 @@ static char *regexp_sub(const char *string, const char *pattern, const char *out
if (NULL == output_template || '\0' == *output_template)
flags |= REG_NOSUB;
- if (0 != regcomp(&re, pattern, flags))
- return NULL;
+ /* performance optimization: if possible then reuse the last compiled regexp */
+ if (NULL == old_pattern)
+ goto compile;
+
+ if (0 != strcmp(old_pattern, pattern) || old_flags != flags)
+ regfree(&re);
+ else
+ goto execute;
+compile:
+ if (0 == regcomp(&re, pattern, flags))
+ {
+ old_pattern = zbx_strdup(old_pattern, pattern);
+ old_flags = flags;
+ }
+ else
+ {
+ zbx_free(old_pattern);
+ return NULL;
+ }
+execute:
if (0 == regexec(&re, string, ARRSIZE(match), match, 0))
ptr = regexp_sub_replace(string, output_template, match, ARRSIZE(match));
- regfree(&re);
-
return ptr;
}
diff --git a/src/zabbix_agent/active.c b/src/zabbix_agent/active.c
index 8003bfebd4c..167d664e3e0 100644
--- a/src/zabbix_agent/active.c
+++ b/src/zabbix_agent/active.c
@@ -32,7 +32,6 @@
#include "comms.h"
#include "threads.h"
#include "zbxjson.h"
-#include "zbxregexp.h"
#if defined(ZABBIX_SERVICE)
# include "service.h"
@@ -126,7 +125,10 @@ static void free_active_metrics(void)
zabbix_log(LOG_LEVEL_DEBUG, "In free_active_metrics()");
for (i = 0; NULL != active_metrics[i].key; i++)
+ {
zbx_free(active_metrics[i].key);
+ zbx_free(active_metrics[i].key_orig);
+ }
zbx_free(active_metrics);
@@ -175,6 +177,7 @@ static void add_check(const char *key, const char *key_orig, int refresh, zbx_ui
active_metrics[i].key = strdup(key);
active_metrics[i].lastlogsize = lastlogsize;
active_metrics[i].mtime = mtime;
+ active_metrics[i].big_rec = 0;
}
/* replace metric */
@@ -198,6 +201,7 @@ static void add_check(const char *key, const char *key_orig, int refresh, zbx_ui
active_metrics[i].mtime = mtime;
/* can skip existing log[] and eventlog[] data */
active_metrics[i].skip_old_data = active_metrics[i].lastlogsize ? 0 : 1;
+ active_metrics[i].big_rec = 0;
/* move to the last metric */
i++;
@@ -720,7 +724,13 @@ ret:
* *
* Author: Alexei Vladishev *
* *
- * Comments: *
+ * Comments: ATTENTION! This function's address and pointers to arguments *
+ * are described in Zabbix defined type "zbx_process_value_func_t" *
+ * and used when calling process_log(), process_logrt() and *
+ * zbx_read2(). If you ever change this process_value() arguments *
+ * or return value do not forget to synchronize changes with the *
+ * defined type "zbx_process_value_func_t" and implementations of *
+ * process_log(), process_logrt(), zbx_read2() and their callers. *
* *
******************************************************************************/
static int process_value(
@@ -799,7 +809,7 @@ static int process_value(
memset(el, 0, sizeof(ZBX_ACTIVE_BUFFER_ELEMENT));
el->host = zbx_strdup(NULL, host);
el->key = zbx_strdup(NULL, key);
- el->value = (NULL == value) ? NULL : zbx_strdup(NULL, value);
+ el->value = zbx_strdup(NULL, value);
if (NULL != source)
el->source = strdup(source);
@@ -830,18 +840,17 @@ out:
static void process_active_checks(char *server, unsigned short port)
{
const char *__function_name = "process_active_checks";
- register int i, s_count, p_count;
+ int i, s_count, p_count;
char **pvalue;
int now, send_err = SUCCEED, ret;
- char *value = NULL, *item_value = NULL;
- zbx_uint64_t lastlogsize;
- int mtime;
char params[MAX_STRING_LEN], filename[MAX_STRING_LEN];
char pattern[MAX_STRING_LEN], output_template[MAX_STRING_LEN];
/* checks `log', `eventlog', `logrt' may contain parameter, which overrides CONFIG_MAX_LINES_PER_SECOND */
char maxlines_persec_str[16];
int maxlines_persec;
#ifdef _WINDOWS
+ char *value = NULL;
+ zbx_uint64_t lastlogsize;
unsigned long timestamp, logeventid;
unsigned short severity;
char key_severity[MAX_STRING_LEN], str_severity[32] /* for `regex_match_ex' */;
@@ -880,7 +889,6 @@ static void process_active_checks(char *server, unsigned short port)
do
{
- /* simple try realization */
if (ZBX_COMMAND_WITH_PARAMS != parse_command(active_metrics[i].key, NULL, 0,
params, sizeof(params)))
{
@@ -919,58 +927,18 @@ static void process_active_checks(char *server, unsigned short port)
if (0 != get_param(params, 6, output_template, sizeof(output_template)))
*output_template = '\0';
- s_count = 0;
- p_count = 0;
- lastlogsize = active_metrics[i].lastlogsize;
-
- while (SUCCEED == (ret = process_log(filename, &lastlogsize, &value, encoding,
- active_metrics[i].skip_old_data)))
- {
- active_metrics[i].skip_old_data = 0;
-
- /* End of file. The file could become empty, must save `lastlogsize'. */
- if (NULL == value)
- {
- active_metrics[i].lastlogsize = lastlogsize;
- break;
- }
-
- if (SUCCEED == regexp_sub_ex(&regexps, value, pattern, ZBX_CASE_SENSITIVE,
- output_template, &item_value))
- {
- send_err = process_value(server, port, CONFIG_HOSTNAME,
- active_metrics[i].key_orig, item_value, &lastlogsize,
- NULL, NULL, NULL, NULL, NULL, 1);
-
- zbx_free(item_value);
-
- s_count++;
- }
- p_count++;
-
- zbx_free(value);
-
- if (SUCCEED == send_err)
- active_metrics[i].lastlogsize = lastlogsize;
- else
- {
- /* buffer is full, stop processing active checks */
- /* till the buffer is cleared */
- lastlogsize = active_metrics[i].lastlogsize;
- goto ret;
- }
+ /* do not flood Zabbix server if file grows too fast */
+ s_count = maxlines_persec * active_metrics[i].refresh;
- /* do not flood Zabbix server if file grows too fast */
- if (s_count >= (maxlines_persec * active_metrics[i].refresh))
- break;
-
- /* do not flood local system if file grows too fast */
- if (p_count >= (4 * maxlines_persec * active_metrics[i].refresh))
- break;
- } /* while processing a log */
+ /* do not flood local system if file grows too fast */
+ p_count = 4 * maxlines_persec * active_metrics[i].refresh;
+ ret = process_log(filename, &active_metrics[i].lastlogsize, NULL,
+ &active_metrics[i].skip_old_data, &active_metrics[i].big_rec, encoding,
+ &regexps, pattern, output_template, &p_count, &s_count, process_value,
+ server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig);
}
- while (0); /* simple try realization */
+ while (0);
if (FAIL == ret)
{
@@ -978,8 +946,9 @@ static void process_active_checks(char *server, unsigned short port)
zabbix_log(LOG_LEVEL_WARNING, "active check \"%s\" is not supported",
active_metrics[i].key);
- process_value(server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, NULL,
- &active_metrics[i].lastlogsize, NULL, NULL, NULL, NULL, NULL, 0);
+ process_value(server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig,
+ ZBX_NOTSUPPORTED, &active_metrics[i].lastlogsize, NULL, NULL, NULL,
+ NULL, NULL, 0);
}
}
/* special processing for log files with rotation */
@@ -989,7 +958,6 @@ static void process_active_checks(char *server, unsigned short port)
do
{
- /* simple try realization */
if (ZBX_COMMAND_WITH_PARAMS != parse_command(active_metrics[i].key, NULL, 0,
params, sizeof(params)))
{
@@ -1028,64 +996,18 @@ static void process_active_checks(char *server, unsigned short port)
if (0 != get_param(params, 6, output_template, sizeof(output_template)))
*output_template = '\0';
- s_count = 0;
- p_count = 0;
- lastlogsize = active_metrics[i].lastlogsize;
- mtime = active_metrics[i].mtime;
-
- while (SUCCEED == (ret = process_logrt(filename, &lastlogsize, &mtime, &value,
- encoding, active_metrics[i].skip_old_data)))
- {
- active_metrics[i].skip_old_data = 0;
-
- /* End of file. The file could become empty,*/
- /* must save `lastlogsize' and `mtime'. */
- if (NULL == value)
- {
- active_metrics[i].lastlogsize = lastlogsize;
- active_metrics[i].mtime = mtime;
- break;
- }
-
- if (SUCCEED == regexp_sub_ex(&regexps, value, pattern, ZBX_CASE_SENSITIVE,
- output_template, &item_value))
- {
- send_err = process_value(server, port, CONFIG_HOSTNAME,
- active_metrics[i].key_orig, item_value, &lastlogsize,
- &mtime, NULL, NULL, NULL, NULL, 1);
-
- zbx_free(item_value);
-
- s_count++;
- }
- p_count++;
-
- zbx_free(value);
-
- if (SUCCEED == send_err)
- {
- active_metrics[i].lastlogsize = lastlogsize;
- active_metrics[i].mtime = mtime;
- }
- else
- {
- /* buffer is full, stop processing active checks */
- /* till the buffer is cleared */
- lastlogsize = active_metrics[i].lastlogsize;
- mtime = active_metrics[i].mtime;
- goto ret;
- }
+ /* do not flood Zabbix server if files grow too fast */
+ s_count = maxlines_persec * active_metrics[i].refresh;
- /* do not flood Zabbix server if file grows too fast */
- if (s_count >= (maxlines_persec * active_metrics[i].refresh))
- break;
+ /* do not flood local system if files grow too fast */
+ p_count = 4 * maxlines_persec * active_metrics[i].refresh;
- /* do not flood local system if file grows too fast */
- if (p_count >= (4 * maxlines_persec * active_metrics[i].refresh))
- break;
- } /* while processing a log */
+ ret = process_logrt(filename, &active_metrics[i].lastlogsize, &active_metrics[i].mtime,
+ &active_metrics[i].skip_old_data, &active_metrics[i].big_rec, encoding,
+ &regexps, pattern, output_template, &p_count, &s_count, process_value,
+ server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig);
}
- while (0); /* simple try realization */
+ while (0);
if (FAIL == ret)
{
@@ -1093,9 +1015,9 @@ static void process_active_checks(char *server, unsigned short port)
zabbix_log(LOG_LEVEL_WARNING, "active check \"%s\" is not supported",
active_metrics[i].key);
- process_value(server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, NULL,
- &active_metrics[i].lastlogsize, &active_metrics[i].mtime,
- NULL, NULL, NULL, NULL, 0);
+ process_value(server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig,
+ ZBX_NOTSUPPORTED, &active_metrics[i].lastlogsize,
+ &active_metrics[i].mtime, NULL, NULL, NULL, NULL, 0);
}
}
/* special processing for eventlog */
@@ -1361,8 +1283,9 @@ static void process_active_checks(char *server, unsigned short port)
zabbix_log(LOG_LEVEL_WARNING, "active check \"%s\" is not supported",
active_metrics[i].key);
- process_value(server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, NULL,
- &active_metrics[i].lastlogsize, NULL, NULL, NULL, NULL, NULL, 0);
+ process_value(server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig,
+ ZBX_NOTSUPPORTED, &active_metrics[i].lastlogsize, NULL, NULL, NULL,
+ NULL, NULL, 0);
}
}
else
@@ -1391,7 +1314,9 @@ static void process_active_checks(char *server, unsigned short port)
}
active_metrics[i].nextcheck = (int)time(NULL) + active_metrics[i].refresh;
}
+#ifdef _WINDOWS
ret:
+#endif
zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
}
diff --git a/src/zabbix_agent/active.h b/src/zabbix_agent/active.h
index a561903ae01..ef41954ea82 100644
--- a/src/zabbix_agent/active.h
+++ b/src/zabbix_agent/active.h
@@ -75,6 +75,7 @@ typedef struct
int mtime;
unsigned char skip_old_data; /* for processing [event]log metrics */
unsigned char state;
+ int big_rec; /* for reading logfiles: 0 - normal record, 1 - long unfinished record */
}
ZBX_ACTIVE_METRIC;
diff --git a/src/zabbix_agent/logfiles.c b/src/zabbix_agent/logfiles.c
index baf331ba06b..30da8928d9e 100644
--- a/src/zabbix_agent/logfiles.c
+++ b/src/zabbix_agent/logfiles.c
@@ -20,7 +20,10 @@
#include "common.h"
#include "logfiles.h"
#include "log.h"
-#include "zbxregexp.h"
+
+#if defined(_WINDOWS)
+# include "gnuregex.h"
+#endif /* _WINDOWS */
/******************************************************************************
* *
@@ -349,28 +352,55 @@ out:
* *
* Function: process_logrt *
* *
- * Purpose: Get message from logfile with rotation *
- * *
- * Parameters: filename - logfile name (regular expression with a path) *
- * lastlogsize - offset for message *
- * mtime - last modification time of the file *
- * value - pointer for logged message *
+ * Purpose: Find new records in logfiles with rotation *
+ * *
+ * Parameters: *
+ * filename - [IN] logfile name (regular expression with a path) *
+ * lastlogsize - [IN/OUT] offset from the beginning of the file *
+ * mtime - [IN/OUT] last modification time of the file *
+ * skip_old_data - [IN/OUT] start from the beginning of the file or *
+ * jump to the end *
+ * big_rec - [IN/OUT] state variable to remember whether a long *
+ * record is being processed *
+ * encoding - [IN] text string describing encoding. *
+ * The following encodings are recognized: *
+ * "UNICODE" *
+ * "UNICODEBIG" *
+ * "UNICODEFFFE" *
+ * "UNICODELITTLE" *
+ * "UTF-16" "UTF16" *
+ * "UTF-16BE" "UTF16BE" *
+ * "UTF-16LE" "UTF16LE" *
+ * "UTF-32" "UTF32" *
+ * "UTF-32BE" "UTF32BE" *
+ * "UTF-32LE" "UTF32LE". *
+ * "" (empty string) means a single-byte character *
+ * set (e.g. ASCII). *
+ * regexps - [IN] array of regexps *
+ * pattern - [IN] pattern to match *
+ * output_template - [IN] output formatting template *
+ * p_count - [IN/OUT] limit of records to be processed *
+ * s_count - [IN/OUT] limit of records to be sent to server *
+ * process_value - [IN] pointer to function process_value() *
+ * server - [IN] server to send data to *
+ * port - [IN] port to send data to *
+ * hostname - [IN] hostname the data comes from *
+ * key - [IN] item key the data belongs to *
* *
* Return value: returns SUCCEED on successful reading, *
* FAIL on other cases *
* *
* Author: Dmitry Borovikov (logrotation) *
* *
- * Comments: This function allocates memory for 'value', so use zbx_free(). *
- * Return SUCCEED and NULL 'value' if end of file received. *
- * *
******************************************************************************/
-int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, char **value, const char *encoding,
- unsigned char skip_old_data)
+int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, unsigned char *skip_old_data,
+ int *big_rec, const char *encoding, zbx_vector_ptr_t *regexps, const char *pattern,
+ const char *output_template, int *p_count, int *s_count, zbx_process_value_func_t process_value,
+ const char *server, unsigned short port, const char *hostname, const char *key)
{
const char *__function_name = "process_logrt";
- int i = 0, nbytes, ret = FAIL, logfiles_num = 0, logfiles_alloc = 0, fd = 0, length = 0, j = 0;
- char buffer[MAX_BUFFER_LEN], *directory = NULL, *format = NULL, *logfile_candidate = NULL;
+ int i = 0, ret = FAIL, logfiles_num = 0, logfiles_alloc = 0, j = 0, reg_error;
+ char err_buf[MAX_STRING_LEN], *directory = NULL, *format = NULL, *logfile_candidate = NULL;
struct stat file_buf;
struct st_logfile *logfiles = NULL;
#ifdef _WINDOWS
@@ -382,6 +412,8 @@ int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, char **
DIR *dir = NULL;
struct dirent *d_ent = NULL;
#endif
+ regex_t re;
+ time_t now;
zabbix_log(LOG_LEVEL_DEBUG, "In %s() filename:'%s' lastlogsize:" ZBX_FS_UI64 " mtime:%d",
__function_name, filename, *lastlogsize, *mtime);
@@ -389,7 +421,37 @@ int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, char **
/* splitting filename */
if (SUCCEED != split_filename(filename, &directory, &format))
{
- zabbix_log(LOG_LEVEL_WARNING, "filename '%s' does not contain a valid directory and/or format", filename);
+ zabbix_log(LOG_LEVEL_WARNING, "filename '%s' does not contain a valid directory and/or format",
+ filename);
+ goto out;
+ }
+
+ if (0 != (reg_error = regcomp(&re, format, REG_EXTENDED | REG_NEWLINE | REG_NOSUB)))
+ {
+ regerror(reg_error, &re, err_buf, sizeof(err_buf));
+ zabbix_log(LOG_LEVEL_WARNING, "Cannot compile a regexp describing filename pattern '%s' for a logrt[] "
+ "item. Error: %s", format, err_buf);
+ goto out;
+ }
+
+ /* Minimize data loss if the system clock has been set back in time. */
+ /* Setting the clock ahead of time is harmless in our case. */
+ if ((time_t)-1 != (now = time(NULL)))
+ {
+ if (now < *mtime)
+ {
+ int old_mtime;
+
+ old_mtime = *mtime;
+ *mtime = (int)now;
+ zabbix_log(LOG_LEVEL_WARNING, "System clock has been set back in time. Setting agent mtime %d "
+ "seconds back.", (int)(old_mtime - now));
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "cannot get system time");
+ regfree(&re);
goto out;
}
@@ -401,7 +463,9 @@ int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, char **
if (-1 == (find_handle = _wfindfirst(find_wpath, &find_data)))
{
- zabbix_log(LOG_LEVEL_DEBUG, "cannot get entries from '%s' directory: %s", directory, zbx_strerror(errno));
+ zabbix_log(LOG_LEVEL_WARNING, "cannot open directory \"%s\" for reading: %s", directory,
+ zbx_strerror(errno));
+ regfree(&re);
zbx_free(directory);
zbx_free(format);
zbx_free(find_wpath);
@@ -409,23 +473,24 @@ int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, char **
}
zbx_free(find_wpath);
- zabbix_log(LOG_LEVEL_DEBUG, "we are in the Windows directory reading cycle");
do
{
file_name_utf8 = zbx_unicode_to_utf8(find_data.name);
logfile_candidate = zbx_dsprintf(logfile_candidate, "%s%s", directory, file_name_utf8);
- if (-1 == zbx_stat(logfile_candidate, &file_buf) || !S_ISREG(file_buf.st_mode))
+ if (0 == zbx_stat(logfile_candidate, &file_buf))
{
- zabbix_log(LOG_LEVEL_DEBUG, "cannot process read entry '%s'", logfile_candidate);
- }
- else if (NULL != zbx_regexp_match(file_name_utf8, format, &length))
- {
- zabbix_log(LOG_LEVEL_DEBUG, "adding file '%s' to logfiles", logfile_candidate);
- add_logfile(&logfiles, &logfiles_alloc, &logfiles_num, file_name_utf8, (int)file_buf.st_mtime);
+ if (S_ISREG(file_buf.st_mode) &&
+ *mtime <= file_buf.st_mtime &&
+ 0 == regexec(&re, file_name_utf8, (size_t)0, NULL, 0))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "adding file '%s' to logfiles", logfile_candidate);
+ add_logfile(&logfiles, &logfiles_alloc, &logfiles_num, file_name_utf8,
+ (int)file_buf.st_mtime);
+ }
}
else
- zabbix_log(LOG_LEVEL_DEBUG, "'%s' does not match '%s'", logfile_candidate, format);
+ zabbix_log(LOG_LEVEL_DEBUG, "cannot process entry '%s'", logfile_candidate);
zbx_free(logfile_candidate);
zbx_free(file_name_utf8);
@@ -437,45 +502,37 @@ int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, char **
if (NULL == (dir = opendir(directory)))
{
zabbix_log(LOG_LEVEL_WARNING, "cannot open directory '%s' for reading: %s", directory, zbx_strerror(errno));
+ regfree(&re);
zbx_free(directory);
zbx_free(format);
goto out;
}
- zabbix_log(LOG_LEVEL_DEBUG, "we are in the *nix directory reading cycle");
while (NULL != (d_ent = readdir(dir)))
{
logfile_candidate = zbx_dsprintf(logfile_candidate, "%s%s", directory, d_ent->d_name);
- if (-1 == zbx_stat(logfile_candidate, &file_buf) || !S_ISREG(file_buf.st_mode))
- {
- zabbix_log(LOG_LEVEL_DEBUG, "cannot process read entry '%s'", logfile_candidate);
- }
- else if (NULL != zbx_regexp_match(d_ent->d_name, format, &length))
+ if (0 == zbx_stat(logfile_candidate, &file_buf))
{
- zabbix_log(LOG_LEVEL_DEBUG, "adding file '%s' to logfiles", logfile_candidate);
- add_logfile(&logfiles, &logfiles_alloc, &logfiles_num, d_ent->d_name, (int)file_buf.st_mtime);
+ if (S_ISREG(file_buf.st_mode) &&
+ *mtime <= file_buf.st_mtime &&
+ 0 == regexec(&re, d_ent->d_name, (size_t)0, NULL, 0))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "adding file '%s' to logfiles", logfile_candidate);
+ add_logfile(&logfiles, &logfiles_alloc, &logfiles_num, d_ent->d_name,
+ (int)file_buf.st_mtime);
+ }
}
else
- zabbix_log(LOG_LEVEL_DEBUG, "'%s' does not match '%s'", logfile_candidate, format);
+ zabbix_log(LOG_LEVEL_DEBUG, "cannot process entry '%s'", logfile_candidate);
zbx_free(logfile_candidate);
}
#endif /*_WINDOWS*/
- if (1 == skip_old_data)
- i = logfiles_num ? logfiles_num - 1 : 0;
- else
- i = 0;
+ regfree(&re);
- /* find the oldest file that match */
- for ( ; i < logfiles_num; i++)
- {
- if (logfiles[i].mtime < *mtime)
- continue; /* not interested in mtimes less than the given mtime */
- else
- break; /* the first occurrence is found */
- }
+ i = (1 == *skip_old_data && 0 < logfiles_num) ? logfiles_num - 1 : 0;
/* escaping those with the same mtime, taking the latest one (without exceptions!) */
for (j = i + 1; j < logfiles_num; j++)
@@ -486,193 +543,441 @@ int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, char **
break; /* all next mtimes are bigger */
}
- /* if all mtimes are less than the given one, take the latest file from existing ones */
- if (0 < logfiles_num && i == logfiles_num)
- i = logfiles_num - 1; /* i cannot be bigger than logfiles_num */
-
- /* processing matched or moving to the newer one and repeating the cycle */
+ /* processing matched logfiles starting from the older one to the newer one */
for (; i < logfiles_num; i++)
{
logfile_candidate = zbx_dsprintf(logfile_candidate, "%s%s", directory, logfiles[i].filename);
- if (0 != zbx_stat(logfile_candidate, &file_buf))/* situation could have changed */
+
+ if (SUCCEED != (ret = process_log(logfile_candidate, lastlogsize, mtime, skip_old_data, big_rec,
+ encoding, regexps, pattern, output_template, p_count, s_count, process_value, server,
+ port, hostname, key)) || 0 >= *p_count || 0 >= *s_count)
{
- zabbix_log(LOG_LEVEL_WARNING, "cannot stat '%s': %s", logfile_candidate, zbx_strerror(errno));
- break; /* must return, situation could have changed */
+ /* Do not make a logrt[] item NOTSUPPORTED if one of selected files is not accessible */
+ /* (can happen during a rotation). Maybe during the next check all will be well. */
+ ret = SUCCEED;
+ break;
}
- if (1 == skip_old_data)
+ if (i != logfiles_num - 1)
{
- *lastlogsize = (zbx_uint64_t)file_buf.st_size;
- zabbix_log(LOG_LEVEL_DEBUG, "skipping existing filename:'%s' lastlogsize:" ZBX_FS_UI64,
- logfile_candidate, *lastlogsize);
+ zbx_free(logfile_candidate);
+ *lastlogsize = 0;
}
+ }
- *mtime = (int)file_buf.st_mtime; /* must contain the latest mtime as possible */
+ if (0 == logfiles_num)
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "there are no files matching '%s' in '%s'", format, directory);
- if (file_buf.st_size < *lastlogsize)
- *lastlogsize = 0; /* maintain backward compatibility */
+ /* do not make a logrt[] item NOTSUPPORTED if there are no matching files in the directory */
+ ret = SUCCEED;
+ }
- if (-1 == (fd = zbx_open(logfile_candidate, O_RDONLY)))
- {
- zabbix_log(LOG_LEVEL_WARNING, "cannot open '%s': %s", logfile_candidate, zbx_strerror(errno));
- break; /* must return, situation could have changed */
- }
+ free_logfiles(&logfiles, &logfiles_alloc, &logfiles_num);
#ifdef _WINDOWS
- if (-1L != _lseeki64(fd, (__int64)*lastlogsize, SEEK_SET))
+ if (0 != find_handle && -1 == _findclose(find_handle))
+ zabbix_log(LOG_LEVEL_WARNING, "cannot close the find directory handle: %s", zbx_strerror(errno));
#else
- if ((off_t)-1 != lseek(fd, (off_t)*lastlogsize, SEEK_SET))
+ if (NULL != dir && -1 == closedir(dir))
+ zabbix_log(LOG_LEVEL_WARNING, "cannot close directory '%s': %s", directory, zbx_strerror(errno));
#endif
+
+ zbx_free(logfile_candidate);
+ zbx_free(directory);
+ zbx_free(format);
+out:
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
+
+ return ret;
+}
+
+static char *buf_find_newline(char *p, char **p_next, const char *p_end, const char *cr, const char *lf,
+ size_t szbyte)
+{
+ if (1 == szbyte) /* single-byte character set */
+ {
+ for (; p < p_end; p++)
{
- if (-1 != (nbytes = zbx_read(fd, buffer, sizeof(buffer), encoding)))
+ if (0xd < *p || 0xa > *p)
+ continue;
+
+ if (0xa == *p) /* LF (Unix) */
{
- if (0 != nbytes)
+ *p_next = p + 1;
+ return p;
+ }
+
+ if (0xd == *p) /* CR (Mac) */
+ {
+ if (p < p_end - 1 && 0xa == *(p + 1)) /* CR+LF (Windows) */
{
- *lastlogsize += nbytes;
- *value = convert_to_utf8(buffer, nbytes, encoding);
- zbx_rtrim(*value, "\r\n ");
- ret = SUCCEED;
- break; /* return at this point */
+ *p_next = p + 2;
+ return p;
+ }
+
+ *p_next = p + 1;
+ return p;
+ }
+ }
+ return (char *)NULL;
+ }
+ else
+ {
+ while (p <= p_end - szbyte)
+ {
+ if (0 == memcmp(p, lf, szbyte)) /* LF (Unix) */
+ {
+ *p_next = p + szbyte;
+ return p;
+ }
+
+ if (0 == memcmp(p, cr, szbyte)) /* CR (Mac) */
+ {
+ if (p <= p_end - szbyte - szbyte && 0 == memcmp(p + szbyte, lf, szbyte))
+ {
+ /* CR+LF (Windows) */
+ *p_next = p + szbyte + szbyte;
+ return p;
}
- else /* EOF is reached, but there can be other files to try reading from */
+
+ *p_next = p + szbyte;
+ return p;
+ }
+
+ p += szbyte;
+ }
+ return (char *)NULL;
+ }
+}
+
+static int zbx_read2(int fd, zbx_uint64_t *lastlogsize, int *mtime, int *big_rec, const char *encoding,
+ zbx_vector_ptr_t *regexps, const char *pattern, const char *output_template, int *p_count, int *s_count,
+ zbx_process_value_func_t process_value, const char *server, unsigned short port, const char *hostname,
+ const char *key)
+{
+ int ret, nbytes;
+ const char *cr, *lf, *p_end;
+ char *p_start, *p, *p_nl, *p_next, *item_value = NULL;
+ size_t szbyte;
+ zbx_offset_t offset;
+ static char *buf = NULL;
+ int send_err;
+ zbx_uint64_t lastlogsize1;
+
+#define BUF_SIZE (256 * ZBX_KIBIBYTE) /* The longest encodings use 4-bytes for every character. To send */
+ /* up to 64 k characters to the Zabbix server a 256 kB buffer might */
+ /* be required. */
+ if (NULL == buf)
+ {
+ buf = zbx_malloc(buf, (size_t)(BUF_SIZE + 1));
+ }
+
+ find_cr_lf_szbyte(encoding, &cr, &lf, &szbyte);
+
+ for (;;)
+ {
+ if (0 >= *p_count || 0 >= *s_count)
+ {
+ /* limit on number of processed or sent-to-server lines reached */
+ ret = SUCCEED;
+ goto out;
+ }
+
+ if ((zbx_offset_t)-1 == (offset = zbx_lseek(fd, 0, SEEK_CUR)))
+ {
+ *big_rec = 0;
+ ret = FAIL;
+ goto out;
+ }
+
+ nbytes = (int)read(fd, buf, (size_t)BUF_SIZE);
+
+ if (-1 == nbytes)
+ {
+ /* error on read */
+ *big_rec = 0;
+ ret = FAIL;
+ goto out;
+ }
+
+ if (0 == nbytes)
+ {
+ /* end of file reached */
+ ret = SUCCEED;
+ goto out;
+ }
+
+ p_start = buf; /* beginning of current line */
+ p = buf; /* current byte */
+ p_end = buf + (size_t)nbytes; /* no data from this position */
+
+ if (NULL == (p_nl = buf_find_newline(p, &p_next, p_end, cr, lf, szbyte)))
+ {
+ if (BUF_SIZE > nbytes)
+ {
+ /* Buffer is not full (no more data available) and there is no "newline" in it. */
+ /* Do not analyze it now, keep the same position in the file and wait the next check, */
+ /* maybe more data will come. */
+
+ *lastlogsize = (zbx_uint64_t)offset;
+ ret = SUCCEED;
+ goto out;
+ }
+ else
+ {
+ /* buffer is full and there is no "newline" in it */
+
+ if (0 == *big_rec)
{
- if (i == logfiles_num - 1)
+ /* It is the first, beginning part of a long record. Match it against the */
+ /* regexp now (our buffer length corresponds to what we can save in the */
+ /* database). */
+
+ char *value = NULL;
+
+ buf[BUF_SIZE] = '\0';
+
+ if ('\0' != *encoding)
+ value = convert_to_utf8(buf, (size_t)BUF_SIZE, encoding);
+ else
+ value = buf;
+
+ zabbix_log(LOG_LEVEL_WARNING, "Logfile contains a large record: \"%.64s\""
+ " (showing only the first 64 characters). Only the first 64 kB"
+ " will be analyzed, the rest will be ignored while Zabbix agent"
+ " is running", value);
+
+ lastlogsize1 = (size_t)offset + (size_t)nbytes;
+ send_err = SUCCEED;
+
+ if (SUCCEED == regexp_sub_ex(regexps, value, pattern, ZBX_CASE_SENSITIVE,
+ output_template, &item_value))
{
- ret = SUCCEED; /* EOF of the most current file is reached */
- break;
+ send_err = process_value(server, port, hostname, key, item_value,
+ &lastlogsize1, mtime, NULL, NULL, NULL, NULL, 1);
+
+ zbx_free(item_value);
+
+ if (SUCCEED == send_err)
+ (*s_count)--;
}
- else
+ (*p_count)--;
+
+ if (SUCCEED == send_err)
{
- zbx_free(logfile_candidate);
- *lastlogsize = 0;
- close(fd);
- continue; /* try to read from a more current file */
+ *lastlogsize = lastlogsize1;
+ *big_rec = 1; /* ignore the rest of this record */
}
+
+ if ('\0' != *encoding)
+ zbx_free(value);
+ }
+ else
+ {
+ /* It is a middle part of a long record. Ignore it. We have already */
+ /* checked the first part against the regexp. */
+
+ *lastlogsize = (size_t)offset + (size_t)nbytes;
}
- }
- else /* cannot read from the file */
- {
- zabbix_log(LOG_LEVEL_WARNING, "cannot read from '%s': %s", logfile_candidate,
- zbx_strerror(errno));
- break; /* must return, situation could have changed */
}
}
- else /* cannot position in the file */
+ else
{
- zabbix_log(LOG_LEVEL_WARNING, "cannot set position to " ZBX_FS_UI64 " for file '%s': %s",
- *lastlogsize, logfile_candidate, zbx_strerror(errno));
- break; /* must return, situation could have changed */
- }
- } /* trying to read from logfiles */
+ /* the "newline" was found, so there is at least one complete record */
+ /* (or trailing part of a large record) in the buffer */
- if (0 == logfiles_num)
- zabbix_log(LOG_LEVEL_WARNING, "there are no files matching '%s' in '%s'", format, directory);
+ for (;;)
+ {
+ if (0 >= *p_count || 0 >= *s_count)
+ {
+ /* limit on number of processed or sent-to-server lines reached */
+ ret = SUCCEED;
+ goto out;
+ }
- free_logfiles(&logfiles, &logfiles_alloc, &logfiles_num);
- if (0 < fd && -1 == close(fd))
- zabbix_log(LOG_LEVEL_WARNING, "cannot close file '%s': %s", logfile_candidate, zbx_strerror(errno));
+ if (0 == *big_rec)
+ {
+ char *value = NULL;
-#ifdef _WINDOWS
- if (0 != find_handle && -1 == _findclose(find_handle))
- zabbix_log(LOG_LEVEL_WARNING, "cannot close the find directory handle: %s", zbx_strerror(errno));
-#else
- if (NULL != dir && -1 == closedir(dir))
- zabbix_log(LOG_LEVEL_WARNING, "cannot close directory '%s': %s", directory, zbx_strerror(errno));
-#endif
+ *p_nl = '\0';
- zbx_free(logfile_candidate);
- zbx_free(directory);
- zbx_free(format);
-out:
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
+ if ('\0' != *encoding)
+ value = convert_to_utf8(p_start, (size_t)(p_nl - p_start), encoding);
+ else
+ value = p_start;
+
+ lastlogsize1 = (size_t)offset + (size_t)(p_next - buf);
+ send_err = SUCCEED;
+
+ if (SUCCEED == regexp_sub_ex(regexps, value, pattern, ZBX_CASE_SENSITIVE,
+ output_template, &item_value))
+ {
+ send_err = process_value(server, port, hostname, key, item_value,
+ &lastlogsize1, mtime, NULL, NULL, NULL, NULL, 1);
+
+ zbx_free(item_value);
+
+ if (SUCCEED == send_err)
+ (*s_count)--;
+ }
+ (*p_count)--;
+
+ if (SUCCEED == send_err)
+ *lastlogsize = lastlogsize1;
+
+ if ('\0' != *encoding)
+ zbx_free(value);
+ }
+ else
+ {
+ /* skip the trailing part of a long record */
+ *lastlogsize = (size_t)offset + (size_t)(p_next - buf);
+ *big_rec = 0;
+ }
+
+ /* move to the next record in the buffer */
+ p_start = p_next;
+ p = p_next;
+ if (NULL == (p_nl = buf_find_newline(p, &p_next, p_end, cr, lf, szbyte)))
+ {
+ /* There are no complete records in the buffer. */
+ /* Try to read more data from this position if available. */
+ if ((zbx_offset_t)-1 == zbx_lseek(fd, *lastlogsize, SEEK_SET))
+ {
+ ret = FAIL;
+ goto out;
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+out:
return ret;
+
+#undef BUF_SIZE
}
/******************************************************************************
* *
* Function: process_log *
* *
- * Purpose: Get message from logfile WITHOUT rotation *
- * *
- * Parameters: filename - logfile name *
- * lastlogsize - offset for message *
- * value - pointer for logged message *
+ * Purpose: Match new records in logfile with regexp, transmit matching *
+ * records to Zabbix server *
+ * *
+ * Parameters: *
+ * filename - [IN] logfile name *
+ * lastlogsize - [IN/OUT] offset from the beginning of the file *
+ * mtime - [IN] file modification time for reporting to server *
+ * skip_old_data - [IN/OUT] start from the beginning of the file or *
+ * jump to the end *
+ * big_rec - [IN/OUT] state variable to remember whether a long *
+ * record is being processed *
+ * encoding - [IN] text string describing encoding. *
+ * The following encodings are recognized: *
+ * "UNICODE" *
+ * "UNICODEBIG" *
+ * "UNICODEFFFE" *
+ * "UNICODELITTLE" *
+ * "UTF-16" "UTF16" *
+ * "UTF-16BE" "UTF16BE" *
+ * "UTF-16LE" "UTF16LE" *
+ * "UTF-32" "UTF32" *
+ * "UTF-32BE" "UTF32BE" *
+ * "UTF-32LE" "UTF32LE". *
+ * "" (empty string) means a single-byte character *
+ * set (e.g. ASCII). *
+ * regexps - [IN] array of regexps *
+ * pattern - [IN] pattern to match *
+ * output_template - [IN] output formatting template *
+ * p_count - [IN/OUT] limit of records to be processed *
+ * s_count - [IN/OUT] limit of records to be sent to server *
+ * process_value - [IN] pointer to function process_value() *
+ * server - [IN] server to send data to *
+ * port - [IN] port to send data to *
+ * hostname - [IN] hostname the data comes from *
+ * key - [IN] item key the data belongs to *
* *
* Return value: returns SUCCEED on successful reading, *
* FAIL on other cases *
* *
* Author: Eugene Grigorjev *
* *
- * Comments: This function allocates memory for 'value', so use zbx_free(). *
- * Return SUCCEED and NULL 'value' if end of file received. *
+ * Comments: *
+ * This function does not deal with log file rotation. *
* *
******************************************************************************/
-int process_log(char *filename, zbx_uint64_t *lastlogsize, char **value, const char *encoding,
- unsigned char skip_old_data)
+int process_log(char *filename, zbx_uint64_t *lastlogsize, int *mtime, unsigned char *skip_old_data, int *big_rec,
+ const char *encoding, zbx_vector_ptr_t *regexps, const char *pattern, const char *output_template,
+ int *p_count, int *s_count, zbx_process_value_func_t process_value, const char *server,
+ unsigned short port, const char *hostname, const char *key)
{
const char *__function_name = "process_log";
- int f;
+ int f, ret = FAIL;
struct stat buf;
- int nbytes, ret = FAIL;
- char buffer[MAX_BUFFER_LEN];
-
- assert(NULL != filename);
- assert(NULL != lastlogsize);
- assert(NULL != value);
- assert(NULL != encoding);
+ zbx_uint64_t l_size;
- zabbix_log(LOG_LEVEL_DEBUG, "In %s() filename:'%s' lastlogsize:" ZBX_FS_UI64,
- __function_name, filename, *lastlogsize);
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s() filename:'%s' lastlogsize:" ZBX_FS_UI64 " mtime: %d",
+ __function_name, filename, *lastlogsize, NULL != mtime ? *mtime : 0);
- /* handling of file shrinking */
if (0 != zbx_stat(filename, &buf))
{
zabbix_log(LOG_LEVEL_WARNING, "cannot stat '%s': %s", filename, zbx_strerror(errno));
- return ret;
+ goto out;
}
- if (1 == skip_old_data)
+ if ((zbx_uint64_t)buf.st_size == *lastlogsize)
{
- *lastlogsize = (zbx_uint64_t)buf.st_size;
- zabbix_log(LOG_LEVEL_DEBUG, "skipping existing filename:'%s' lastlogsize:" ZBX_FS_UI64,
- filename, *lastlogsize);
+ /* The file size has not changed. Nothing to do. Here we do not deal with a case of changing */
+ /* a logfile's content while keeping the same length. */
+ ret = SUCCEED;
+ goto out;
}
- if (buf.st_size < *lastlogsize)
- *lastlogsize = 0;
-
if (-1 == (f = zbx_open(filename, O_RDONLY)))
{
zabbix_log(LOG_LEVEL_WARNING, "cannot open '%s': %s", filename, zbx_strerror(errno));
- return ret;
+ goto out;
}
-#ifdef _WINDOWS
- if (-1L != _lseeki64(f, (__int64)*lastlogsize, SEEK_SET))
-#else
- if ((off_t)-1 != lseek(f, (off_t)*lastlogsize, SEEK_SET))
-#endif
+ l_size = *lastlogsize;
+
+ if (1 == *skip_old_data)
{
- if (-1 != (nbytes = zbx_read(f, buffer, sizeof(buffer), encoding)))
- {
- if (0 != nbytes)
- {
- *lastlogsize += nbytes;
- *value = convert_to_utf8(buffer, nbytes, encoding);
- zbx_rtrim(*value, "\r\n ");
- }
- ret = SUCCEED;
- }
- else
- zabbix_log(LOG_LEVEL_WARNING, "cannot read from '%s': %s", filename, zbx_strerror(errno));
+ l_size = (zbx_uint64_t)buf.st_size;
+ zabbix_log(LOG_LEVEL_DEBUG, "skipping old data in filename:'%s' to lastlogsize:" ZBX_FS_UI64,
+ filename, l_size);
+ }
+
+ if ((zbx_uint64_t)buf.st_size < l_size) /* handle file truncation */
+ l_size = 0;
+
+ if ((zbx_offset_t)-1 != zbx_lseek(f, l_size, SEEK_SET))
+ {
+ *lastlogsize = l_size;
+ *skip_old_data = 0;
+
+ if (NULL != mtime)
+ *mtime = (int)buf.st_mtime;
+
+ ret = zbx_read2(f, lastlogsize, mtime, big_rec, encoding, regexps, pattern, output_template, p_count,
+ s_count, process_value, server, port, hostname, key);
}
else
+ {
zabbix_log(LOG_LEVEL_WARNING, "cannot set position to " ZBX_FS_UI64 " for '%s': %s",
- *lastlogsize, filename, zbx_strerror(errno));
+ l_size, filename, zbx_strerror(errno));
+ }
- close(f);
+ if (0 != close(f))
+ zabbix_log(LOG_LEVEL_WARNING, "cannot close file '%s': %s", filename, zbx_strerror(errno));
+out:
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s() filename:'%s' lastlogsize:" ZBX_FS_UI64 " mtime: %d ret:%s",
+ __function_name, filename, *lastlogsize, NULL != mtime ? *mtime : 0, zbx_result_string(ret));
return ret;
}
diff --git a/src/zabbix_agent/logfiles.h b/src/zabbix_agent/logfiles.h
index 674fa3c750a..b28dec98fdb 100644
--- a/src/zabbix_agent/logfiles.h
+++ b/src/zabbix_agent/logfiles.h
@@ -20,9 +20,16 @@
#ifndef ZABBIX_LOGFILES_H
#define ZABBIX_LOGFILES_H
-int process_log(char *filename, zbx_uint64_t *lastlogsize, char **value, const char *encoding,
- unsigned char skip_old_data);
-int process_logrt(char *fileformat, zbx_uint64_t *lastlogsize, int *mtime, char **value, const char *encoding,
- unsigned char skip_old_data);
+#include "zbxregexp.h"
+
+int process_log(char *filename, zbx_uint64_t *lastlogsize, int *mtime, unsigned char *skip_old_data, int *big_rec,
+ const char *encoding, zbx_vector_ptr_t *regexps, const char *pattern, const char *output_template,
+ int *p_count, int *s_count, zbx_process_value_func_t process_value, const char *server,
+ unsigned short port, const char *hostname, const char *key);
+
+int process_logrt(char *filename, zbx_uint64_t *lastlogsize, int *mtime, unsigned char *skip_old_data,
+ int *big_rec, const char *encoding, zbx_vector_ptr_t *regexps, const char *pattern,
+ const char *output_template, int *p_count, int *s_count, zbx_process_value_func_t process_value,
+ const char *server, unsigned short port, const char *hostname, const char *key);
#endif