zabbix优化之LLD Filter Multi-macro
提出问题:zabbix对文件系统的监控是通过LLD实现的,zabbix首先通过Discovery rule发现所有的文件系统名称和类型,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
shell# zabbix_get -s 127.0.0.1 -k vfs.fs.discovery
{
"data":[
{
"{#FSNAME}":"/",
"{#FSTYPE}":"rootfs"
},
{
"{#FSNAME}":"/proc",
"{#FSTYPE}":"proc"
},
{
"{#FSNAME}":"/sys",
"{#FSTYPE}":"sysfs"
},
{
"{#FSNAME}":"/dev",
"{#FSTYPE}":"devtmpfs"
},
{
"{#FSNAME}":"/dev/pts",
"{#FSTYPE}":"devpts"
},
{
"{#FSNAME}":"/dev/shm",
"{#FSTYPE}":"tmpfs"
},
{
"{#FSNAME}":"/",
"{#FSTYPE}":"ext4"
},
{
"{#FSNAME}":"/proc/bus/usb",
"{#FSTYPE}":"usbfs"
},
{
"{#FSNAME}":"/boot",
"{#FSTYPE}":"ext4"
},
{
"{#FSNAME}":"/data",
"{#FSTYPE}":"ext4"
},
{
"{#FSNAME}":"/proc/sys/fs/binfmt_misc",
"{#FSTYPE}":"binfmt_misc"
}
]
}
然后通过在Discovery rule中配置的宏过滤规则(Filter Macro),把不需要监控的文件系统类型过滤掉,见下图。
上图是zabbix默认的配置,通过宏{#FSTYPE}和正则表达式“File systems for discovery”过滤文件系统类型。
现在问题来了,如果我想同时根据{#FSNAME}这个宏过滤掉一些我不关心的文件系统,该怎么办?
分析问题:
zabbix在Discovery rule中只能过滤单个宏,不支持多宏过滤的写法,因此上述需求就无法实现了。
但是通过修改zabbix底层C代码,可以支持多宏过滤的。
规定参数写法:
Macro 多个宏变量之间用逗号分隔;
Regexp 正则表达式名前面加'@',多个表达式之间也用逗号分隔;
相同位置的宏变量和正则表达式是对应的,即第一个宏对应第一个正则表达式,第二个宏对应第二个正则表达式...
填写方式如下:
解决方法:
建议先在自己的测试环境中修改,测试成功后再应用到生产环境。
第一步,下载附件,改名为lld.c。如果你的zabbix版本是2.2.5,下载源码安装包,解压:
1
shell# tar xvzf zabbix-2.2.5.tar.gz
第二步,把上面下载的lld.c文件覆盖掉zabbix原始lld.c文件,zabbix2.2.2及以上版本可直接覆盖:
1
shell# \cp lld.c zabbix-2.2.5/src/libs/zbxdbhigh/lld.c
第三步,编译zabbix server:
1
2
3
shell# cd zabbix-2.2.5
shell# ./configure --prefix=/etc/zabbix --with-mysql --with-net-snmp --with-libcurl --with-openipmi --with-ssh2 --enable-server
shell# make
没有报错的话,编译成功~见下图
第四步,停掉zabbix server服务,备份zabbix_server主程序
1
2
shell# /etc/init.d/zabbix-server stop
shell# cp /usr/sbin/zabbix_server /usr/sbin/zabbix_server.bak
第五步,将编译好的zabbix_server覆盖原zabbix_server主程序,启动zabbix server服务
1
2
shell# cp src/zabbix_server/zabbix_server /usr/sbin/zabbix_server
shell# /etc/init.d/zabbix-server start
测试结果:
第一步:只过滤{#FSTYPE},配置Discovery rule如下:
监控间隔设置120秒,"Keep lost resources period"设置为0,方便观察结果。
"Filter Macro"填写"{#FSTYPE}";"Regexp"填写"@File systems for discovery"。
查看监控项组Filesystems下的监控项:
第二步:同时过滤{#FSTYPE}和{#FSNAME},使{#FSNAME}过滤掉boot目录
先创建正则表达式"Filter file system name":
配置Discovery rule:
"Filter Macro"填写"{#FSTYPE},{#FSNAME}";
"Regexp"填写"@File systems for discovery,@Filter file system name"。
注意:这里是英文的逗号','。
大约120秒后,查看监控项组Filesystems下的监控项:
发现boot目录已经被过滤掉了。测试完成。
=====================================================================================================
附:lld.c主要修改部分截图,右侧是优化后的
优化后的lld.c
/*
** Zabbix
** Copyright (C) 2001-2014 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 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 General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA02110-1301, USA.
**/
#include "lld.h"
#include "db.h"
#include "log.h"
#include "events.h"
#include "zbxalgo.h"
#include "zbxserver.h"
#include "zbxregexp.h"
static int lld_check_record(struct zbx_json_parse *jp_row, const char *f_macro, const char *f_regexp,
zbx_vector_ptr_t *regexps)
{
const char *__function_name = "lld_check_record";
char *value = NULL;
size_t value_alloc = 0;
int res = SUCCEED;
zabbix_log(LOG_LEVEL_DEBUG, "In %s() jp_row:'%.*s'", __function_name,
jp_row->end - jp_row->start + 1, jp_row->start);
if (SUCCEED == zbx_json_value_by_name_dyn(jp_row, f_macro, &value, &value_alloc))
res = regexp_match_ex(regexps, value, f_regexp, ZBX_CASE_SENSITIVE);
zbx_free(value);
zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
return res;
}
static int lld_rows_get(char *value, char *filter, zbx_vector_ptr_t *lld_rows, char **error)
{
const char *__function_name = "lld_rows_get";
struct zbx_json_parse jp, jp_data, jp_row;
char *f_macros_all = NULL, *f_regexps_all = NULL;
char *f_macros = NULL, *f_regexps = NULL;
char *f_macros_n = NULL, *f_regexps_n = NULL;
char *f_macro = NULL, *f_regexp = NULL;
const char *p;
zbx_vector_ptr_t regexps;
zbx_lld_row_t *lld_row;
int ret = FAIL, filter_out = FAIL;
zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
if (SUCCEED != zbx_json_open(value, &jp))
{
*error = zbx_strdup(*error, "Value should be a JSON object.");
goto out;
}
/* {"data":[{"{#IFNAME}":"eth0"},{"{#IFNAME}":"lo"},...]} */
/* ^-------------------------------------------^*/
if (SUCCEED != zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
{
*error = zbx_dsprintf(*error, "Cannot find the \"%s\" array in the received JSON object.",
ZBX_PROTO_TAG_DATA);
goto out;
}
zbx_vector_ptr_create(®exps);
if (NULL != (f_regexps_all= strchr(filter, ':')))
{
f_macros_all= filter;
*f_regexps_all++ = '\0';
zabbix_log(LOG_LEVEL_DEBUG, "%s() f_macros_all:'%s' f_regexps_all:'%s'", __function_name, f_macros_all, f_regexps_all);
}
f_macros = zbx_malloc(NULL, strlen(f_macros_all) + 1);
f_regexps = zbx_malloc(NULL, strlen(f_regexps_all) + 1);
p = NULL;
/* {"data":[{"{#IFNAME}":"eth0"},{"{#IFNAME}":"lo"},...]} */
/* ^ */
while (NULL != (p = zbx_json_next(&jp_data, p)))
{
/* {"data":[{"{#IFNAME}":"eth0"},{"{#IFNAME}":"lo"},...]} */
/* ^------------------^ */
if (FAIL == zbx_json_brackets_open(p, &jp_row))
continue;
f_macros_n = f_macros;
f_regexps_n = f_regexps;
zbx_strlcpy(f_macros_n, f_macros_all, strlen(f_macros_all) + 1);
zbx_strlcpy(f_regexps_n, f_regexps_all, strlen(f_regexps_all) + 1);
while (NULL != f_macros_n && NULL != f_regexps_n)
{
f_macro = f_macros_n;
if(NULL != (f_macros_n = strchr(f_macros_n, ',')))
*f_macros_n++ = '\0';
f_regexp = f_regexps_n;
if(NULL != (f_regexps_n = strchr(f_regexps_n, ',')))
*f_regexps_n++ = '\0';
if ('@' == *f_regexp)
DCget_expressions_by_name(®exps, f_regexp + 1);
zabbix_log(LOG_LEVEL_DEBUG, "%s() f_macro:'%s' f_regexp:'%s'", __function_name, f_macro, f_regexp);
if (NULL != f_macro && SUCCEED != lld_check_record(&jp_row, f_macro, f_regexp, ®exps))
{
filter_out = SUCCEED;
break;
}
}
if (filter_out == SUCCEED)
{
filter_out = FAIL;
continue;
}
lld_row = zbx_malloc(NULL, sizeof(zbx_lld_row_t));
memcpy(&lld_row->jp_row, &jp_row, sizeof(struct zbx_json_parse));
zbx_vector_ptr_create(&lld_row->item_links);
zbx_vector_ptr_append(lld_rows, lld_row);
}
zbx_free(f_macros);
zbx_free(f_regexps);
zbx_regexp_clean_expressions(®exps);
zbx_vector_ptr_destroy(®exps);
ret = SUCCEED;
out:
zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
return ret;
}
static void lld_item_link_free(zbx_lld_item_link_t *item_link)
{
zbx_free(item_link);
}
static void lld_row_free(zbx_lld_row_t *lld_row)
{
zbx_vector_ptr_clean(&lld_row->item_links, (zbx_mem_free_func_t)lld_item_link_free);
zbx_vector_ptr_destroy(&lld_row->item_links);
zbx_free(lld_row);
}
/******************************************************************************
* *
* Function: lld_process_discovery_rule *
* *
* Purpose: add or update items, triggers and graphs for discovery item *
* *
* Parameters: lld_ruleid - discovery item identificator from database *
* value - received value from agent *
* *
******************************************************************************/
void lld_process_discovery_rule(zbx_uint64_t lld_ruleid, char *value, zbx_timespec_t *ts)
{
const char *__function_name = "lld_process_discovery_rule";
DB_RESULT result;
DB_ROW row;
zbx_uint64_t hostid = 0;
char *discovery_key = NULL, *filter = NULL, *error = NULL, *db_error = NULL, *error_esc;
unsigned char state = 0;
unsigned short lifetime;
zbx_vector_ptr_t lld_rows;
char *sql = NULL;
size_t sql_alloc = 128, sql_offset = 0;
const char *sql_start = "update items set ", *sql_continue = ",";
zabbix_log(LOG_LEVEL_DEBUG, "In %s() itemid:" ZBX_FS_UI64, __function_name, lld_ruleid);
zbx_vector_ptr_create(&lld_rows);
sql = zbx_malloc(sql, sql_alloc);
result = DBselect(
"select hostid,key_,state,filter,error,lifetime"
" from items"
" where itemid=" ZBX_FS_UI64,
lld_ruleid);
if (NULL != (row = DBfetch(result)))
{
char *lifetime_str;
ZBX_STR2UINT64(hostid, row);
discovery_key = zbx_strdup(discovery_key, row);
state = (unsigned char)atoi(row);
filter = zbx_strdup(filter, row);
db_error = zbx_strdup(db_error, row);
lifetime_str = zbx_strdup(NULL, row);
substitute_simple_macros(NULL, NULL, NULL, NULL, &hostid, NULL, NULL,
&lifetime_str, MACRO_TYPE_COMMON, NULL, 0);
if (SUCCEED != is_ushort(lifetime_str, &lifetime))
{
zabbix_log(LOG_LEVEL_WARNING, "cannot process lost resources for the discovery rule \"%s:%s\":"
" \"%s\" is not a valid value",
zbx_host_string(hostid), discovery_key, lifetime_str);
lifetime = 3650; /* max value for the field */
}
zbx_free(lifetime_str);
}
else
zabbix_log(LOG_LEVEL_WARNING, "invalid discovery rule ID [" ZBX_FS_UI64 "]", lld_ruleid);
DBfree_result(result);
if (0 == hostid)
goto clean;
zabbix_log(LOG_LEVEL_WARNING, "%s() discovery_key:'%s' filter:'%s'", __function_name, discovery_key, filter);
if (SUCCEED != lld_rows_get(value, filter, &lld_rows, &error))
goto error;
error = zbx_strdup(error, "");
lld_update_items(hostid, lld_ruleid, &lld_rows, &error, lifetime, ts->sec);
lld_update_triggers(hostid, lld_ruleid, &lld_rows, &error);
lld_update_graphs(hostid, lld_ruleid, &lld_rows, &error);
lld_update_hosts(lld_ruleid, &lld_rows, &error, lifetime, ts->sec);
if (ITEM_STATE_NOTSUPPORTED == state)
{
zabbix_log(LOG_LEVEL_WARNING,"discovery rule [" ZBX_FS_UI64 "][%s] became supported",
lld_ruleid, zbx_host_key_string(lld_ruleid));
add_event(0, EVENT_SOURCE_INTERNAL, EVENT_OBJECT_LLDRULE, lld_ruleid, ts, ITEM_STATE_NORMAL,
NULL, NULL, 0, 0);
process_events();
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sstate=%d", sql_start, ITEM_STATE_NORMAL);
sql_start = sql_continue;
}
error:
if (NULL != error && 0 != strcmp(error, db_error))
{
error_esc = DBdyn_escape_string_len(error, ITEM_ERROR_LEN);
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%serror='%s'", sql_start, error_esc);
sql_start = sql_continue;
zbx_free(error_esc);
}
if (sql_start == sql_continue)
{
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where itemid=" ZBX_FS_UI64, lld_ruleid);
DBbegin();
DBexecute("%s", sql);
DBcommit();
}
clean:
zbx_free(error);
zbx_free(db_error);
zbx_free(filter);
zbx_free(discovery_key);
zbx_free(sql);
zbx_vector_ptr_clean(&lld_rows, (zbx_mem_free_func_t)lld_row_free);
zbx_vector_ptr_destroy(&lld_rows);
zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
}
页:
[1]