From da6e2f9ab21101af9e70b17a27caf5f4c982fb48 Mon Sep 17 00:00:00 2001 From: Wetp Zhang Date: Wed, 16 Feb 2022 18:57:04 +0800 Subject: [PATCH 1/4] fix dependence check for ccbpf Signed-off-by: Wetp Zhang --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 75054c77..01953ca3 100755 --- a/configure +++ b/configure @@ -148,7 +148,7 @@ if [ $? = 0 ]; then echo "$target_path need lkm" fi -grep -nrw "bpf.mk" $file > /dev/null +grep -nr "bpf.mk" $file > /dev/null if [ $? = 0 ]; then enable_libbpf="YES" echo "$target_path need libbpf" -- Gitee From bc59e0e9314fbe6cc15a20ad671ec839118d2361 Mon Sep 17 00:00:00 2001 From: Wetp Zhang Date: Wed, 16 Feb 2022 18:58:48 +0800 Subject: [PATCH 2/4] add submod support Signed-off-by: Wetp Zhang --- source/mk/submod.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/mk/submod.mk b/source/mk/submod.mk index 237c1ec6..429348fe 100644 --- a/source/mk/submod.mk +++ b/source/mk/submod.mk @@ -5,8 +5,7 @@ TARGET_PATH := $(OBJ_TOOLS_ROOT) endif $(target): - make -C $(SUBMOD_SRC) $(MAKE_ARGS) - cp $(target) $(TARGET_PATH)/ + make -C $(SUBMOD_SRC) $(MAKE_ARGS) INSTALL_PRE=$(TARGET_PATH) install echo $(target):$(DEPEND) >> $(OBJ_TOOLS_PATH)/$(SYSAK_RULES) .PHONY: $(target) -- Gitee From 7acb2f697c640d0b0080e1559fec0b25b5d8440c Mon Sep 17 00:00:00 2001 From: Wetp Zhang Date: Wed, 16 Feb 2022 19:05:02 +0800 Subject: [PATCH 3/4] add sysak mservice Signed-off-by: Wetp Zhang --- Makefile | 8 + source/tools/monitor/mservice/Makefile | 4 + .../tools/monitor/mservice/master/.gitignore | 9 + source/tools/monitor/mservice/master/AUTHORS | 10 + source/tools/monitor/mservice/master/COPYING | 201 +++ .../tools/monitor/mservice/master/ChangeLog | 12 + source/tools/monitor/mservice/master/INSTALL | 22 + source/tools/monitor/mservice/master/Makefile | 24 + .../tools/monitor/mservice/master/README.cn | 128 ++ .../tools/monitor/mservice/master/README.md | 136 ++ .../mservice/master/conf/sysakmon.conf | 59 + .../mservice/master/devel/Makefile.test | 21 + .../monitor/mservice/master/devel/mod_test.c | 84 ++ .../mservice/master/devel/mod_test.conf | 15 + .../monitor/mservice/master/devel/tsar.h | 121 ++ .../monitor/mservice/master/devel/tsardevel | 43 + .../monitor/mservice/master/include/common.h | 37 + .../monitor/mservice/master/include/config.h | 93 ++ .../monitor/mservice/master/include/debug.h | 40 + .../monitor/mservice/master/include/define.h | 148 ++ .../mservice/master/include/framework.h | 88 ++ .../mservice/master/include/output_db.h | 34 + .../mservice/master/include/output_file.h | 42 + .../mservice/master/include/output_http.h | 7 + .../mservice/master/include/output_nagios.h | 34 + .../mservice/master/include/output_print.h | 35 + .../mservice/master/include/output_tcp.h | 32 + .../monitor/mservice/master/include/public.h | 301 ++++ .../monitor/mservice/master/include/tsar.h | 61 + source/tools/monitor/mservice/master/info.md | 524 +++++++ .../monitor/mservice/master/modules/Makefile | 30 + .../mservice/master/modules/mod_apache.c | 151 ++ .../monitor/mservice/master/modules/mod_cpu.c | 167 +++ .../mservice/master/modules/mod_haproxy.c | 415 ++++++ .../monitor/mservice/master/modules/mod_io.c | 345 +++++ .../mservice/master/modules/mod_load.c | 92 ++ .../monitor/mservice/master/modules/mod_lvs.c | 231 ++++ .../monitor/mservice/master/modules/mod_mem.c | 126 ++ .../mservice/master/modules/mod_ncpu.c | 119 ++ .../mservice/master/modules/mod_nginx.c | 290 ++++ .../mservice/master/modules/mod_partition.c | 139 ++ .../mservice/master/modules/mod_pcsw.c | 67 + .../mservice/master/modules/mod_percpu.c | 129 ++ .../mservice/master/modules/mod_pernic.c | 90 ++ .../mservice/master/modules/mod_proc.c | 216 +++ .../mservice/master/modules/mod_squid.c | 656 +++++++++ .../mservice/master/modules/mod_swap.c | 100 ++ .../monitor/mservice/master/modules/mod_tcp.c | 113 ++ .../mservice/master/modules/mod_tcpx.c | 137 ++ .../mservice/master/modules/mod_traffic.c | 114 ++ .../monitor/mservice/master/modules/mod_udp.c | 73 + .../monitor/mservice/master/src/.gitignore | 1 + .../monitor/mservice/master/src/Makefile | 31 + .../monitor/mservice/master/src/common.c | 281 ++++ .../monitor/mservice/master/src/config.c | 436 ++++++ .../tools/monitor/mservice/master/src/debug.c | 51 + .../monitor/mservice/master/src/framework.c | 531 +++++++ .../monitor/mservice/master/src/httpserver.c | 115 ++ .../monitor/mservice/master/src/output_db.c | 216 +++ .../monitor/mservice/master/src/output_file.c | 68 + .../mservice/master/src/output_nagios.c | 166 +++ .../mservice/master/src/output_print.c | 1225 +++++++++++++++++ .../monitor/mservice/master/src/output_tcp.c | 117 ++ .../tools/monitor/mservice/master/src/tsar.c | 369 +++++ .../monitor/mservice/master/tools/bytes.sh | 29 + .../monitor/mservice/master/tools/cpu.sh | 30 + .../monitor/mservice/master/tools/load.sh | 27 + .../monitor/mservice/master/tools/mem.sh | 31 + .../monitor/mservice/master/tools/packets.sh | 28 + .../monitor/mservice/master/tools/readme.txt | 26 + .../monitor/mservice/master/tools/retran.sh | 29 + 71 files changed, 9980 insertions(+) create mode 100644 source/tools/monitor/mservice/Makefile create mode 100644 source/tools/monitor/mservice/master/.gitignore create mode 100644 source/tools/monitor/mservice/master/AUTHORS create mode 100644 source/tools/monitor/mservice/master/COPYING create mode 100644 source/tools/monitor/mservice/master/ChangeLog create mode 100644 source/tools/monitor/mservice/master/INSTALL create mode 100644 source/tools/monitor/mservice/master/Makefile create mode 100644 source/tools/monitor/mservice/master/README.cn create mode 100644 source/tools/monitor/mservice/master/README.md create mode 100644 source/tools/monitor/mservice/master/conf/sysakmon.conf create mode 100644 source/tools/monitor/mservice/master/devel/Makefile.test create mode 100644 source/tools/monitor/mservice/master/devel/mod_test.c create mode 100644 source/tools/monitor/mservice/master/devel/mod_test.conf create mode 100644 source/tools/monitor/mservice/master/devel/tsar.h create mode 100755 source/tools/monitor/mservice/master/devel/tsardevel create mode 100644 source/tools/monitor/mservice/master/include/common.h create mode 100644 source/tools/monitor/mservice/master/include/config.h create mode 100644 source/tools/monitor/mservice/master/include/debug.h create mode 100644 source/tools/monitor/mservice/master/include/define.h create mode 100644 source/tools/monitor/mservice/master/include/framework.h create mode 100644 source/tools/monitor/mservice/master/include/output_db.h create mode 100644 source/tools/monitor/mservice/master/include/output_file.h create mode 100644 source/tools/monitor/mservice/master/include/output_http.h create mode 100644 source/tools/monitor/mservice/master/include/output_nagios.h create mode 100644 source/tools/monitor/mservice/master/include/output_print.h create mode 100644 source/tools/monitor/mservice/master/include/output_tcp.h create mode 100644 source/tools/monitor/mservice/master/include/public.h create mode 100644 source/tools/monitor/mservice/master/include/tsar.h create mode 100644 source/tools/monitor/mservice/master/info.md create mode 100644 source/tools/monitor/mservice/master/modules/Makefile create mode 100644 source/tools/monitor/mservice/master/modules/mod_apache.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_cpu.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_haproxy.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_io.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_load.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_lvs.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_mem.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_ncpu.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_nginx.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_partition.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_pcsw.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_percpu.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_pernic.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_proc.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_squid.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_swap.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_tcp.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_tcpx.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_traffic.c create mode 100644 source/tools/monitor/mservice/master/modules/mod_udp.c create mode 100644 source/tools/monitor/mservice/master/src/.gitignore create mode 100644 source/tools/monitor/mservice/master/src/Makefile create mode 100644 source/tools/monitor/mservice/master/src/common.c create mode 100644 source/tools/monitor/mservice/master/src/config.c create mode 100644 source/tools/monitor/mservice/master/src/debug.c create mode 100644 source/tools/monitor/mservice/master/src/framework.c create mode 100644 source/tools/monitor/mservice/master/src/httpserver.c create mode 100644 source/tools/monitor/mservice/master/src/output_db.c create mode 100644 source/tools/monitor/mservice/master/src/output_file.c create mode 100644 source/tools/monitor/mservice/master/src/output_nagios.c create mode 100644 source/tools/monitor/mservice/master/src/output_print.c create mode 100644 source/tools/monitor/mservice/master/src/output_tcp.c create mode 100644 source/tools/monitor/mservice/master/src/tsar.c create mode 100755 source/tools/monitor/mservice/master/tools/bytes.sh create mode 100755 source/tools/monitor/mservice/master/tools/cpu.sh create mode 100755 source/tools/monitor/mservice/master/tools/load.sh create mode 100755 source/tools/monitor/mservice/master/tools/mem.sh create mode 100755 source/tools/monitor/mservice/master/tools/packets.sh create mode 100644 source/tools/monitor/mservice/master/tools/readme.txt create mode 100755 source/tools/monitor/mservice/master/tools/retran.sh diff --git a/Makefile b/Makefile index ba72b231..50a486f1 100644 --- a/Makefile +++ b/Makefile @@ -57,3 +57,11 @@ $(OBJ_TOOLS_PATH): install: cp $(OBJPATH)/sysak /usr/local/sbin/ cp $(OBJPATH)/.sysak_compoents /usr/local/sbin/ -rf + mkdir -p /etc/sysak + mkdir -p /var/log/sysak + cp $(OBJPATH)/.sysak_compoents/tools/monitor/sysakmon.conf /etc/sysak/ + +uninstall: + rm -rf /etc/sysak + rm -rf /usr/local/sbin/sysak + rm -rf /usr/local/sbin/.sysak_compoents diff --git a/source/tools/monitor/mservice/Makefile b/source/tools/monitor/mservice/Makefile new file mode 100644 index 00000000..ae753b0f --- /dev/null +++ b/source/tools/monitor/mservice/Makefile @@ -0,0 +1,4 @@ +target := mservice +SUBMOD_SRC := master + +include $(SRC)/mk/submod.mk diff --git a/source/tools/monitor/mservice/master/.gitignore b/source/tools/monitor/mservice/master/.gitignore new file mode 100644 index 00000000..16df7e1a --- /dev/null +++ b/source/tools/monitor/mservice/master/.gitignore @@ -0,0 +1,9 @@ +*.o +*.so +*.so.* +tags +src/tsar +*.DS_Store +*.dSYM +cscope.out +ttsar.sh diff --git a/source/tools/monitor/mservice/master/AUTHORS b/source/tools/monitor/mservice/master/AUTHORS new file mode 100644 index 00000000..c4e4bcbd --- /dev/null +++ b/source/tools/monitor/mservice/master/AUTHORS @@ -0,0 +1,10 @@ +#This file contains a list of people who've made non-trivial +# contribution to the Tsar project. People who commit code +# to the project are encouraged to add their names here. +# Please keep the list sorted by first names. + +kongjian +kuotai +yonghao +zituan +huiyan.jhf diff --git a/source/tools/monitor/mservice/master/COPYING b/source/tools/monitor/mservice/master/COPYING new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/source/tools/monitor/mservice/master/COPYING @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/source/tools/monitor/mservice/master/ChangeLog b/source/tools/monitor/mservice/master/ChangeLog new file mode 100644 index 00000000..fed64ce8 --- /dev/null +++ b/source/tools/monitor/mservice/master/ChangeLog @@ -0,0 +1,12 @@ +2015-12-14 +* 增加了tsar -w 功能 +2015-07-27 +* output_tcp 增加了多目的发送功能,目前最多支持4个地址,以空格隔开 +2013-03-06 +* tsar的模块支持参数配置 +2013-01-23 +* tsar支持--spec功能,可以指定特定字段来显示 +2013-01-16 +* merge inner and opensource tsar version +2011-05-18 +* tsar opensourced diff --git a/source/tools/monitor/mservice/master/INSTALL b/source/tools/monitor/mservice/master/INSTALL new file mode 100644 index 00000000..383467fa --- /dev/null +++ b/source/tools/monitor/mservice/master/INSTALL @@ -0,0 +1,22 @@ +Simple install procedure +======================== + + % gzip -cd tsar-2.1.0.tar.gz | tar xvf - # unpack the sources + % cd tsar-2.1.0 # change to the toplevel directory + % make # build tsar + + [ Become root if necessary ] + % make install # install tsar + % make uninstall # uninstall tsar + [ if you want install tsardevel ] + % make tsardevel + % make uninstall + +RPM install +======================== + + %gzip -cd tsar-2.1.0.tar.gz | tar xvf - # unpack the sources + %cd tsar-2.1.0/rpm # change to the rpm directory + %sh tsar-build.sh .. tsar 2.1.0 1 # create rpm for tsar + %rpm -ivh *.rpm # install tsar by rpm + diff --git a/source/tools/monitor/mservice/master/Makefile b/source/tools/monitor/mservice/master/Makefile new file mode 100644 index 00000000..08db2a37 --- /dev/null +++ b/source/tools/monitor/mservice/master/Makefile @@ -0,0 +1,24 @@ +DIRS = src modules + +all: + for i in $(DIRS); do make -C $$i; done + +clean: + for i in $(DIRS); do cd $$i;make clean;cd ..; done + +install: all + #mkdir for mservice + mkdir -p $(INSTALL_PRE)/monitor/modules + #copy shared so + cp modules/*.so $(INSTALL_PRE)/monitor/modules/ + #copy bin file + cp src/mservice $(INSTALL_PRE)/ + #copy config file + cp conf/sysakmon.conf $(INSTALL_PRE)/monitor/ + +uninstall: + #rm tsar + rm -rf $(INSTALL_PRE)/monitor/ + rm -rf $(INSTALL_PRE)/mservice + +.PHONY: all clean install unintall diff --git a/source/tools/monitor/mservice/master/README.cn b/source/tools/monitor/mservice/master/README.cn new file mode 100644 index 00000000..1b922d16 --- /dev/null +++ b/source/tools/monitor/mservice/master/README.cn @@ -0,0 +1,128 @@ +Tsar介绍 +------------ +Tsar是淘宝的一个用来收集服务器系统和应用信息的采集报告工具,如收集服务器的系统信息(cpu,mem等),以及应用数据(nginx、swift等),收集到的数据存储在服务器磁盘上,可以随时查询历史信息,也可以将数据发送到nagios报警。 + +Tsar能够比较方便的增加模块,只需要按照tsar的要求编写数据的采集函数和展现函数,就可以把自定义的模块加入到tsar中。 + +安装 +------------- +Tsar目前托管在github上,下载编译安装步骤: + + $git clone git://github.com/kongjian/tsar.git + $cd tsar + $make + $make install + +安装后: + +定时任务配置:`/etc/cron.d/tsar`,负责每分钟调用tsar执行采集任务; + +日志文件轮转配置:`/etc/logrotate.d/tsar`,每个月会把tsar的本地存储进行轮转; + +Tsar配置文件路径:`/etc/tsar/tsar.conf`,tsar的采集模块和输出的具体配置; + +模块路径:`/usr/local/tsar/modules`,各个模块的动态库so文件; + +Tsar配置 +------------- +Tsar刚安装完,还没有历史数据,想要check是否正常,执行tsar -l,查看是否有实时信息输出: + + [kongjian@v132172.sqa.cm4 tsar]$ tsar -l -i 1 + Time ---cpu-- ---mem-- ---tcp-- -----traffic---- --xvda-- -xvda1-- -xvda2-- -xvda3-- -xvda4-- -xvda5-- ---load- + Time util util retran pktin pktout util util util util util util load1 + 11/04/13-14:09:10 0.20 11.57 0.00 9.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 + 11/04/13-14:09:11 0.20 11.57 0.00 4.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 + +Tsar的配置主要都在`/etc/tsar/tsar.conf`中,常用的有: +* 增加一个模块,添加 `mod_ on` 到配置文件中 +* 打开或者关闭一个模块,修改`mod_ on/off` +* `output_stdio_mod` 能够配置执行tsar时的输出模块 +* `output_file_path` 采集到的数据默认保存到的文件(如果修改的话需要对应修改轮转的配置`/etc/logrotate.d/tsar`) +* `output_interface` 指定tsar的数据输出目的,默认file保存本地,nagios/db输出到监控中心/数据库中,这两个功能还需要结合其它配置,具体见后面 + +Tsar使用 +------------- +* 查看历史数据,tsar +* -l/--list 查看可用的模块列表 +* -l/--live 查看实时数据,tsar -l --cpu +* -i/--interval 指定间隔,历史,tsar -i 1 --cpu +* --modname 指定模块,tsar --cpu +* -s/--spec 指定字段,tsar --cpu -s sys,util +* -d/--date 指定日期,YYYYMMDD或者n代表n天前 +* -C/--check 查看最后一次的采集数据 +* -d/--detail 能够指定查看主要字段还是模块的所有字段 +* -h/--help 帮助功能 + +高级功能 +------------- +* 输出到nagios + +配置: +首先配置`output_interface file,nagios`,增加nagios输出 + +然后配置nagios服务器和端口,以及发送的间隔时间 + + ####The IP address or the host running the NSCA daemon + server_addr nagios.server.com + ####The port on which the daemon is running - default is 5667 + server_port 8086 + ####The cycle of send alert to nagios + cycle_time 300 + +由于是nagios的被动监控模式,需要制定nsca的位置和配置文件位置 + + ####nsca client program + send_nsca_cmd /usr/bin/send_nsca + send_nsca_conf /home/a/conf/amon/send_nsca.conf + +接下来制定哪些模块和字段需要进行监控,一共四个阀值对应nagios中的不同报警级别 + + ####tsar mod alert config file + ####threshold servicename.key;w-min;w-max;c-min;cmax; + threshold cpu.util;50;60;70;80; + +* 输出到mysql + +配置: +首先配置`output_interface file,db`,增加db输出 + +然后配置哪些模块数据需要输出 + + output_db_mod mod_cpu,mod_mem,mod_traffic,mod_load,mod_tcp,mod_udpmod_io + +然后配置sql语句发送的目的地址和端口 + + output_db_addr console2:56677 + +目的地址在该端口监听tcp数据,并且把数据入库即可,可以参照tsar2db:https://github.com/kongjian/tsar2db + +模块开发 +------------- +Tsar的一个比较好的功能是能够增加自己的采集,这时候需要编写模块代码,编译成so文件即可。 + +C模块 +----- +首先安装tsardevel,刚才安装时,如果执行`make tsardevel`,就会把模块开发的基本文件安装到系统 +然后执行tsardevel ,就能在当前模块生成一个模块目录: + +````bash +[kongjian@v132172.sqa.cm4 tsar]$ tsardevel test +build:make +install:make install +uninstall:make uninstall + +[kongjian@v132172.sqa.cm4 tsar]$ ls test +Makefile mod_test.c mod_test.conf +```` + +按照要求修改mod_test.c中的read_test_stats,set_test_record +完成后`make;make install`就完成新模块的配置文件和so的设置,执行`tsar --yourmodname`就能查看效果 + +另外也可以通过配置文件对自定义模块传递参数,方法是 +修改配置文件中的`mod_test on myparameter` +然后在mod_test.c中的read_test_stats函数中,通过parameter参数就可以获得刚才配置文件中的内容 + +其它 +------------- +Taocode地址:http://code.taobao.org/p/tsar/ +有其它问题请联系:kongjian@taobao.com diff --git a/source/tools/monitor/mservice/master/README.md b/source/tools/monitor/mservice/master/README.md new file mode 100644 index 00000000..28d3b92d --- /dev/null +++ b/source/tools/monitor/mservice/master/README.md @@ -0,0 +1,136 @@ +Introduction +------------ +Tsar (Taobao System Activity Reporter) is a monitoring tool, which can be used to gather and summarize system information, e.g. CPU, load, IO, and application information, e.g. nginx, HAProxy, Squid, etc. The results can be stored at local disk or sent to Nagios. + +Tsar can be easily extended by writing modules, which makes it a powerful and versatile reporting tool. + +Module introduction: [info](https://github.com/alibaba/tsar/blob/master/info.md) + +Installation +------------- +Tsar is available on GitHub, you can clone and install it as follows: + + $ git clone https://github.com/alibaba/tsar.git + $ cd tsar + $ make + # make install + +Or you can download the zip file and install it: + + $ wget -O tsar.zip https://github.com/alibaba/tsar/archive/master.zip --no-check-certificate + $ unzip tsar.zip + $ cd tsar + $ make + # make install + +After installation, you may see these files: + +* `/etc/tsar/tsar.conf`, which is tsar's main configuration file; +* `/etc/cron.d/tsar`, is used to run tsar to collect information every minute; +* `/etc/logrotate.d/tsar` will rotate tsar's log files every month; +* `/usr/local/tsar/modules` is the directory where all module libraries (*.so) are located; + +Configuration +------------- +There is no output displayed after installation by default. Just run `tsar -l` to see if the real-time monitoring works, for instance: + + [kongjian@tsar]$ tsar -l -i 1 + Time ---cpu-- ---mem-- ---tcp-- -----traffic---- --xvda-- -xvda1-- -xvda2-- -xvda3-- -xvda4-- -xvda5-- ---load- + Time util util retran pktin pktout util util util util util util load1 + 11/04/13-14:09:10 0.20 11.57 0.00 9.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 + 11/04/13-14:09:11 0.20 11.57 0.00 4.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 + +Usually, we configure Tsar by simply editing `/etc/tsar/tsar.conf`: + +* To add a module, add a line like `mod_ on` +* To enable or disable a module, use `mod_ on/off` +* To specify parameters for a module, use `mod_ on parameter` +* `output_stdio_mod` is to set modules output to standard I/O +* `output_file_path` is to set history data file, (you should modify the logrotate script `/etc/logrotate.d/tsar` too) +* `output_interface` specifies tsar data output destination, which by default is a local file. See the Advanced section for more information. + +Usage +------ +* null :see default mods history data, `tsar` +* --modname :specify module to show, `tsar --cpu` +* -L/--list :list available module, `tsar -L` +* -l/--live :show real-time info, `tsar -l --cpu` +* -i/--interval :set interval for report, `tsar -i 1 --cpu` +* -s/--spec :specify module detail field, `tsar --cpu -s sys,util` +* -D/--detail :do not conver data to K/M/G, `tsar --mem -D` +* -m/--merge :merge multiply item to one, `tsar --io -m` +* -I/--item :show spec item data, `tsar --io -I sda` +* -d/--date :specify data, YYYYMMDD, or n means n days ago +* -C/--check :show the last collect data +* -h/--help :show help, `tsar -h` + +Advanced +-------- +* Output to Nagios + +To turn it on, just set output type `output_interface file,nagios` in the main configuration file. + +You should also specify Nagios' IP address, port, and sending interval, e.g.: + + ####The IP address or the hostname running the NSCA daemon + server_addr nagios.server.com + ####The port on which the daemon is listening - by default it is 5667 + server_port 8086 + ####The cycle (interval) of sending alerts to Nagios + cycle_time 300 + +As tsar uses Nagios' passive mode, so you should specify the nsca binary and its configuration file, e.g.: + + ####nsca client program + send_nsca_cmd /usr/bin/send_nsca + send_nsca_conf /home/a/conf/amon/send_nsca.conf + +Then specify the module and fields to be checked. There are 4 threshold levels. + + ####tsar mod alert config file + ####threshold servicename.key;w-min;w-max;c-min;cmax; + threshold cpu.util;50;60;70;80; + +* Output to MySQL + +To use this feature, just add output type `output_interface file,db` in tsar's configuration file. + +Then specify which module(s) will be enabled: + + output_db_mod mod_cpu,mod_mem,mod_traffic,mod_load,mod_tcp,mod_udpmod_io + +Note that you should set the IP address (or hostname) and port where tsar2db listens, e.g.: + + output_db_addr console2:56677 + +Tsar2db receives sql data and flush it to MySQL. You can find more information about tsar2db at https://github.com/alibaba/tsar2db. + + +Module development +------------------ +Tsar is easily extended. Whenever you want information that is not collected by tsar yet, you can write a module with `C` . + +C Module +-------- +First, install the tsardevel tool (`make tsardevel` will do this for you): + +Then run `tsardevel `, and you will get a directory named yourmodname, e.g.: + +````bash +[kongjian@tsar]$ tsardevel test +build:make +install:make install +uninstall:make uninstall + +[kongjian@tsar]$ ls test +Makefile mod_test.c mod_test.conf +```` + +You can modify the read_test_stats() and set_test_record() functions in mod_test.c as you need. +Then run `make;make install` to install your module and run `tsar --yourmodname` to see the output. + +More +---- +Homepage http://tsar.taobao.org + +Any question, please feel free to contact me by kongjian@taobao.com diff --git a/source/tools/monitor/mservice/master/conf/sysakmon.conf b/source/tools/monitor/mservice/master/conf/sysakmon.conf new file mode 100644 index 00000000..64b7988a --- /dev/null +++ b/source/tools/monitor/mservice/master/conf/sysakmon.conf @@ -0,0 +1,59 @@ +####debug_level(INFO DEBUG WARN ERROR FATAL) +debug_level ERROR +####[module] +mod_cpu on +mod_mem on +mod_swap on +mod_tcp on +mod_udp on +mod_traffic on +mod_io on +mod_pcsw on +mod_partition on +mod_tcpx on +mod_load on +mod_apache off +mod_lvs off +mod_haproxy off +mod_squid off +mod_nginx off +mod_percpu off +mod_proc off pidname + +####output_interface file,db,nagios +output_interface file + +####[output_file] original data to store +output_file_path /var/log/sysak/tsar.data + +####[output_stdio] these mod will be show as using tsar command +output_stdio_mod mod_swap,mod_partition,mod_cpu,mod_mem,mod_lvs,mod_haproxy,mod_traffic,mod_squid,mod_load,mod_tcp,mod_udp,mod_tcpx,mod_apache,mod_pcsw,mod_io,mod_percpu + +####[output_db] +#output_db_mod mod_swap,mod_partition,mod_cpu,mod_mem,mod_traffic,mod_load,mod_tcp,mod_udp,mod_pcsw,mod_io +#output_db_addr console2:56677 + +####[output_tcp] +#output_tcp_mod mod_swap,mod_cpu +#output_tcp_addr localhost:9666 +#output_tcp_merge on + +####support include other mod conf +include /etc/tsar/conf.d/*.conf + +####The IP address or the host running the NSCA daemon +#server_addr nagios.server.com +####The port on which the daemon is running - default is 5667 +#server_port 8086 +####The cycle of send alert to nagios +#cycle_time 300 +####nsca client program +#send_nsca_cmd /usr/bin/send_nsca +#send_nsca_conf /home/a/conf/amon/send_nsca.conf + +####tsar mod alert config file +####threshold servicename.key;w-min;w-max;c-min;cmax; +#threshold cpu.util;N;N;N;N; + +####run as service +cron_period 60 diff --git a/source/tools/monitor/mservice/master/devel/Makefile.test b/source/tools/monitor/mservice/master/devel/Makefile.test new file mode 100644 index 00000000..fb127814 --- /dev/null +++ b/source/tools/monitor/mservice/master/devel/Makefile.test @@ -0,0 +1,21 @@ +CFLAGS = -Wall -fPIC --shared -g -O2 +CC = gcc +INCLUDE_DIR = /usr/local/tsar/devel +LINK = $(CC) -I$(INCLUDE_DIR) $(CFLAGS) + + +OBJS = mod_test.so + +all: $(OBJS) + +$(OBJS): %.so: %.c + $(LINK) $< -o $@ +clean: + rm -f *.so; +install: + mkdir -p /etc/tsar/conf.d/ + cp ./mod_test.so /usr/local/tsar/modules/ + cp ./mod_test.conf /etc/tsar/conf.d/test.conf +uninstall: + rm /usr/local/tsar/modules/mod_test.so + rm /etc/tsar/conf.d/test.conf diff --git a/source/tools/monitor/mservice/master/devel/mod_test.c b/source/tools/monitor/mservice/master/devel/mod_test.c new file mode 100644 index 00000000..6b970d45 --- /dev/null +++ b/source/tools/monitor/mservice/master/devel/mod_test.c @@ -0,0 +1,84 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" + +#define STATS_TEST_SIZE (sizeof(struct stats_test)) + +static const char *test_usage = " --test test information"; + +/* + * temp structure for collection infomation. + */ +struct stats_test { + unsigned long long value_1; + unsigned long long value_2; + unsigned long long value_3; +}; + +/* Structure for tsar */ +static struct mod_info test_info[] = { + {"value1", SUMMARY_BIT, 0, STATS_NULL}, + {"value2", DETAIL_BIT, 0, STATS_NULL}, + {"value3", DETAIL_BIT, 0, STATS_NULL} +}; + +static void +read_test_stats(struct module *mod, const char *parameter) +{ + /* parameter actually equals to mod->parameter */ + char buf[256]; + struct stats_test st_test; + + memset(buf, 0, sizeof(buf)); + memset(&st_test, 0, sizeof(struct stats_test)); + + st_test.value_1 = 1; + st_test.value_2 = 1; + st_test.value_3 = 1; + + int pos = sprintf(buf, "%llu,%llu,%llu", + /* the store order is not same as read procedure */ + st_test.value_1, + st_test.value_2, + st_test.value_3); + + buf[pos] = '\0'; + /* send data to tsar you can get it by pre_array&cur_array at set_test_record */ + set_mod_record(mod, buf); + return; +} + +static void +set_test_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + /* set st record */ + for (i = 0; i < mod->n_col; i++) { + st_array[i] = cur_array[i]; + } +} + +/* register mod to tsar */ +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--test", test_usage, test_info, 3, read_test_stats, set_test_record); +} diff --git a/source/tools/monitor/mservice/master/devel/mod_test.conf b/source/tools/monitor/mservice/master/devel/mod_test.conf new file mode 100644 index 00000000..b3069abe --- /dev/null +++ b/source/tools/monitor/mservice/master/devel/mod_test.conf @@ -0,0 +1,15 @@ +mod_test on + +####add it to tsar default output +output_stdio_mod mod_test + +####add it to center db +#output_db_mod mod_test + +####add it to nagios send +####set nagios threshold for alert +#output_nagios_mod mod_test + +#threshold test.value1;N;N;N;N; +#threshold test.value2;N;N;N;N; +#threshold test.value3;N;N;N;N; diff --git a/source/tools/monitor/mservice/master/devel/tsar.h b/source/tools/monitor/mservice/master/devel/tsar.h new file mode 100644 index 00000000..0edab9b9 --- /dev/null +++ b/source/tools/monitor/mservice/master/devel/tsar.h @@ -0,0 +1,121 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef _TSARMOD_H +#define _TSARMOD_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define U_64 unsigned long long + +#define LEN_32 32 +#define LEN_64 64 +#define LEN_128 128 +#define LEN_256 256 +#define LEN_512 512 +#define LEN_1024 1024 +#define LEN_4096 4096 +#define LEN_1M 1048576 + +#define ITEM_SPLIT ";" +#define DATA_SPLIT "," + + +struct mod_info { + char hdr[LEN_128]; + int summary_bit; /* bit set indefi summary */ + int merge_mode; + int stats_opt; +}; + +struct module { + + char name[LEN_32]; + char opt_line[LEN_32]; + char record[LEN_1M]; + char usage[LEN_256]; + char parameter[LEN_256]; + char print_item[LEN_256]; + + struct mod_info *info; + void *lib; + int enable; + int spec; + int p_item; + + /* private data used by framework*/ + int n_item; + int n_col; + long n_record; + + int pre_flag:4; + int st_flag:4; + + U_64 *pre_array; + U_64 *cur_array; + double *st_array; + double *max_array; + double *mean_array; + double *min_array; + + /* callback function of module */ + void (*data_collect) (struct module *, char *); + void (*set_st_record) (struct module *, double *, U_64 *, U_64 *, int); + + /* mod manage */ + void (*mod_register) (struct module *); +}; + +void register_mod_fields(struct module *mod, const char *opt, const char *usage, + struct mod_info *info, int n_col, void *data_collect, void *set_st_record); +void set_mod_record(struct module *mod, const char *record); + +enum { + HIDE_BIT, + DETAIL_BIT, + SUMMARY_BIT, + SPEC_BIT +}; + +enum { + MERGE_NULL, + MERGE_SUM, + MERGE_AVG +}; + +enum { + STATS_NULL, + STATS_SUB, + STATS_SUB_INTER +}; + +#endif diff --git a/source/tools/monitor/mservice/master/devel/tsardevel b/source/tools/monitor/mservice/master/devel/tsardevel new file mode 100755 index 00000000..8a0eccea --- /dev/null +++ b/source/tools/monitor/mservice/master/devel/tsardevel @@ -0,0 +1,43 @@ +#!/bin/sh + +# check argc +usage() +{ + echo "Usage:" + echo "tsardevel modname" + exit 0 +} +install() +{ + echo "build:make" + echo "install:make install" + echo "uninstall:make uninstall" + echo "test:tsar --list or tsar --$modname --live -i 1" +} +if [ $# -ne 1 ] +then + usage +fi + +modname=$1 +install_path='/usr/local/tsar/devel' + +for file in mod_test.c mod_test.conf Makefile.test +do + if [ ! -e "$install_path/$file" ] ;then + echo "$install_path/$file not exist!" + echo "make sure you have run 'make tsardevel' when install tsar." + exit 1 + fi +done + + +# mk new mod_test +mkdir -p $modname +sed -e "s/test/$modname/g" < $install_path/mod_test.c > ./$modname/mod_$modname.c +sed -e "s/test/$modname/g" < $install_path/mod_test.conf > ./$modname/mod_$modname.conf +sed -e "s/test/$modname/g" < $install_path/Makefile.test > ./$modname/Makefile +if [ $? -eq 0 ] +then + install +fi diff --git a/source/tools/monitor/mservice/master/include/common.h b/source/tools/monitor/mservice/master/include/common.h new file mode 100644 index 00000000..b67f21d9 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/common.h @@ -0,0 +1,37 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_COMMON_H +#define TSAR_COMMON_H + + +#define PRE_RECORD_FILE "/tmp/.tsar.tmp" + +/* + * convert data to array + */ +int convert_record_to_array(U_64 *array, int l_array, const char *record); +void get_mod_hdr(char hdr[], const struct module *mod); +char* strtok_next_item(char *record, int *start); +int merge_mult_item_to_array(U_64 *array, struct module *mod); +int get_strtok_num(const char *str, const char *split); +int get_st_array_from_file(int have_collect); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/config.h b/source/tools/monitor/mservice/master/include/config.h new file mode 100644 index 00000000..c7053f6b --- /dev/null +++ b/source/tools/monitor/mservice/master/include/config.h @@ -0,0 +1,93 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_CONFIG_H +#define TSAR_CONFIG_H + + +#include "define.h" + + +struct configure { + + /* from arg */ + int running_mode; /* running mode */ + char config_file[LEN_128]; + int debug_level; + + char output_interface[LEN_128]; /* which interface will enable*/ + + /* output print */ + char output_print_mod[LEN_512]; /* which mod will print throught argv */ + char output_stdio_mod[LEN_512]; /* which mod will print throuhth conf file */ + char output_nagios_mod[LEN_512]; /* which mod will output to nagios */ + int print_interval; /* how many seconds will escape every print interval */ + int print_nline_interval; /* how many lines will skip every print interval */ + int print_mode; /* data type will print: summary or detail */ + int print_merge; /* mult items is merge */ + int print_detail; /* conver data to K/M/G */ + int print_ndays; /* these days will print.default:1 */ + int print_day; /* which day will print */ + int print_start_time; /* the start of the print time */ + int print_end_time; /* the end of the print time */ + int print_tail; + int print_file_number; /* which tsar.data file used */ + int print_max_day; /* max day for history print */ + int print_nminute; /* these minutes for history watch */ + + /* output db */ + char output_db_mod[LEN_512]; /* which mod will output */ + char output_db_addr[LEN_512]; /* db addr */ + + /* output tcp */ + int output_tcp_addr_num; /*the number of tcp address indeed need to send data*/ + char output_tcp_mod[LEN_512]; + char output_tcp_addr[MAX_TCP_ADDR_NUM][LEN_256]; + char output_tcp_merge[LEN_256]; + + /* output nagios */ + char server_addr[LEN_512]; + int server_port; + int cycle_time; + char send_nsca_cmd[LEN_512]; + char send_nsca_conf[LEN_512]; + + char check_name[MAX_MOD_NUM][LEN_32]; + float wmin[MAX_MOD_NUM]; + float wmax[MAX_MOD_NUM]; + float cmin[MAX_MOD_NUM]; + float cmax[MAX_MOD_NUM]; + int mod_num; + + /* output file */ + char output_file_path[LEN_128]; + + /* service mode*/ + int cron_period; +}; + + +void parse_config_file(const char *file_name); +void get_include_conf(); +void get_threshold(); +void set_special_field(const char *spec_field); +void set_special_item(const char *spec_field); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/debug.h b/source/tools/monitor/mservice/master/include/debug.h new file mode 100644 index 00000000..5889d31f --- /dev/null +++ b/source/tools/monitor/mservice/master/include/debug.h @@ -0,0 +1,40 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_DEBUG_H +#define TSAR_DEBUG_H + + +typedef enum +{ + LOG_INFO, + LOG_DEBUG, + LOG_WARN, + LOG_ERR, + LOG_FATAL +} log_level_t; + + +#define do_debug(level, ...) \ + _do_debug(level, __FILE__, __LINE__, __VA_ARGS__) + +void _do_debug(log_level_t level, const char *file, int line, const char *fmt, ...); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/define.h b/source/tools/monitor/mservice/master/include/define.h new file mode 100644 index 00000000..84842838 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/define.h @@ -0,0 +1,148 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_DEFINE_H +#define TSAR_DEFINE_H + + +//-check & --check function for old tsar amon usage +#define OLDTSAR + +#define U_BIT 3 + +#define U_64 unsigned long long + +#define LEN_32 32 +#define LEN_64 64 +#define LEN_128 128 +#define LEN_256 256 +#define LEN_512 512 +#define LEN_1024 1024 +#define LEN_4096 4096 +#define LEN_1M 1048576 +#define LEN_10M 10485760 + +#define MAX_COL_NUM 64 +#define MAX_MOD_NUM 32 +#define MAX_TCP_ADDR_NUM 4 + +#define SECTION_SPLIT "|" +#define STRING_SPLIT ":" +#define ITEM_SPLIT ";" +#define ITEM_SPSTART "=" +#define DATA_SPLIT "," +#define PARAM_SPLIT ':' +#define HDR_SPLIT "#" +#define PRINT_DATA_SPLIT " " +#define PRINT_SEC_SPLIT " " +#define W_SPACE " \t\r\n" + +#define DEFAULT_PRINT_NUM 20 +#define DEFAULT_PRINT_INTERVAL 5 + +#define MOD_INFO_SIZE sizeof(strcut mod_info) + +#define DEFAULT_MODULE_PATH "/usr/local/tsar/modules" +#define DEFAULT_CONF_FILE_PATH "/etc/sysak/sysakmon.conf" +#define DEFAULT_OUTPUT_FILE_PATH "/var/log/sysak/tsar.data" +#define MIN_STRING "MIN: " +#define MEAN_STRING "MEAN: " +#define MAX_STRING "MAX: " + +#define TRUE 1 +#define FALSE 0 + +#define VMSTAT "/proc/vmstat" +#define STAT "/proc/stat" +#define MEMINFO "/proc/meminfo" +#define LOADAVG "/proc/loadavg" +#define NET_DEV "/proc/net/dev" +#define NET_SNMP "/proc/net/snmp" +#define APACHERT "/tmp/apachert.mmap" +#define TCP "/proc/net/tcp" +#define NETSTAT "/proc/net/netstat" + + +enum { + MERGE_NOT, + MERGE_ITEM +}; + + +enum { + RUN_NULL, + RUN_LIST, + RUN_CRON, +#ifdef OLDTSAR + RUN_CHECK, +#endif + RUN_CHECK_NEW, + RUN_PRINT, + RUN_PRINT_LIVE, + RUN_WATCH, + RUN_SERVICE +}; + + +enum { + DATA_NULL, + DATA_SUMMARY, + DATA_DETAIL, + DATA_ALL +}; + + +enum { + TAIL_NULL, + TAIL_MAX, + TAIL_MEAN, + TAIL_MIN +}; + + +enum { + OUTPUT_NULL, + OUTPUT_PRINT, + OUTPUT_NAGIOS +}; + + +enum { + HIDE_BIT, + DETAIL_BIT, + SUMMARY_BIT, + SPEC_BIT +}; + + +enum { + MERGE_NULL, + MERGE_SUM, + MERGE_AVG +}; + + +enum { + STATS_NULL, + STATS_SUB, + STATS_SUB_INTER +}; + + +#endif diff --git a/source/tools/monitor/mservice/master/include/framework.h b/source/tools/monitor/mservice/master/include/framework.h new file mode 100644 index 00000000..0a4df0c1 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/framework.h @@ -0,0 +1,88 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_FRAMEWORK_H +#define TSAR_FRAMEWORK_H + + +#include "define.h" + +struct mod_info { + char hdr[LEN_128]; + int summary_bit; /* bit set indefi summary */ + int merge_mode; + int stats_opt; +}; + +struct module { + + char name[LEN_32]; + char opt_line[LEN_32]; + char record[LEN_1M]; + char usage[LEN_256]; + char parameter[LEN_256]; + char print_item[LEN_256]; + + struct mod_info *info; + void *lib; + int enable; + int spec; + int p_item; + + /* private data used by framework*/ + int n_item; + int n_col; + long n_record; + + int pre_flag:4; + int st_flag:4; + + U_64 *pre_array; + U_64 *cur_array; + double *st_array; + double *max_array; + double *mean_array; + double *min_array; + + /* callback function of module */ + void (*data_collect) (struct module *, char *); + void (*set_st_record) (struct module *, double *, U_64 *, U_64 *, int); + + /* mod manage */ + void (*mod_register) (struct module *); +}; + + +void register_mod_fields(struct module *mod, const char *opt, const char *usage, + struct mod_info *info, int n_col, void *data_collect, void *set_st_record); +void set_mod_record(struct module *mod, const char *record); +void init_module_fields(); +int reload_modules(const char *s_mod); +#ifdef OLDTSAR +void reload_check_modules(); +#endif +void load_modules(); +void free_modules(); +void collect_record(); +time_t read_line_to_module_record(char *line); +int collect_record_stat(); +void disable_col_zero(); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/output_db.h b/source/tools/monitor/mservice/master/include/output_db.h new file mode 100644 index 00000000..e4b3a848 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/output_db.h @@ -0,0 +1,34 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_OUTPUT_DB_H +#define TSAR_OUTPUT_DB_H + + +#include +#include +#include +#include +#include + + +void output_db(int have_collect); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/output_file.h b/source/tools/monitor/mservice/master/include/output_file.h new file mode 100644 index 00000000..dd8ce7f1 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/output_file.h @@ -0,0 +1,42 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_OUTPUT_FILE_H +#define TSAR_OUTPUT_FILE_H + + +/* + * output data to file + */ + +struct buffer { + char *data; + int len; +}; + +struct file_header { + int version; + time_t t_start; +}; + + +void output_file(); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/output_http.h b/source/tools/monitor/mservice/master/include/output_http.h new file mode 100644 index 00000000..36635707 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/output_http.h @@ -0,0 +1,7 @@ +#ifndef OUTPUT_HTTP_H +#define OUTPUT_HTTP_H + +extern void output_http(int sk); +extern int http_server(void); + +#endif diff --git a/source/tools/monitor/mservice/master/include/output_nagios.h b/source/tools/monitor/mservice/master/include/output_nagios.h new file mode 100644 index 00000000..54cdf7fd --- /dev/null +++ b/source/tools/monitor/mservice/master/include/output_nagios.h @@ -0,0 +1,34 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_OUTPUT_NAGIOS_H +#define TSAR_OUTPUT_NAGIOS_H + + +#include +#include +#include +#include +#include + + +void output_nagios(); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/output_print.h b/source/tools/monitor/mservice/master/include/output_print.h new file mode 100644 index 00000000..0c8e9d98 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/output_print.h @@ -0,0 +1,35 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_OUT_PRINT_H +#define TSAR_OUT_PRINT_H + + +/* + * output data to std output (history or live mode) + */ +void running_print(); +#ifdef OLDTSAR +void running_current(); +void running_check(int check_type); +#endif +void running_print_live(); + + +#endif diff --git a/source/tools/monitor/mservice/master/include/output_tcp.h b/source/tools/monitor/mservice/master/include/output_tcp.h new file mode 100644 index 00000000..2eba8897 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/output_tcp.h @@ -0,0 +1,32 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_OUTPUT_TCP_H +#define TSAR_OUTPUT_TCP_H + + +#include +#include +#include +#include + + +void output_multi_tcp(int have_collect); +struct sockaddr_in * str2sa(char *); +#endif diff --git a/source/tools/monitor/mservice/master/include/public.h b/source/tools/monitor/mservice/master/include/public.h new file mode 100644 index 00000000..f4cfb76a --- /dev/null +++ b/source/tools/monitor/mservice/master/include/public.h @@ -0,0 +1,301 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_PUBLIC_H +#define TSAR_PUBLIC_H + + +#include +#include +#include +#include "tsar.h" + + +/* + * /proc/files + */ +#define NET_DEV "/proc/net/dev" +#define STAT "/proc/stat" +#define MEMINFO "/proc/meminfo" +#define LOADAVG "/proc/loadavg" +#define INTERRUPT "/proc/interrupts" +#define APACHERT "/tmp/apachert.mmap" +#define VMSTAT "/proc/vmstat" +#define DISKSTATS "/proc/diskstats" +#define NET_SNMP "/proc/net/snmp" +#define FDENTRY_STATE "/proc/sys/fs/dentry-state" +#define FFILE_NR "/proc/sys/fs/file-nr" +#define FINODE_STATE "/proc/sys/fs/inode-state" +#define PTY_NR "/proc/sys/kernel/pty/nr" + + +/* + * ANSI Color setting segment + * + */ +#define BLUE_FMT(s) "\033[40;34m"s"\033[0m" +#define GREEN_FMT(s) "\033[40;32m"s"\033[0m" +#define RED_FMT(s) "\033[40;31m"s"\033[0m" + + +#define COLOR(val, fmt, str, ret, color) do \ +{ \ + if ((val) > 100) \ + ret = sprintf(str, \ + color##_FMT(fmt), (val)); \ + else \ + ret = sprintf(str, fmt, (val)); \ +} while(0) + +#define FALSE 0 +#define TRUE 1 +#define PRINT_STATISTICS FALSE + +#define CURR 0 +#define PAST 1 + + +/* + * for statistics + */ +#define NR_ARRAY 3 + +enum {MIN, MEAN, MAX}; + + +/* + * Macros used to display statistics values. + * + * NB: Define SP_VALUE() to normalize to %; + * HZ is 1024 on IA64 and % should be normalized to 100. + */ +#define _S(a, b) (((b) == 0) ? 0 : ((a) / (b))) + +#define S_VALUE(m, n, p) (((double) ((n) - (m))) / (p) ) + +#define SP_VALUE(m, n, p) (((double) ((n) - (m))) / (p) * 100) + +#define SK(K, shift) (((unsigned long long)(K) << 10) >> shift) +#define SB(B, shift) ((unsigned long long)(B) >> shift) +#define KTOB(B) ((unsigned long long)(B) << 10) + +#define FMT_U64 "%lld" +#define FMT_U32 "%ld" + +#define FMT_SP " %5.1f " +#define FMT_S "%5.1f%c " +#define FMT_NAGIOS "%.2f," + +/*1000 * 1024 * 1024 * 1024*/ +#define TB 0xF424000000 + +/* 1000 * 1024 * 1024*/ +#define GB 0x3E800000 + +/* 1000 * 1024 */ +#define MB 0xFA000 + +/* 1000 */ +#define KB 0x3E8 + +#define __INDENT(f, idx, ret) \ + do { \ + if((f/1024.0) > GB) { \ + (ret) = (f) * 1.0/1024.0 / GB; \ + (idx) = 3; \ + } \ + else if((f) > GB) { \ + (ret) = (f) * 1.0 / GB; \ + (idx) = 2; \ + } \ + else if ((f) > MB){ \ + (ret) = (f) * 1.0 / MB; \ + (idx) = 1; \ + } \ + else { \ + (ret) = (f) * 1.0 / KB; \ + (idx) = 0; \ + } \ + }while(0) + + +#define __PRINT_S(buffer, val, ret) do { \ + int _i; \ + double _f; \ + char u[] = {'K', 'M', 'G', 'T'}; \ + __INDENT((val), _i, _f); \ + (ret) += sprintf((buffer), FMT_S, _f, u[_i]); \ +}while(0) + +#define __PRINT_SP(buffer, val, ret) do { \ + (ret) += sprintf(buffer, FMT_SP, (val)); \ +}while(0) + +#define __PRINT_NAGIOS(buffer, val, ret) do { \ + (ret) += sprintf(buffer, FMT_NAGIOS, (val)); \ +}while(0) + +#define PRINT(buffer, val, ret, type) do { \ + if (type == OUTPUT_NAGIOS) { \ + __PRINT_NAGIOS(buffer, val, ret); \ + } \ + else{ \ + if ((val) < KB) { \ + __PRINT_SP(buffer, val, ret); \ + } \ + else { \ + __PRINT_S(buffer, val, ret); \ + } \ + } \ +} while(0) + +#define myalloc(p, type, size) \ + struct type * p = NULL; \ +p = (struct type *)malloc(size); \ +if(!p) { \ + fprintf(stderr, "failed to alloc memory\n"); \ + exit(EXIT_FAILURE); \ +} \ +memset(p, 0, size) \ + +#define BUFFER_ROTATE(mod, size) \ + do { \ + memcpy(&s_st_##mod[PAST], &s_st_##mod[CURR], (size)); \ + memset(&s_st_##mod[CURR], '\0', (size)); \ + }while(0) + +inline void func_mod_free(struct module *mod) +{ + free(mod->detail); + free(mod->summary); + mod->detail = NULL; + mod->summary = NULL; +} + +#define INIT_STRING_P(s, nr, len) \ + do { \ + int i; \ + s = (char **)malloc((nr) * sizeof(char *)); \ + for(i = 0; i < (nr); i++) \ + s[i] = (char *)malloc(len); \ + } while(0) + + +#define DECLARE_TMP_MOD_STATISTICS(mod) \ + union mod##_statistics mod##_tmp_s; \ + +#define SET_CURRENT_VALUE(mod, type, member, ret) \ + do { \ + mod##_tmp_s.mod##_##type.ret = \ + s_st_##mod[CURR].member; \ + }while(0) + +#define __COMPUTE_MOD_VALUE(ret, ops, m1, m2, i) \ + do { \ + if (!(i)) { \ + (ret) = 0; \ + } \ + else if ((m1) == (m2)) { \ + (ret) = 0; \ + } \ + else { \ + (ret) = ops((m1), (m2), (i)); \ + } \ + } while(0) + + +#define COMPUTE_MOD_VALUE(mod, ops, type, member, i, ret) \ + do { \ + /*printf("i = %ld\n", (i));*/ \ + __COMPUTE_MOD_VALUE( \ + mod##_tmp_s.mod##_##type.ret, \ + ops, \ + s_st_##mod[1].member, \ + s_st_##mod[0].member, \ + (i)); \ + } while(0) + + +/* Fix me */ +#define __SET_MOD_STATISTICS(val, mean, max, min, i) \ + do{ \ + static int sw = 0; \ + if(!sw) { \ + (max) = (val); \ + (min) = (val); \ + sw = 1; \ + } else { \ + if (((val) - (max)) > 0.00001) \ + (max) = (val); \ + else if (((min) - (val)) > 0.00001) { \ + (min) = (val); \ + } \ + } \ + (mean) += (val); \ + } while(0) + +#define SET_MOD_STATISTICS(mod, member, i, type) \ + __SET_MOD_STATISTICS \ +( \ + mod##_tmp_s.mod##_##type.member, \ + mod##_statis[MEAN].mod##_##type.member, \ + mod##_statis[MAX].mod##_##type.member, \ + mod##_statis[MIN].mod##_##type.member, \ + i) + +#define __PRINT_AVG(buf, pos, val, member, idx, count, otype) do \ +{ \ + if ((idx) == MEAN) \ + val[(idx)].member = \ + val[(idx)].member / (count); \ + PRINT(buf[(idx)] + pos[(idx)], \ + val[(idx)].member, \ + pos[(idx)], (otype)); \ +}while(0) + +#define __PRINT_AVG_SEP(buf, pos, val, member, sep, idx, count, otype) do \ +{ \ + if((idx) == MEAN) \ + val[(idx)].member = \ + (val[(idx)].member / (count)); \ + PRINT(buf[(idx)] + pos[(idx)], \ + val[(idx)].member * (sep), \ + pos[(idx)], (otype)); \ +}while(0) + +inline char *getitem(char *r, char *mnt) +{ + char *start, *end; + if (r == NULL || *r == '\0') { + return NULL; + } else { + start = strstr(r, "="); + end = strstr(r, ";"); + memcpy(mnt, start + 1, end - start -1); + r = end + 1; + mnt[end - start - 1] = '\0'; + } + + return r; +} + +#define CALITV(pt, ct, i) ((i) = ((pt) < (ct)) ? (ct) - (pt) : 1) + + +#endif diff --git a/source/tools/monitor/mservice/master/include/tsar.h b/source/tools/monitor/mservice/master/include/tsar.h new file mode 100644 index 00000000..52d419b5 --- /dev/null +++ b/source/tools/monitor/mservice/master/include/tsar.h @@ -0,0 +1,61 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifndef TSAR_H +#define TSAR_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "framework.h" +#include "debug.h" +#include "config.h" + +#include "output_file.h" +#include "output_print.h" +#include "output_db.h" +#include "output_tcp.h" +#include "output_nagios.h" +#include "output_http.h" +#include "common.h" + +struct statistic { + int total_mod_num; + time_t cur_time; +}; + + +extern struct configure conf; +extern struct module *mods[MAX_MOD_NUM]; +extern struct statistic statis; + + +#endif diff --git a/source/tools/monitor/mservice/master/info.md b/source/tools/monitor/mservice/master/info.md new file mode 100644 index 00000000..55a1bc81 --- /dev/null +++ b/source/tools/monitor/mservice/master/info.md @@ -0,0 +1,524 @@ +## 系统模块 +### cpu +#### 字段含义 +* user: 表示CPU执行用户进程的时间,通常期望用户空间CPU越高越好. +* sys: 表示CPU在内核运行时间,系统CPU占用率高,表明系统某部分存在瓶颈.通常值越低越好. +* wait: CPU在等待I/O操作完成所花费的时间.系统部应该花费大量时间来等待I/O操作,否则就说明I/O存在瓶颈. +* hirq: 系统处理硬中断所花费的时间百分比 +* sirq: 系统处理软中断所花费的时间百分比 +* util: CPU总使用的时间百分比 +* nice: 系统调整进程优先级所花费的时间百分比 +* steal: 被强制等待(involuntary wait)虚拟CPU的时间,此时hypervisor在为另一个虚拟处理器服务 +* ncpu: CPU的总个数 + +#### 采集方式 +CPU的占用率计算,都是根据/proc/stat计数器文件而来,stat文件的内容基本格式是: + + cpu 67793686 1353560 66172807 4167536491 2705057 0 195975 609768 + cpu0 10529517 944309 11652564 835725059 2150687 0 74605 196726 + cpu1 14380773 127146 13908869 832565666 150815 0 31780 108418 + +cpu是总的信息,cpu0,cpu1等是各个具体cpu的信息,共有8个值,单位是ticks,分别是: +- User time, 67793686 +- Nice time, 1353560 +- System time, 66172807 +- Idle time, 4167536491 +- Waiting time, 2705057 +- Hard Irq time, 0 +- SoftIRQ time, 195975 +- Steal time, 609768 + +`CPU总时间=user+system+nice+idle+iowait+irq+softirq+Stl` + +各个状态的占用=状态的cpu时间/CPU总时间*100% + +比较特殊的是CPU总使用率的计算(util),目前的算法是: +`util = 1 - idle - iowait - steal` 。 + +### mem +#### 字段含义 +* free: 空闲的物理内存的大小 +* used: 已经使用的内存大小 +* buff: buff使用的内存大小,buffer is something that has yet to be "written" to disk. +* cach: 操作系统会把经常访问的东西放在cache中加快执行速度,A cache is something that has been "read" from the disk and stored for later use +* total: 系统总的内存大小 +* util: 内存使用率 + +#### 采集方法 +内存的计数器在/proc/meminfo,里面有一些关键项 + + MemTotal: 7680000 kB + MemFree: 815652 kB + Buffers: 1004824 kB + Cached: 4922556 kB + +含义就不解释了,主要介绍一下内存使用率的计算算法: +`util = (total - free - buff - cache) / total * 100%` + +### load +#### 字段含义 +* load1: 一分钟的系统平均负载 +* load5: 五分钟的系统平均负载 +* load15:十五分钟的系统平均负载 +* runq: 在采样时刻,运行队列的任务的数目,与/proc/stat的procs_running表示相同意思 +* plit: 在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务) + +#### 采集方法 +/proc/loadavg文件中保存的有负载相关的数据: + +`0.00 0.01 0.00 1/271 23741` + +分别是1分钟负载,五分钟负载,十五分钟负载,运行进程/总进程 最大的pid + +只需要采集前五个数据既可得到所有信息 + +注意:只有当系统负载除cpu核数>1的时候,系统负载较高 + +### traffic +#### 字段含义 +* bytin: 入口流量byte/s +* bytout: 出口流量byte/s +* pktin: 入口pkt/s +* pktout: 出口pkt/s + +#### 采集方法 +流量的计数器信息来自:/proc/net/dev + + face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed + lo:1291647853895 811582000 0 0 0 0 0 0 1291647853895 811582000 0 0 0 0 0 0 + eth0:853633725380 1122575617 0 0 0 0 0 0 1254282827126 808083790 0 0 0 0 0 0 + +字段的含义第一行已经标示出来,每一行代表一个网卡,tsar主要采集的是出口和入口的bytes/packets。 + +注意tsar只对以eth和em开头的网卡数据进行了采集,像lo这种网卡直接就忽略掉了,流量的单位是byte。 + +### tcp +#### 字段含义 +* active:主动打开的tcp连接数目 +* pasive:被动打开的tcp连接数目 +* iseg: 收到的tcp报文数目 +* outseg:发出的tcp报文数目 +* EstRes:Number of resets that have occurred at ESTABLISHED +* AtmpFa:Number of failed connection attempts +* CurrEs:当前状态为ESTABLISHED的tcp连接数 +* retran:系统的重传率 + +#### 采集方法 +tcp的相关计数器文件是:/proc/net/snmp + + Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts + Tcp: 1 200 120000 -1 31702170 14416937 935062 772446 16 1846056224 1426620266 448823 0 5387732 + +我们主要关注其中的ActiveOpens/PassiveOpens/AttemptFails/EstabResets/CurrEstab/InSegs/OutSegs/RetransSegs + +主要关注一下重传率的计算方式: +`retran = (RetransSegs-last RetransSegs) / (OutSegs-last OutSegs) * 100%` + +### udp +#### 字段含义 +* idgm: 收到的udp报文数目 +* odgm: 发送的udp报文数目 +* noport:udp协议层接收到目的地址或目的端口不存在的数据包 +* idmerr:udp层接收到的无效数据包的个数 + + +#### 采集方法 +UDP的数据来源文件和TCP一样,也是在/proc/net/snmp + + Udp: InDatagrams NoPorts InErrors OutDatagrams + Udp: 31609577 10708119 0 159885874 + +### io +#### 字段含义 +* rrqms: The number of read requests merged per second that were issued to the device. +* wrqms: The number of write requests merged per second that were issued to the device. +* %rrqm: The percentage of read requests merged together before being sent to the device. +* %wrqm: The percentage of write requests merged together before being sent to the device. +* rs: The number of read requests that were issued to the device per second. +* ws: The number of write requests that were issued to the device per second. +* rsecs: The number of sectors read from the device per second. +* wsecs: The number of sectors written to the device per second. +* rqsize:The average size (in megabytes) of the requests that were issued to the device. +* rarqsz:The average size (in megabytes) of the read requests that were issued to the device. +* warqsz:The average size (in megabytes) of the write requests that were issued to the device. +* qusize:The average queue length of the requests that were issued to the device. +* await: The average time (in milliseconds) for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them. +* rawait:The average time (in milliseconds) for read requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them. +* wawait:The average time (in milliseconds) for write requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them. +* svctm: The average service time (in milliseconds) for I/O requests that were issued to the device. +* util: Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device).Device saturation occurs when this value is close to 100%. + +#### 采集方法 +IO的计数器文件是:/proc/diskstats,比如: + + 202 0 xvda 12645385 1235409 416827071 59607552 193111576 258112651 3679534806 657719704 0 37341324 717325100 + 202 1 xvda1 421 2203 3081 9888 155 63 421 1404 0 2608 11292 + +每一行字段的含义是: +* major: 主设备号 +* minor: 次设备号,设备号是用来区分磁盘的类型和厂家信息 +* name: 设备名称 +* rd_ios: 读完成次数,number of issued reads. This is the total number of reads completed successfully +* rd_merges: 合并读完成次数,为了效率可能会合并相邻的读和写.从而两次4K的读在它最终被处理到磁盘上之前可能会变成一次8K的读,才被计数(和排队),因此只有一次I/O操作 +* rd_sectors: 读扇区的次数,number of sectors read. This is the total number of sectors read successfully. +* rd_ticks: 读花费的毫秒数,number of milliseconds spent reading. This is the total number of milliseconds spent by all reads +* wr_ios: 写完成次数,number of writes completed. This is the total number of writes completed successfully +* wr_merges: 合并写完成次数,number of writes merged Reads and writes which are adjacent to each other may be merged for efficiency. Thus two 4K reads may become one 8K read before it is ultimately handed to the disk, and so it will be counted (and queued) as only one I/O. +* wr_sectors: 写扇区次数,number of sectors written. This is the total number of sectors written successfully +* wr_ticks: 写花费的毫秒数,number of milliseconds spent writing. This is the total number of milliseconds spent by all writes. +* cur_ios: 正在处理的输入/输出请求数,number of I/Os currently in progress. The only field that should go to zero. Incremented as requests are given to appropriate request_queue_t and decremented as they finish. +* ticks: 输入/输出操作花费的毫秒数 +* aveq: 输入/输出操作花费的加权毫秒数 + +通过这些计数器可以算出来上面的每个字段的值 + + double n_ios = rd_ios + wr_ios; + st_array[0] = rd_merges / (inter * 1.0); + st_array[1] = wr_merges / (inter * 1.0); + st_array[2] = rd_merges + rd_ios ? (double)rd_merges / (rd_merges + rd_ios) * 100 : 0.0; + st_array[3] = wr_merges + wr_ios ? (double)wr_merges / (wr_merges + wr_ios) * 100 : 0.0; + st_array[4] = rd_ios / (inter * 1.0); + st_array[5] = wr_ios / (inter * 1.0); + st_array[6] = rd_sectors / (inter * 1.0); + st_array[7] = wr_sectors / (inter * 1.0); + st_array[8] = n_ios ? (rd_sectors + wr_sectors) / (n_ios * 2) : 0.0; + st_array[9] = rd_ios ? rd_sectors / ((double)rd_ios * 2) : 0.0; + st_array[10] = wr_ios ? wr_sectors / ((double)wr_ios * 2) : 0.0; + st_array[11] = aveq / (inter * 1000); + st_array[12] = n_ios ? (rd_ticks + wr_ticks) / (double)n_ios : 0.0; + st_array[13] = rd_ios ? rd_ticks / (double)rd_ios : 0.0; + st_array[14] = wr_ios ? wr_ticks / (double)wr_ios : 0.0; + st_array[15] = n_ios ? ticks / n_ios : 0.0; + st_array[16] = ticks / (inter * 10.0); /* percentage! */ + /*st_array分别代表tsar显示的每一个值*/ + +注意: +> 1. 扇区一般都是512字节,因此有的地方除以2了 +> 1. ws是指真正落到io设备上的写次数, wrqpms是指系统调用合并的写次数, 它们之间的大小关系没有可比性,因为不知道多少请求能够被合并,比如发起了100个read系统调用,每个读4K,假如这100个都是连续的读,由于硬盘通常允许最大的request为256KB,那么block层会把这100个读请求合并成2个request,一个256KB,另一个144KB,rrqpm/s为100,因为100个request都发生了合并,不管它最后合并成几个;r/s为2,因为最后的request数为2 + +### partition +#### 字段含义 +* bfree: 分区空闲的字节 +* bused: 分区使用中的字节 +* btotl: 分区总的大小 +* util: 分区使用率 +* ifree: 可用文件结点数 +* itotl: 文件结点总数 +* iutil: 文件结点使用率 + +#### 采集方法 +首先通过/etc/mtab获取到分区信息,然后通过statfs访问该分区的信息,查询文件系统相关信息,包含: + + struct statfs { + long f_type; /* 文件系统类型 */ + long f_bsiz + e; /* 经过优化的传输块大小 */ + long f_blocks; /* 文件系统数据块总数 */ + long f_bfree; /* 可用块数 */ + long f_bavail; /* 非超级用户可获取的块数 */ + long f_files; /* 文件结点总数 */ + long f_ffree; /* 可用文件结点数 */ + fsid_t f_fsid; /* 文件系统标识 */ + long f_namelen; /* 文件名的最大长度 */ + }; + +然后就可以计算出tsar需要的信息,分区的字节数=块数*块大小=f_blocks * f_bsize + +### pcsw +#### 字段含义 +* cswch: 进程切换次数 +* proc: 新建的进程数 + +#### 采集方法 +计数器在/proc/stat: + + ctxt 19873315174 + processes 296444211 + +分别代表进程切换次数,以及进程数 + +### tcpx +#### 字段含义 +recvq sendq est twait fwait1 fwait2 lisq lising lisove cnest ndrop edrop rdrop pdrop kdrop + +分别代表 + +tcprecvq tcpsendq tcpest tcptimewait tcpfinwait1 tcpfinwait2 tcplistenq tcplistenincq tcplistenover tcpnconnest tcpnconndrop tcpembdrop tcprexmitdrop tcppersistdrop tcpkadrop +#### 采集方法 +计数器来自:/proc/net/netstat /proc/net/snmp + +里面用到的数据有: + + TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed EmbryonicRsts PruneCalled RcvPruned OfoPruned OutOfWindowIcmps LockDroppedIcmps ArpFilter TW TWRecycled TWKilled PAWSPassive PAWSActive PAWSEstab DelayedACKs DelayedACKLocked DelayedACKLost ListenOverflows ListenDrops TCPPrequeued TCPDirectCopyFromBacklog TCPDirectCopyFromPrequeue TCPPrequeueDropped TCPHPHits TCPHPHitsToUser TCPPureAcks TCPHPAcks TCPRenoRecovery TCPSackRecovery TCPSACKReneging TCPFACKReorder TCPSACKReorder TCPRenoReorder TCPTSReorder TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo TCPLoss TCPLostRetransmit TCPRenoFailures TCPSackFailures TCPLossFailures TCPFastRetrans TCPForwardRetrans TCPSlowStartRetrans TCPTimeouts TCPRenoRecoveryFail TCPSackRecoveryFail TCPSchedulerFailed TCPRcvCollapsed TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv TCPAbortOnSyn TCPAbortOnData TCPAbortOnClose TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger TCPAbortFailed TCPMemoryPressures + TcpExt: 0 0 0 80 539 0 0 0 0 0 3733709 51268 0 0 0 80 5583301 5966 104803 146887 146887 6500405 39465075 2562794034 0 689613557 2730596 540646233 234702206 0 44187 2066 94 240 0 114 293 1781 7221 60514 185158 2 2 3403 400 107505 5860 24813 174014 0 2966 7 168787 106151 40 32851 2 0 2180 9862 0 15999 0 0 0 + +具体字段找到并且获取即可 + +### percpu ncpu +#### 字段含义 +字段含义等同cpu模块,只不过能够支持采集具体的每一个cpu的信息 +#### 采集方法 +等同于cpu模块 + +### pernic +#### 字段含义 +字段含义等同traffic模块,只不过能够支持采集具体的每一个网卡的信息 +#### 采集方法 +等同于traffic模块 + +## 应用模块 +### proc +#### 字段含义 +* user: 某个进程用户态cpu消耗 +* sys: 某个进程系统态cpu消耗 +* total:某个进程总的cpu消耗 +* mem: 某个进程的内存消耗百分比 +* RSS: 某个进程的虚拟内存消耗,这是驻留在物理内存的一部分.它没有交换到硬盘.它包括代码,数据和栈 +* read: 进程io读字节 +* write:进程的io写字节 + +### #采集方法 +计数器文件 +> /proc/pid/stat:获取进程的cpu信息 +> /proc/pid/status:获取进程的mem信息 +> /proc/pid/io:获取进程的读写IO信息 + +注意,需要将采集的进程名称配置在/etc/tsar/tsar.conf总的mod_proc on procname,这样就会找到procname的pid,并进行数据采集 + +### nginx +#### 字段含义 +* accept:总共接收的新连接数目 +* handle:总共处理的连接数目 +* reqs:总共产生请求数目 +* active:活跃的连接数,等于read+write+wait +* read:读取请求数据的连接数目 +* write:向用户写响应数据的连接数目 +* wait:长连接等待的连接数目 +* qps:每秒处理的请求数 +* rt:平均响应时间ms +* sslqps:每秒处理的SSL请求数 +* spdyps:每秒处理的spdy请求数 +* sslhst:平均ssl握手时间ms + + +#### 采集方法 +通过nginx的采集模块配置,访问特定地址,具体参见:https://github.com/taobao/tsar-mod_nginx + + location = /nginx_status { + stub_status on; + } + +请确保如下方式能得到数据: +curl 127.0.0.1:80/nginx_status -H 'Host: status.taobao.com' +请求到的数据是: + + Active connections: 1 + server accepts handled requests request_time + 24 24 7 0 + Reading: 0 Writing: 1 Waiting: 0 + SSL: 0 SPDY: 0 +(注:对于上述返回数据中的server accepts handled requests request_time,当前是通过“ 24 24 7 0”数据行首的空格作为前导。现tsar在本模块中同时支持“Server accepts: 24 handled: 24 requests: 7 request_time 0”格式返回该数据行。今后将升级tengine改用此方式。) + +需要确保nginx配置该location,并且能够访问`curl http://localhost/nginx_status`得到上面的数据 +如果nginx的端口不是80,则需要在配置文件中指定端口,配置文件是/etc/tsar/tsar.conf,修改mod_nginx on为mod_nginx on 8080 。 + +不同端口的nginx数据以不同item的形式展现,在对各item进行合并的时候(-m),除rt以及sslhst依然为平均值之外,其他的所有值都为所有端口的值的总和 + +类似的有nginx_code, nginx_domain模块,相应的配置是: + + req_status_zone server "$host" 20M; + req_status server; + location /traffic_status { + req_status_show; + } + +通过访问`curl http://localhost/traffic_status`能够得到如下字段的数据 +`localhost,0,0,2,2,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0` + +请求到的数据每个字段的含义是: +* kv 计算得到的req_status_zone指令定义变量的值,此时为domain字段 +* bytes_in_total 从客户端接收流量总和 +* bytes_out_total 发送到客户端流量总和 +* conn_total 处理过的连接总数 +* req_total 处理过的总请求数 +* 2xx 2xx请求的总数 +* 3xx 3xx请求的总数 +* 4xx 4xx请求的总数 +* 5xx 5xx请求的总数 +* other 其他请求的总数 +* rt_total rt的总数 +* upstream_req 需要访问upstream的请求总数 +* upstream_rt 访问upstream的总rt +* upstream_tries upstram总访问次数 +* 200 200请求的总数 +* 206 206请求的总数 +* 302 302请求的总数 +* 304 304请求的总数 +* 403 403请求的总数 +* 404 404请求的总数 +* 416 416请求的总数 +* 499 499请求的总数 +* 500 500请求的总数 +* 502 502请求的总数 +* 503 503请求的总数 +* 504 504请求的总数 +* 508 508请求的总数 +* detail_other 非以上13种status code的请求总数 + +如果domain数量太多,或者端口不是80,需要进行专门的配置,配置文件内容如下: + + port=8080 #指定nginx的端口 + top=10 #指定最多采集的域名个数,按照请求总个数排列 + domain=a.com b.com #指定特定需要采集的域名列表,分隔符为空格,逗号,或者制表符 + +在/etc/tsar/tsar.conf中指定配置文件的路径:mod_nginx_domain on /tmp/my.conf + +#### nginx_domain_traffic +nginx配置是: + + req_status_zone server "$host" 20M; + req_status server; + + # req_status_zone_add_indecator 指令:可以在req status输出的每一行最后添加新的字段 + # 这里添加的字段用于统计nginx的变量: $2xx_bytes_sent, $3xx_bytes_sent, $4xx_bytes_sent, $5xx_bytes_sent + # $2xx_bytes_sent: 请求返回2xx时候,发送给客户端的数据量(如果请求非2xx则该变量为0) + req_status_zone_add_indecator server $2xx_bytes_sent $3xx_bytes_sent $4xx_bytes_sent $5xx_bytes_sent; + + location /traffic_status { + req_status_show; + } + +输出实例: + + module004033.sqa.cm4 tsar $ tsar --nginx_domain_traffic -li1 + Time -----------------localhost:8080----------------- ----------------www.foo.com:8080---------------- + Time bytin bytout 2XXout 3XXout 4XXout 5XXout bytin bytout 2XXout 3XXout 4XXout 5XXout + 09/01/15-13:45:48 0.00 0.00 0.00 0.00 0.00 0.00 410.1K 16.6M 16.6M 0.00 0.00 0.00 + 09/01/15-13:45:49 0.00 0.00 0.00 0.00 0.00 0.00 407.8K 16.5M 16.5M 0.00 0.00 0.00 + 09/01/15-13:45:51 159.0K 287.4K 0.00 0.00 0.00 287.4K 258.6K 10.5M 10.5M 0.00 0.00 0.00 + 09/01/15-13:45:52 245.5K 443.5K 0.00 0.00 0.00 443.5K 224.2K 9.1M 9.1M 0.00 0.00 0.00 + +字段含义: +* bytin: 收到的请求字节数byte/s +* bytout: 输出的应答字节数byte/s +* 2XXout: 输出的2XX应答字节数byte/s +* 3XXout: 输出的3XX应答字节数byte/s +* 4XXout: 输出的4XX应答字节数byte/s +* 5XXout: 输出的5XX应答字节数byte/s + +#### nginx_ups +用于输出nginx upstream想关信息 +nginx配置是: + + req_status_zone server "$host" 20M; + req_status server; + req_status_zone_add_indecator server $response_fbt_time $upstream_response_fbt_time $upstream_response_length; + + location /traffic_status { + req_status_show; + } + +输出实例: + + module004033.sqa.cm4 tsar $ tsar --nginx_ups -li1 + Time ----------------------------nginx_ups--------------------------- + Time traff qps 4XX 5XX rqps rt fbt ufbt + 09/01/15-16:26:29 15.8M 3.9K 3.9K 0.00 0.00 9.7K 9.7K 9.7K + 09/01/15-16:26:30 15.8M 3.9K 3.9K 0.00 0.00 9.7K 9.7K 9.7K + 09/01/15-16:26:31 4.9M 1.2K 1.2K 0.00 0.00 3.0K 3.0K 3.0K + +字段含义: +* traff: 后端返回的应答body的流量(不包括http应答头部) +* qps: 后端qps +* rqps: 后端总qps(包含重试的qps + 后端qps) +* 4XX: 后端返回4XX状态码的qps +* 5XX: 后端返回5XX状态码的qps +* rt: 后端应答时间 +* fbt: tengine首字节时间 +* ufbt: 后端应答首字节时间 + +### nginx_live +#### 字段含义 +* online:当前总共在线数 +* olhstr:历史总共在线数 +* olvary:历史在线数增长量(待商榷,不显示) +* upflow:上行总流量 +* uspeed:上行总速度 +* downfl:下行总流量 +* dspeed:下行总速度 +* fmtime:当前平均首播时间 +* fmdata:不显示 +* dropfr:丢帧 + + +#### 采集方法 +请确保如下方式能得到数据: +curl -x 127.0.0.1:7001 http://status.taobao.com/rtmp_reqstat +请求到的数据是: +rtmp://pagefault/alicdn/diaoliang123,fm_time:574 drop_frame:0 online:1 online_history:2 down_flow:166096189 up_flow:166096188 internal:0 edge:2 + +### squid +#### 字段含义 +* qps: 每秒请求数 +* rt: 访问平均相应时间 +* r_hit: 请求命中率 +* b_hit: 字节命中率 +* d_hit: 磁盘命中率 +* m_hit: 内存命中率 +* fdused: Number of file desc currently in use +* fdque: Files queued for open +* objs: StoreEntries +* inmem: StoreEntries with MemObjects +* hot: Hot Object Cache Items +* size: Mean Object Size + +####采集方法 +访问squid的mgrinfo信息获取,有些字段经过了一些patch,可能不适用外部版本 + +###haproxy +####字段含义 +* stat: 状态,1正常 +* uptime:启动持续时间 +* conns: 总的连接数 +* qps: 每秒请求数 +* hit: haproxy开启cache时的命中率 +* rt: 平均响应时间ms + +#### 采集方法 +haproxy经过了patch,能够在多进程模式下进行统计信息的汇总,然后通过haproxy的本地访问其状态页面admin分析得到 + +### lvs +#### 字段含义 +* stat: lvs状态,1正常 +* conns: 总的连接数 +* pktin: 收到的包数 +* pktout:发出的包数 +* bytin: 收到的字节数 +* bytout:发出的字节数 +* total: lvs所有的 session 数量, 包含 local 和 sync +* local: lvs本机转发的 session 数量 +* lact: local session 中处于 establish 状态的数量 +* linact: local session 中处于非 establish 状态的数量 +* sync: 其他lvs同步过来的 session 数量 +* sact: sync session 中处于 establish 状态的数量 +* sinact: sync session 中处于非 establish 状态的数量 +* templ: 会话保持(模板) session 的数量 + + +#### 采集方法 +内核版 lvs: 访问lvs的统计文件:/proc/net/ip_vs_stats, /proc/net/ip_vs_conn_stats +netframe lvs: 访问 lvs 的命令行工具: slb_admin -ln --total --dump, appctl -cas + +### apache +参见:https://github.com/kongjian/tsar-apache +### tcprt +私有应用,略 +### swift +私有应用,略 +### cgcpu/cgmem/cgblkio +私有应用,略 +### trafficserver +待补充 +### tmd +私有应用,略 + diff --git a/source/tools/monitor/mservice/master/modules/Makefile b/source/tools/monitor/mservice/master/modules/Makefile new file mode 100644 index 00000000..d13a5157 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/Makefile @@ -0,0 +1,30 @@ +CFLAGS = -MD -Wall -fPIC --shared -g -O2 -Wno-strict-aliasing +CC = gcc +INCLUDE_DIR = ../include +LINK = $(CC) -I$(INCLUDE_DIR) -I../src/obj/include $(CFLAGS) + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + LINK += -Wl,-undefined -Wl,dynamic_lookup + + OBJS = mod_apache.so mod_cpu.so mod_haproxy.so mod_load.so mod_swap.so\ + mod_lvs.so mod_mem.so mod_ncpu.so mod_nginx.so \ + mod_pcsw.so mod_percpu.so mod_pernic.so \ + mod_proc.so mod_squid.so mod_tcp.so mod_tcpx.so mod_traffic.so mod_udp.so +else + OBJS = mod_apache.so mod_cpu.so mod_haproxy.so mod_io.so mod_load.so mod_swap.so \ + mod_lvs.so mod_mem.so mod_ncpu.so mod_nginx.so \ + mod_partition.so mod_pcsw.so mod_percpu.so mod_pernic.so \ + mod_proc.so mod_squid.so mod_tcp.so mod_tcpx.so mod_traffic.so mod_udp.so +endif + +all: $(OBJS) + +$(OBJS): %.so: %.c + $(LINK) $< -o $@ +clean: + rm -f *.so; + rm -f *.d; + rm -rf *.dSYM; + +-include $(OBJS:.so=.d) diff --git a/source/tools/monitor/mservice/master/modules/mod_apache.c b/source/tools/monitor/mservice/master/modules/mod_apache.c new file mode 100644 index 00000000..e1d27e03 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_apache.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include + +#include "tsar.h" + +char *apache_usage = " --apache apache statistics"; + +struct stats_apache { + unsigned int busy_proc; + unsigned int idle_proc; + unsigned long long query; + unsigned long long response_time; + unsigned long long kBytes_sent; +}; + +#define STATS_APACHE_SIZE (sizeof(struct stats_apache)) + + +struct hostinfo { + char *host; + int port; +}; + +void +init_host_info(struct hostinfo *p) +{ + p->host = strdup("127.0.0.1"); + p->port = 80; +} + +void +read_apache_stats(struct module *mod) +{ + int fd, n, m, sockfd, send, pos; + char buf[LEN_4096] = {0}, request[LEN_4096], line[LEN_4096], + buff[LEN_4096]; + memset(buf, 0, LEN_4096); + struct sockaddr_in servaddr; + FILE *stream = NULL; + /* FIX me */ + char *cmd = "server-status?auto"; + struct stats_apache st_apache; + memset(&st_apache, 0, sizeof(struct stats_apache)); + struct hostinfo hinfo; + memset(&hinfo, 0, sizeof(struct hostinfo)); + + if ((fd = open(APACHERT, O_RDONLY , 0644)) < 0 ){ + return; + } + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + goto last; + } + if ((n = read(fd, buff, 16)) != 16) { + goto last; + } + st_apache.query = * (unsigned long long *)buff; + st_apache.response_time = * (unsigned long long *)&buff[8]; + /*fullfil another member int the structure*/ + init_host_info(&hinfo); + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(hinfo.port); + inet_pton(AF_INET, hinfo.host, &servaddr.sin_addr); + sprintf(request, + "GET /%s HTTP/1.0\r\n" + "User-Agent: Wget/1.9\r\n" + "Host: %s\r\n" + "Accept:*/*\r\n" + "Connection: Close\r\n\r\n", + cmd, hinfo.host); + + if ((m = connect(sockfd, (struct sockaddr *) &servaddr, + sizeof(servaddr))) == -1 ) { + goto writebuf; + } + + if ((send = write(sockfd, request, strlen(request))) == -1) { + goto writebuf; + } + stream = fdopen(sockfd, "r"); + if (!stream) { + goto last; + } + while(fgets(line, LEN_4096, stream) != NULL) { + if(!strncmp(line, "Total kBytes:", 13)) { + sscanf(line + 14, "%llu", &st_apache.kBytes_sent); + + } else if (!strncmp(line, "BusyWorkers:", 12)) { + sscanf(line + 13, "%d", &st_apache.busy_proc); + + } else if (!strncmp(line, "IdleWorkers:", 12)) { + sscanf(line + 13, "%d", &st_apache.idle_proc); + + } else { + ; + } + memset(line, 0, LEN_4096); + } +writebuf: + pos = sprintf(buf, "%lld,%lld,%lld,%d,%d", + st_apache.query, + st_apache.response_time / 1000, + st_apache.kBytes_sent, + st_apache.busy_proc, + st_apache.idle_proc); + buf[pos] = '\0'; + if (stream) { + if (fclose(stream) < 0) { + goto last; + } + } + set_mod_record(mod, buf); +last: + close(fd); + if (sockfd) { + close(sockfd); + } + free(hinfo.host); +} + +static void +set_apache_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + /* set st record */ + if(cur_array[0] >= pre_array[0]) + st_array[0] = (cur_array[0] - pre_array[0]) / (inter * 1.0); + if((cur_array[1] >= pre_array[1]) && (cur_array[0] > pre_array[0])) + st_array[1] = (cur_array[1] - pre_array[1]) / ((cur_array[0] - pre_array[0]) * 1.0); + if(cur_array[2] >= pre_array[2]) + st_array[2] = (cur_array[2] - pre_array[2]) / (inter * 1.0); + for (i = 3; i <= 4; i++) st_array[i] = cur_array[i]; +} + +static struct mod_info apache_info[] = { + {" qps", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {" rt", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {" sent", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" busy", DETAIL_BIT, 0, STATS_NULL}, + {" idle", DETAIL_BIT, 0, STATS_NULL}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--apache", apache_usage, apache_info, 5, read_apache_stats, set_apache_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_cpu.c b/source/tools/monitor/mservice/master/modules/mod_cpu.c new file mode 100644 index 00000000..01e463cf --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_cpu.c @@ -0,0 +1,167 @@ +#include "tsar.h" + +/* + * Structure for CPU infomation. + */ +struct stats_cpu { + unsigned long long cpu_user; + unsigned long long cpu_nice; + unsigned long long cpu_sys; + unsigned long long cpu_idle; + unsigned long long cpu_iowait; + unsigned long long cpu_steal; + unsigned long long cpu_hardirq; + unsigned long long cpu_softirq; + unsigned long long cpu_guest; + unsigned long long cpu_number; +}; + +#define STATS_CPU_SIZE (sizeof(struct stats_cpu)) + +static char *cpu_usage = " --cpu CPU share (user, system, interrupt, nice, & idle)"; +static int cpu_quota = 1; + + +static void +read_cpu_stats(struct module *mod) +{ + FILE *fp, *ncpufp; + char *max_cpu; + char line[LEN_4096]; + char buf[LEN_4096]; + struct stats_cpu st_cpu; + + memset(buf, 0, LEN_4096); + memset(&st_cpu, 0, sizeof(struct stats_cpu)); + //get cpu number for cpushare + max_cpu = getenv("SIGMA_MAX_CPU_QUOTA"); + cpu_quota = max_cpu ? atoi(max_cpu) / 100 : 1; + //unsigned long long cpu_util; + if ((fp = fopen(STAT, "r")) == NULL) { + return; + } + while (fgets(line, LEN_4096, fp) != NULL) { + if (!strncmp(line, "cpu ", 4)) { + /* + * Read the number of jiffies spent in the different modes + * (user, nice, etc.) among all proc. CPU usage is not reduced + * to one processor to avoid rounding problems. + */ + sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu %llu", + &st_cpu.cpu_user, + &st_cpu.cpu_nice, + &st_cpu.cpu_sys, + &st_cpu.cpu_idle, + &st_cpu.cpu_iowait, + &st_cpu.cpu_hardirq, + &st_cpu.cpu_softirq, + &st_cpu.cpu_steal, + &st_cpu.cpu_guest); + } + } + + /* get cpu number */ + if ((ncpufp = fopen("/proc/cpuinfo", "r")) == NULL) { + fclose(fp); + return; + } + while (fgets(line, LEN_4096, ncpufp)) { + if (!strncmp(line, "processor\t:", 11)) + st_cpu.cpu_number++; + } + fclose(ncpufp); + + /* cpu_util = */ + /* st_cpu.cpu_user + st_cpu.cpu_sys + */ + /* st_cpu.cpu_hardirq + st_cpu.cpu_softirq; */ + + sprintf(buf, "%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu", + /* the store order is not same as read procedure */ + st_cpu.cpu_user, + st_cpu.cpu_sys, + st_cpu.cpu_iowait, + st_cpu.cpu_hardirq, + st_cpu.cpu_softirq, + st_cpu.cpu_idle, + st_cpu.cpu_nice, + st_cpu.cpu_steal, + st_cpu.cpu_guest, + st_cpu.cpu_number); + + set_mod_record(mod, buf); + if (fclose(fp) < 0) { + return; + } +} + +static void +set_cpu_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i, j; + char *max_cpu; + U_64 pre_total, cur_total; + + //get cpu number for cpushare + max_cpu = getenv("SIGMA_MAX_CPU_QUOTA"); + cpu_quota = max_cpu ? atoi(max_cpu) / 100 : 1; + + pre_total = cur_total = 0; + + for (i = 0; i < 9; i++) { + if(cur_array[i] < pre_array[i]){ + for(j = 0; j < 9; j++) + st_array[j] = -1; + return; + } + pre_total += pre_array[i]; + cur_total += cur_array[i]; + } + + /* no tick changes, or tick overflows */ + if (cur_total <= pre_total) { + for(j = 0; j < 9; j++) + st_array[j] = -1; + return; + } + + /* set st record */ + for (i = 0; i < 9; i++) { + /* st_array[5] is util, calculate it late */ + if((i != 5) && (cur_array[i] >= pre_array[i])) + st_array[i] = (cur_array[i] - pre_array[i]) * 100.0 / (cur_total - pre_total); + } + + /* util = 100 - idle - iowait - steal */ + if (cur_array[5] >= pre_array[5]) { + st_array[5] = 100.0 - (cur_array[5] - pre_array[5]) * 100.0 / (cur_total - pre_total) - st_array[2] - st_array[7]; + } + if (cpu_quota > 1) { + for (i = 0; i < 9; i++) { + st_array[i] = st_array[i] * cur_array[9] / cpu_quota; + } + } + + st_array[9] = cur_array[9]; + /* util = user + sys + hirq + sirq + nice */ + //st_array[5] = st_array[0] + st_array[1] + st_array[3] + st_array[4] + st_array[6]; +} + +static struct mod_info cpu_info[] = { + {" user", DETAIL_BIT, 0, STATS_NULL}, + {" sys", DETAIL_BIT, 0, STATS_NULL}, + {" wait", DETAIL_BIT, 0, STATS_NULL}, + {" hirq", DETAIL_BIT, 0, STATS_NULL}, + {" sirq", DETAIL_BIT, 0, STATS_NULL}, + {" util", SUMMARY_BIT, 0, STATS_NULL}, + {" nice", HIDE_BIT, 0, STATS_NULL}, + {" steal", HIDE_BIT, 0, STATS_NULL}, + {" guest", HIDE_BIT, 0, STATS_NULL}, + {" ncpu", HIDE_BIT, 0, STATS_NULL}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--cpu", cpu_usage, cpu_info, 10, read_cpu_stats, set_cpu_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_haproxy.c b/source/tools/monitor/mservice/master/modules/mod_haproxy.c new file mode 100644 index 00000000..6f8d055c --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_haproxy.c @@ -0,0 +1,415 @@ +#define _GNU_SOURCE +#include "tsar.h" +#include +#include +#include +#include + +#define SOCK_PATH "/var/run/haproxy.stat" +#define HAPROXY "/var/run/haproxy.pid" +#define HAPROXY_STORE_FMT(d) "%ld"d"%ld"d"%ld"d"%ld"d"%ld"d"%ld" +#define server_port 80 +#define server_address "127.0.0.1" +#define URL "http://img01.taobaocdn.com/health.gif" +#define CRLF "\r\n" +#define DEBUG 0 +#define RETRY 3 +#define MAX_HOST_ADDRESS_LENGTH 64 +#define MAX_INPUT_BUFFER 1024 +#define MAX_SIZE 40960 +#define my_recv(buf, len) read(sd, buf, len) +#define my_send(buf, len) send(sd, buf, len, 0) +#define my_tcp_connect(addr, port, s) np_net_connect(addr, port, s, "tcp") +int np_net_connect(const char *address, int port, int *sd, char* proto); +int get_http_status(); +int StrToInt(const char* str); +int get_haproxy_detail(); +int sd; +int was_refused = 0; +int econn_refuse_state = 2; +int address_family = AF_INET; +char buffer[MAX_INPUT_BUFFER]; + +struct stats_haproxy { + unsigned long stat; + unsigned long uptime; + unsigned long conns; + unsigned long qps; + unsigned long hit; + unsigned long rt; +}; + +static struct mod_info info[] = { + {" stat", SUMMARY_BIT, MERGE_NULL, STATS_NULL}, + {"uptime", SUMMARY_BIT, MERGE_NULL, STATS_NULL}, + {" conns", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {" qps", SUMMARY_BIT, MERGE_NULL, STATS_NULL}, + {" hit", SUMMARY_BIT, MERGE_NULL, STATS_NULL}, + {" rt", DETAIL_BIT, MERGE_NULL, STATS_NULL}, +}; + +static char *haproxy_usage = " --haproxy haproxy usage"; +struct stats_haproxy st_haproxy; + +/* + ******************************************************* + * Read swapping statistics from haproxy.stat & 80 port + ******************************************************* + */ +static void +read_haproxy(struct module *mod) +{ + int i, pos=0; + char buf[512]; + + memset(&st_haproxy, 0, sizeof(struct stats_haproxy)); + for (i = 0;i < RETRY;i++) { + if (get_http_status() == 0 && access(HAPROXY, 0) == 0) { + st_haproxy.stat = 1; + break; + } + } + if (st_haproxy.stat == 1 && get_haproxy_detail() == 0) { + if (DEBUG) { + printf("get right.\n"); + } + + } else { + if (DEBUG) { + printf("get wrong.\n"); + } + } + if (st_haproxy.stat == 1) { + pos = sprintf(buf, HAPROXY_STORE_FMT(DATA_SPLIT), st_haproxy.stat, st_haproxy.uptime, + st_haproxy.conns, st_haproxy.qps, st_haproxy.hit, st_haproxy.rt); + } + buf[pos] = '\0'; + set_mod_record(mod, buf); + return; +} + + +static void +set_haproxy_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + for (i = 0; i <3; i++) { + st_array[i] = cur_array[i]; + } + if (cur_array[3] > pre_array[3]) { + st_array[3] = (cur_array[3] - pre_array[3]) / inter; + } else { + st_array[3] = 0; + } + st_array[4] = cur_array[4] / 10.0; + st_array[5] = cur_array[5] / 100.0; +} + + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--haproxy", haproxy_usage, info, sizeof(info) / sizeof(struct mod_info), read_haproxy, set_haproxy_record); +} + + +/* Returns 1 if we're done processing the document body; 0 to keep going */ +static int +document_headers_done (char *full_page) +{ + const char *body; + + for (body = full_page; *body; body++) { + if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3)) + break; + } + + if (!*body) + return 0; /* haven't read end of headers yet */ + + full_page[body - full_page] = 0; + return 1; +} + +int +get_http_status() +{ + if (my_tcp_connect (server_address, server_port, &sd) == 0) { + close(sd); + if (DEBUG) { + printf("connect host %s at %d\n", server_address, server_port); + } + return 0; + } else { + close(sd); + return -1; + if (DEBUG) { + printf("cat't connect host %s at %d\n", server_address, server_port); + } + } + int i = 0; + int http_status; + char *buf; + char *full_page; + char *page; + char *status_line; + char *status_code; + size_t pagesize = 0; + + if (asprintf (&buf, "GET %s HTTP/1.0\r\nUser-Agent: check_http\r\n", URL) < 0) { + return -1; + } + /* tell HTTP/1.1 servers not to keep the connection alive */ + if (asprintf (&buf, "%sConnection: close\r\n", buf) < 0) { + return -1; + } + if (server_address) { + if (asprintf (&buf, "%sHost: %s:%d\r\n", buf, server_address, server_port) < 0) { + return -1; + } + } + if (asprintf (&buf, "%s%s", buf, CRLF) < 0){ + return -1; + } + if (DEBUG) { + printf ("send %s\n", buf); + } + my_send (buf, strlen (buf)); + full_page = strdup(""); + while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) { + buffer[i] = '\0'; + if (asprintf (&full_page, "%s%s", full_page, buffer) < 0) { + return -1; + } + pagesize += i; + if (document_headers_done (full_page)) { + i = 0; + break; + } + } + if (DEBUG) { + printf("%s\n", full_page); + } + if (i < 0 && errno != ECONNRESET) { + printf("HTTP CRITICAL - Error on receive\n"); + } + /* return a CRITICAL status if we couldn't read any data */ + if (pagesize == (size_t) 0){ + printf("HTTP CRITICAL - No data received from host\n"); + } + /* close the connect */ + if (sd) { + close(sd); + } + + + /* find status line and null-terminate it */ + page = full_page; + page += (size_t) strspn (page, "\r\n"); + status_line = page; + status_line[strcspn(status_line, "\r\n")] = 0; + if (DEBUG) { + printf ("STATUS: %s\n", status_line); + } + status_code = strchr (status_line, ' ') + sizeof (char); + http_status = atoi (status_code); + return http_status; +} + + +/* opens a tcp or udp connection to a remote host or local socket */ +int +np_net_connect (const char *host_name, int port, int *sd, char* proto) +{ + int result; + struct protoent *ptrp; + struct sockaddr_in servaddr; + + bzero((char *)&servaddr, sizeof(servaddr)); + servaddr.sin_family=AF_INET; + servaddr.sin_port=htons(port); + inet_pton(AF_INET, server_address, &servaddr.sin_addr); + + /* map transport protocol name to protocol number */ + if (((ptrp = getprotobyname(proto))) == NULL) { + if (DEBUG) { + printf("Cannot map \"%s\" to protocol number\n", proto); + } + return 3; + } + + /* create a socket */ + *sd = socket(PF_INET, (!strcmp(proto, "udp"))?SOCK_DGRAM:SOCK_STREAM, ptrp->p_proto); + if (*sd < 0) { + close(*sd); + if (DEBUG) { + printf("Socket creation failed\n"); + } + return 3; + } + /* open a connection */ + result = connect(*sd, (struct sockaddr *)&servaddr, sizeof(servaddr)); + if (result < 0) { + close(*sd); + switch(errno) { + case ECONNREFUSED: + if (DEBUG) { + printf("Connection refused by host\n"); + } + break; + case ETIMEDOUT: + if (DEBUG) { + printf("Timeout while attempting connection\n"); + } + break; + case ENETUNREACH: + if (DEBUG) { + printf("Network is unreachable\n"); + } + break; + default: + if (DEBUG) { + printf("Connection refused or timed out\n"); + } + } + + return 2; + } + return 0; +} + +int +StrToInt(const char* str) +{ + int num = 0; + if (str != NULL) { + const char* digit = str; + while (*digit != '\0') { + if (*digit >= '0' && *digit <= '9') { + num = num * 10 + (*digit - '0'); + } else { + num = 0; + break; + } + digit ++; + } + } + return num; +} + +int +get_haproxy_detail(void) +{ + int s, t, len; + char str[MAX_SIZE]; + char show_info[20] = "show info\n"; + char show_tsar[20] = "show tsar\n"; + char *p_split; + struct sockaddr_un remote; + /*result for tsar to show*/ + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + if (DEBUG) { + perror("socket"); + } + return -1; + } + + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + close(s); + if (DEBUG) { + perror("connect"); + } + return -1; + } + memset(str, '\0', sizeof(str)); + if (send(s, show_tsar, strlen(show_tsar), 0) == -1) { + close(s); + if (DEBUG) { + perror("send"); + } + return -1; + } + + t = recv(s, str, MAX_SIZE, 0); + close(s); + if (t > 0) { + str[t] = '\0'; + } else { + if (t < 0 && DEBUG) { + perror("recv"); + } else if (DEBUG) { + perror("Server closed connection\n"); + } + return -1; + } + + if (!strstr(str, "Uptime_sec")) { + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + if (DEBUG) { + perror("socket"); + } + return -1; + } + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + close(s); + if (DEBUG) { + perror("connect"); + } + return -1; + } + memset(str, '\0', sizeof(str)); + if (send(s, show_info, strlen(show_info), 0) == -1) { + close(s); + if (DEBUG) { + perror("send"); + } + return -1; + } + + if ((t=recv(s, str, MAX_SIZE, 0)) > 0) { + str[t] = '\0'; + } else { + close(s); + if (t < 0 && DEBUG) { + perror("recv"); + } else if (DEBUG) { + perror("Server closed connection\n"); + } + return -1; + } + close(s); + } + p_split = strtok(str, "\n"); + while (p_split) { + if (strstr(p_split, "total request num:")) { + sscanf(p_split, "total request num: %ld/", &st_haproxy.qps); + } + if (strstr(p_split, "total request num/total hit request num/ total conns num:")) { + sscanf(p_split, "total request num/total hit request num/ total conns num: %ld/", &st_haproxy.qps); + } + if (strstr(p_split, "mean rt:")) { + int a, b; + sscanf(p_split, "mean rt: %d.%d (ms)", &a, &b); + st_haproxy.rt = a * 100 + b; + } + if (strstr(p_split, "req hit ratio:")) { + int a, b; + sscanf(p_split, "req hit ratio: %d.%d ", &a, &b); + st_haproxy.hit = a * 1000 + b; + } + if (strstr(p_split, "Uptime_sec")) { + char *p = strstr(p_split, " "); + st_haproxy.uptime = StrToInt(p + 1); + } + if (strstr(p_split, "CurrConns")) { + char *p = strstr(p_split, " "); + st_haproxy.conns = StrToInt(p + 1); + } + p_split = strtok(NULL, "\n"); + } + return 0; +} diff --git a/source/tools/monitor/mservice/master/modules/mod_io.c b/source/tools/monitor/mservice/master/modules/mod_io.c new file mode 100644 index 00000000..1b85b205 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_io.c @@ -0,0 +1,345 @@ +/* + * iostat.c for 2.6.* with file /proc/diskstat + * Linux I/O performance monitoring utility + */ +#include "tsar.h" +#include +#include +#include +#include +#include +#include +#include +#include + +char *io_usage = " --io Linux I/O performance"; + +#define MAX_PARTITIONS 64 +#define IO_FILE "/proc/diskstats" + +struct part_info { + unsigned int major; /* Device major number */ + unsigned int minor; /* Device minor number */ + char name[32]; +} partition[MAX_PARTITIONS]; + +struct blkio_info { + unsigned long long rd_ios; /* Read I/O operations */ + unsigned long long rd_merges; /* Reads merged */ + unsigned long long rd_sectors; /* Sectors read */ + unsigned long long rd_ticks; /* Time in queue + service for read */ + unsigned long long wr_ios; /* Write I/O operations */ + unsigned long long wr_merges; /* Writes merged */ + unsigned long long wr_sectors; /* Sectors written */ + unsigned long long wr_ticks; /* Time in queue + service for write */ + unsigned long long ticks; /* Time of requests in queue */ + unsigned long long aveq; /* Average queue length */ +} new_blkio[MAX_PARTITIONS]; +#define STATS_IO_SIZE (sizeof(struct blkio_info)) + +char buffer[256]; /* Temporary buffer for parsing */ +FILE *iofp; /* /proc/diskstats*/ +int print_partition = 0; +int print_device = 1; + +unsigned int n_partitions = 0; /* Number of partitions */ +unsigned int max_partitions = MAX_PARTITIONS; /* Max of partitions */ + +static struct mod_info io_info[] = { + {" rrqms", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" wrqms", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" %rrqm", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" %wrqm", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" rs", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" ws", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" rsecs", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" wsecs", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {"rqsize", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {"rarqsz", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {"warqsz", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {"qusize", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" await", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {"rawait", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {"wawait", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" svctm", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" util", SUMMARY_BIT, MERGE_AVG, STATS_NULL} +}; + +#ifndef IDE_DISK_MAJOR +#define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \ + (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \ + (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \ + (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \ + (M) == IDE8_MAJOR || (M) == IDE9_MAJOR) +#endif /* !IDE_DISK_MAJOR */ + +#ifndef SCSI_DISK_MAJOR +#ifndef SCSI_DISK8_MAJOR +#define SCSI_DISK8_MAJOR 128 +#endif +#ifndef SCSI_DISK15_MAJOR +#define SCSI_DISK15_MAJOR 135 +#endif +#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ + ((M) >= SCSI_DISK1_MAJOR && \ + (M) <= SCSI_DISK7_MAJOR) || \ + ((M) >= SCSI_DISK8_MAJOR && \ + (M) <= SCSI_DISK15_MAJOR)) +#endif /* !SCSI_DISK_MAJOR */ + +#ifndef DEVMAP_MAJOR +#define DEVMAP_MAJOR 253 +#endif + +#ifndef COMPAQ_MAJOR +#define COMPAQ_CISS_MAJOR 104 +#define COMPAQ_CISS_MAJOR7 111 +#define COMPAQ_SMART2_MAJOR 72 +#define COMPAQ_SMART2_MAJOR7 79 +#define COMPAQ_MAJOR(M) (((M) >= COMPAQ_CISS_MAJOR && \ + (M) <= COMPAQ_CISS_MAJOR7) || \ + ((M) >= COMPAQ_SMART2_MAJOR && \ + (M) <= COMPAQ_SMART2_MAJOR7)) +#endif /* !COMPAQ_MAJOR */ + +void +handle_error(const char *string, int error) +{ + if (error) { + fputs("iostat: ", stderr); + if (errno) + perror(string); + else + fprintf(stderr, "%s\n", string); + exit(EXIT_FAILURE); + } +} + +int +printable(unsigned int major, unsigned int minor) +{ + if (IDE_DISK_MAJOR(major)) { + return (!(minor & 0x3F) && print_device) + || ((minor & 0x3F) && print_partition); + } else if (SCSI_DISK_MAJOR(major)) { + return (!(minor & 0x0F) && print_device) + || ((minor & 0x0F) && print_partition); + } else if(COMPAQ_MAJOR(major)){ + return (!(minor & 0x0F) && print_device) + || ((minor & 0x0F) && print_partition); + } + /* + } else if(DEVMAP_MAJOR == major){ + return 0; + } + */ + return 1; /* if uncertain, print it */ +} + +/* Get partition names. Check against match list */ +void +initialize() +{ + const char *scan_fmt = NULL; + + scan_fmt = "%4d %4d %31s %u"; + + while (fgets(buffer, sizeof(buffer), iofp)) { + unsigned int reads = 0; + struct part_info curr; + + if (sscanf(buffer, scan_fmt, &curr.major, &curr.minor, + curr.name, &reads) == 4) { + unsigned int p; + if (n_partitions >= max_partitions) { + break; + } + + for (p = 0; p < n_partitions + && (partition[p].major != curr.major + || partition[p].minor != curr.minor); + p++); + + if (p == n_partitions && p < MAX_PARTITIONS) { + if (reads && printable(curr.major, curr.minor)) { + partition[p] = curr; + n_partitions = p + 1; + } + } + } + } +} + +void +get_kernel_stats() +{ + const char *scan_fmt = NULL; + + scan_fmt = "%4d %4d %*s %u %u %llu %u %u %u %llu %u %*u %u %u"; + + rewind(iofp); + while (fgets(buffer, sizeof(buffer), iofp)) { + int items; + struct part_info curr; + struct blkio_info blkio; + memset(&blkio, 0, STATS_IO_SIZE); + items = sscanf(buffer, scan_fmt, + &curr.major, &curr.minor, + &blkio.rd_ios, &blkio.rd_merges, + &blkio.rd_sectors, &blkio.rd_ticks, + &blkio.wr_ios, &blkio.wr_merges, + &blkio.wr_sectors, &blkio.wr_ticks, + &blkio.ticks, &blkio.aveq); + + /* + * Unfortunately, we can report only transfer rates + * for partitions in 2.6 kernels, all other I/O + * statistics are unavailable. + */ + if (items == 6) { + blkio.rd_sectors = blkio.rd_merges; + blkio.wr_sectors = blkio.rd_ticks; + blkio.rd_ios = 0; + blkio.rd_merges = 0; + blkio.rd_ticks = 0; + blkio.wr_ios = 0; + blkio.wr_merges = 0; + blkio.wr_ticks = 0; + blkio.ticks = 0; + blkio.aveq = 0; + items = 12; + } + + if (items == 12) { + unsigned int p; + + /* Locate partition in data table */ + for (p = 0; p < n_partitions; p++) { + if (partition[p].major == curr.major + && partition[p].minor == curr.minor) { + new_blkio[p] = blkio; + break; + } + } + } + } +} + +/* + * Print out statistics. + * extended form is: + * read merges + * write merges + * read io requests + * write io requests + * kilobytes read + * kilobytes written + * average queue length + * average waiting time (queue + service) + * average service time at disk + * average disk utilization. + */ + +void +print_partition_stats(struct module *mod) +{ + int pos = 0; + char buf[LEN_1M]; + memset(buf, 0, LEN_1M); + unsigned int p; + + for (p = 0; p < n_partitions; p++) { + pos += snprintf(buf + pos, LEN_1M - pos, "%s=%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%d" ITEM_SPLIT, + partition[p].name, + new_blkio[p].rd_ios, + new_blkio[p].rd_merges, + new_blkio[p].rd_sectors, + new_blkio[p].rd_ticks, + new_blkio[p].wr_ios, + new_blkio[p].wr_merges, + new_blkio[p].wr_sectors, + new_blkio[p].wr_ticks, + new_blkio[p].ticks, + new_blkio[p].aveq, + pos); + if (strlen(buf) == LEN_1M - 1) { + fclose(iofp); + return; + } + } + set_mod_record(mod, buf); + rewind(iofp); + if (NULL != iofp) { + if (fclose(iofp) < 0) { + return; + } + iofp =NULL; + } + return; +} + +void +read_io_stat(struct module *mod, char *parameter) +{ + if (atoi(parameter) != 0) { + max_partitions = atoi(parameter); + } + setlinebuf(stdout); + /*open current io statistics file*/ + iofp = fopen(IO_FILE, "r"); + handle_error("Can't open /proc/diskstats", !iofp); + initialize(); + get_kernel_stats(); + print_partition_stats(mod); +} + +static void +set_io_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i, j; + for(i = 0; i < 11; i++){ + if(cur_array[i] < pre_array[i]){ + for(j = 0; j < 11; j++){ + st_array[j] = -1; + } + return; + } + } + unsigned long long rd_ios = cur_array[0] - pre_array[0]; + unsigned long long rd_merges = cur_array[1] - pre_array[1]; + unsigned long long rd_sectors = cur_array[2] - pre_array[2]; + unsigned long long rd_ticks = cur_array[3] - pre_array[3];; + unsigned long long wr_ios = cur_array[4] - pre_array[4]; + unsigned long long wr_merges = cur_array[5] - pre_array[5]; + unsigned long long wr_sectors = cur_array[6] - pre_array[6]; + unsigned long long wr_ticks = cur_array[7] - pre_array[7]; + unsigned long long ticks = cur_array[8] - pre_array[8]; + unsigned long long aveq = cur_array[9] - pre_array[9]; + double n_ios = rd_ios + wr_ios; + st_array[0] = rd_merges / (inter * 1.0); + st_array[1] = wr_merges / (inter * 1.0); + st_array[2] = rd_merges + rd_ios ? (double)rd_merges / (rd_merges + rd_ios) * 100 : 0.0; + st_array[3] = wr_merges + wr_ios ? (double)wr_merges / (wr_merges + wr_ios) * 100 : 0.0; + st_array[4] = rd_ios / (inter * 1.0); + st_array[5] = wr_ios / (inter * 1.0); + st_array[6] = rd_sectors / (inter * 1.0); + st_array[7] = wr_sectors / (inter * 1.0); + st_array[8] = n_ios ? (rd_sectors + wr_sectors) / (n_ios * 2) : 0.0; + st_array[9] = rd_ios ? rd_sectors / ((double)rd_ios * 2) : 0.0; + st_array[10] = wr_ios ? wr_sectors / ((double)wr_ios * 2) : 0.0; + st_array[11] = aveq / (inter * 1000); + st_array[12] = n_ios ? (rd_ticks + wr_ticks) / (double)n_ios : 0.0; + st_array[13] = rd_ios ? rd_ticks / (double)rd_ios : 0.0; + st_array[14] = wr_ios ? wr_ticks / (double)wr_ios : 0.0; + st_array[15] = n_ios ? ticks / n_ios : 0.0; + st_array[16] = ticks / (inter * 10.0); /* percentage! */ + if(st_array[16] > 100.0) + st_array[16] = 100.0; +} + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--io", io_usage, io_info, 17, read_io_stat, set_io_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_load.c b/source/tools/monitor/mservice/master/modules/mod_load.c new file mode 100644 index 00000000..d66bae3a --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_load.c @@ -0,0 +1,92 @@ +#include "tsar.h" + +#define LOAD_DETAIL_HDR(d) \ + " runq"d" plist"d" min1"d \ +" min5"d" min15" + +#define LOAD_STORE_FMT(d) \ + "%ld"d"%d"d"%d"d"%d"d"%d" + +char *load_usage = " --load System Run Queue and load average"; + +/* Structure for queue and load statistics */ +struct stats_load { + unsigned long nr_running; + unsigned int load_avg_1; + unsigned int load_avg_5; + unsigned int load_avg_15; + unsigned int nr_threads; +}; + +#define STATS_LOAD_SIZE (sizeof(struct stats_load)) + +void +read_stat_load(struct module *mod) +{ + int load_tmp[3]; + FILE *fp; + char buf[LEN_4096]; + struct stats_load st_load; + memset(buf, 0, LEN_4096); + memset(&st_load, 0, sizeof(struct stats_load)); + + if ((fp = fopen(LOADAVG, "r")) == NULL) { + return; + } + + /* Read load averages and queue length */ + if (fscanf(fp, "%d.%d %d.%d %d.%d %ld/%d %*d\n", + &load_tmp[0], &st_load.load_avg_1, + &load_tmp[1], &st_load.load_avg_5, + &load_tmp[2], &st_load.load_avg_15, + &st_load.nr_running, + &st_load.nr_threads) != 8) + { + fclose(fp); + return; + } + st_load.load_avg_1 += load_tmp[0] * 100; + st_load.load_avg_5 += load_tmp[1] * 100; + st_load.load_avg_15 += load_tmp[2] * 100; + + if (st_load.nr_running) { + /* Do not take current process into account */ + st_load.nr_running--; + } + + sprintf(buf , "%u,%u,%u,%lu,%u", + st_load.load_avg_1, + st_load.load_avg_5, + st_load.load_avg_15, + st_load.nr_running, + st_load.nr_threads); + set_mod_record(mod, buf); + fclose(fp); +} + +static void +set_load_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + for (i = 0; i < 3; i++) { + st_array[i] = cur_array[i] / 100.0; + } + st_array[3] = cur_array[3]; + st_array[4] = cur_array[4]; +} + +static struct mod_info load_info[] = { + {" load1", SUMMARY_BIT, 0, STATS_NULL}, + {" load5", DETAIL_BIT, 0, STATS_NULL}, + {"load15", DETAIL_BIT, 0, STATS_NULL}, + {" runq", DETAIL_BIT, 0, STATS_NULL}, + {" plit", DETAIL_BIT, 0, STATS_NULL} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--load", load_usage, load_info, 5, read_stat_load, set_load_record); +} + diff --git a/source/tools/monitor/mservice/master/modules/mod_lvs.c b/source/tools/monitor/mservice/master/modules/mod_lvs.c new file mode 100644 index 00000000..a008b262 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_lvs.c @@ -0,0 +1,231 @@ +#define _GNU_SOURCE +#include "tsar.h" + +#define LVS_PROC_STATS "/proc/net/ip_vs_stats" +#define LVS_CONN_PROC_STATS "/proc/net/ip_vs_conn_stats" + +#define LVS_CMD "sudo /usr/local/sbin/slb_admin -ln --total --dump" +#define LVS_CONN_CMD "sudo /usr/local/sbin/appctl -csa" + +#define LVS_CMD_PATH "/usr/local/sbin/slb_admin" +#define LVS_STORE_FMT(d) \ + "%lld"d"%lld"d"%lld"d"%lld"d"%lld"d"%lld"d\ + "%lld"d"%lld"d"%lld"d"%lld"d"%lld"d"%lld"d"%lld"d"%lld" +#define MAX_LINE_LEN 1024 +struct stats_lvs{ + unsigned long long stat; + unsigned long long conns; + unsigned long long pktin; + unsigned long long pktout; + unsigned long long bytin; + unsigned long long bytout; + + unsigned long long total_conns; /* total conns */ + unsigned long long local_conns; /* local conns */ + unsigned long long act_conns; /* active conns */ + unsigned long long inact_conns; /* inactive conns */ + unsigned long long sync_conns; /* sync conns */ + unsigned long long sync_act_conns; /* sync active conns */ + unsigned long long sync_inact_conns; /* sync inactive conns */ + unsigned long long template_conns; /* template conns */ +}; +#define STATS_LVS_SIZE (sizeof(struct stats_lvs)) + +static struct mod_info info[] = { + {" stat", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {" conns", SUMMARY_BIT, MERGE_NULL, STATS_SUB_INTER}, + {" pktin", DETAIL_BIT, MERGE_NULL, STATS_SUB_INTER}, + {"pktout", DETAIL_BIT, MERGE_NULL, STATS_SUB_INTER}, + {" bytin", DETAIL_BIT, MERGE_NULL, STATS_SUB_INTER}, + {"bytout", DETAIL_BIT, MERGE_NULL, STATS_SUB_INTER}, + {" total", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {" local", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {" lact", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {"linact", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {" sync", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {" sact", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {"sinact", DETAIL_BIT, MERGE_NULL, STATS_NULL}, + {" templ", DETAIL_BIT, MERGE_NULL, STATS_NULL}, +}; + +static char *lvs_usage = " --lvs lvs connections and packets and bytes in/out"; +struct stats_lvs st_lvs; +/* + ******************************************************* + * Read swapping statistics from ip_vs_stat + ******************************************************* + */ +static void +read_lvs_stat(int has_netframe) +{ + int i = 0, use_popen = 0; + char tmp[5][16]; + FILE *fp = NULL; + char line[MAX_LINE_LEN]; + + if (has_netframe) { + fp = popen(LVS_CMD, "r"); + use_popen = 1; + } else if (!access(LVS_PROC_STATS, F_OK)) + fp = fopen(LVS_PROC_STATS, "r"); + + if (!fp) + return; + + st_lvs.stat = 1; + while (fgets(line, MAX_LINE_LEN, fp) != NULL) { + i++; + if (i < 3) { + continue; + } + if (!strncmp(line, "CPU", 3)) { + /* CPU 0: 5462458943 44712664864 54084995692 8542115117674 41738811918899 */ + int k = 0; + k = strcspn(line, ":"); + sscanf(line + k + 1, "%s %s %s %s %s", tmp[0], tmp[1], tmp[2], tmp[3], tmp[4]); + st_lvs.conns += strtoll(tmp[0], NULL, 10); + st_lvs.pktin += strtoll(tmp[1], NULL, 10); + st_lvs.pktout += strtoll(tmp[2], NULL, 10); + st_lvs.bytin += strtoll(tmp[3], NULL, 10); + st_lvs.bytout += strtoll(tmp[4], NULL, 10); + } else { + /* 218EEA1A 1B3BA96D 0 163142140FA1F 0 */ + sscanf(line, "%s %s %s %s %s", tmp[0], tmp[1], tmp[2], tmp[3], tmp[4]); + st_lvs.conns += strtoll(tmp[0], NULL ,16); + st_lvs.pktin += strtoll(tmp[1], NULL, 16); + st_lvs.pktout += strtoll(tmp[2], NULL, 16); + st_lvs.bytin += strtoll(tmp[3], NULL, 16); + st_lvs.bytout += strtoll(tmp[4], NULL, 16); + break; + } + } + + if (use_popen) + pclose(fp); + else + fclose(fp); +} + +static void +read_lvs_conn_stat(int has_netframe) +{ + int use_popen = 0; + FILE *fp = NULL; + char line[MAX_LINE_LEN]; + + if (has_netframe) { + fp = popen(LVS_CONN_CMD, "r"); + use_popen = 1; + } else if (!access(LVS_CONN_PROC_STATS, F_OK)) + fp = fopen(LVS_CONN_PROC_STATS, "r"); + + if (!fp) + return; + + while (fgets(line, MAX_LINE_LEN, fp) != NULL) { + + if (has_netframe) { + unsigned long long *item = NULL; + + /* Example: + total_conns : 0 + local_conns : 0 + local_active_conns : 0 + local_inactive_conns : 0 + sync_conns : 0 + sync_active_conns : 0 + sync_inactive_conns : 0 + template_conns : 0 + */ + if (!strncmp(line, "total_conns", 11)) + item = &st_lvs.total_conns; + else if (!strncmp(line, "local_conns", 11)) + item = &st_lvs.local_conns; + else if (!strncmp(line, "local_active_conns", 18)) + item = &st_lvs.act_conns; + else if (!strncmp(line, "local_inactive_conns", 20)) + item = &st_lvs.inact_conns; + else if (!strncmp(line, "sync_conns", 10)) + item = &st_lvs.sync_conns; + else if (!strncmp(line, "sync_active_conns", 16)) + item = &st_lvs.sync_act_conns; + else if (!strncmp(line, "sync_inactive_conns", 18)) + item = &st_lvs.sync_inact_conns; + else if (!strncmp(line, "template_conns", 10)) + item = &st_lvs.template_conns; + + if (item) + *item = strtoll(strchr(line, ':') + 1, NULL, 10); + + } else { + /* Example: + PersistConns: 17 + + Total Local Sync LocAct SynAct LocInAct SynInAct Flush Flush + Conns Conns Conns Conns Conns Conns Conns Threshold State + CPU0 : 58094 14710 43384 9522 28133 5188 15251 0 N/A + CPU11: 49888 12589 37299 7657 22498 4932 14801 0 N/A + TOTAL: 603642 151514 452128 90610 269578 60904 182550 0 N/A + */ + if (!strncmp(line, "PersistConns", 12)) { + st_lvs.template_conns = strtoll(strchr(line, ':') + 1, NULL, 10); + } else if (!strncmp(line, "TOTAL", 5)) { + char tmp[7][16]; + + sscanf(strchr(line, ':') + 1, "%s %s %s %s %s %s %s", + tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6]); + + st_lvs.total_conns = strtoll(tmp[0], NULL, 10); + st_lvs.local_conns = strtoll(tmp[1], NULL, 10); + st_lvs.sync_conns = strtoll(tmp[2], NULL, 10); + st_lvs.act_conns = strtoll(tmp[3], NULL, 10); + st_lvs.sync_act_conns = strtoll(tmp[4], NULL, 10); + st_lvs.inact_conns = strtoll(tmp[5], NULL, 10); + st_lvs.sync_inact_conns = strtoll(tmp[6], NULL, 10); + } + } + } + + if (use_popen) + pclose(fp); + else + fclose(fp); +} + +static void +read_lvs(struct module *mod) +{ + char buf[512] = { 0 }; + int pos = 0, has_netframe = 0; + + memset(&st_lvs, 0, sizeof(struct stats_lvs)); + + if (!access(LVS_CMD_PATH, F_OK | X_OK)) + has_netframe = 1; + + read_lvs_stat(has_netframe); + + read_lvs_conn_stat(has_netframe); + + if (st_lvs.stat == 1) { + pos = sprintf(buf, LVS_STORE_FMT(DATA_SPLIT), + st_lvs.stat, st_lvs.conns, + st_lvs.pktin, st_lvs.pktout, st_lvs.bytin, st_lvs.bytout, + st_lvs.total_conns, st_lvs.local_conns, st_lvs.act_conns, st_lvs.inact_conns, + st_lvs.sync_conns, st_lvs.sync_act_conns, st_lvs.sync_inact_conns, + st_lvs.template_conns); + } else { + return; + } + + buf[pos] = '\0'; + set_mod_record(mod, buf); + return; +} + + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--lvs", lvs_usage, info, sizeof(info)/sizeof(struct mod_info), read_lvs, NULL); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_mem.c b/source/tools/monitor/mservice/master/modules/mod_mem.c new file mode 100644 index 00000000..c8fbef24 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_mem.c @@ -0,0 +1,126 @@ +#include "tsar.h" + +char *mem_usage = +" --mem Physical memory share (active, inactive, cached, free, wired)"; + +/* Structure for memory and swap space utilization statistics */ +struct stats_mem { + unsigned long frmkb; + unsigned long bufkb; + unsigned long camkb; + unsigned long tlmkb; + unsigned long acmkb; + unsigned long iamkb; + unsigned long slmkb; + unsigned long frskb; + unsigned long tlskb; + unsigned long caskb; + unsigned long comkb; +}; + +static void +read_mem_stats(struct module *mod) +{ + FILE *fp; + char line[LEN_128]; + char buf[LEN_4096]; + struct stats_mem st_mem; + + memset(buf, 0, LEN_4096); + memset(&st_mem, 0, sizeof(struct stats_mem)); + if ((fp = fopen(MEMINFO, "r")) == NULL) { + return; + } + + while (fgets(line, 128, fp) != NULL) { + + if (!strncmp(line, "MemTotal:", 9)) { + /* Read the total amount of memory in kB */ + sscanf(line + 9, "%lu", &st_mem.tlmkb); + } + else if (!strncmp(line, "MemFree:", 8)) { + /* Read the amount of free memory in kB */ + sscanf(line + 8, "%lu", &st_mem.frmkb); + } + else if (!strncmp(line, "Buffers:", 8)) { + /* Read the amount of buffered memory in kB */ + sscanf(line + 8, "%lu", &st_mem.bufkb); + } + else if (!strncmp(line, "Cached:", 7)) { + /* Read the amount of cached memory in kB */ + sscanf(line + 7, "%lu", &st_mem.camkb); + } + else if (!strncmp(line, "Active:", 7)) { + /* Read the amount of Active memory in kB */ + sscanf(line + 7, "%lu", &st_mem.acmkb); + } + else if (!strncmp(line, "Inactive:", 9)) { + /* Read the amount of Inactive memory in kB */ + sscanf(line + 9, "%lu", &st_mem.iamkb); + } + else if (!strncmp(line, "Slab:", 5)) { + /* Read the amount of Slab memory in kB */ + sscanf(line + 5, "%lu", &st_mem.slmkb); + } + else if (!strncmp(line, "SwapCached:", 11)) { + /* Read the amount of cached swap in kB */ + sscanf(line + 11, "%lu", &st_mem.caskb); + } + else if (!strncmp(line, "SwapTotal:", 10)) { + /* Read the total amount of swap memory in kB */ + sscanf(line + 10, "%lu", &st_mem.tlskb); + } + else if (!strncmp(line, "SwapFree:", 9)) { + /* Read the amount of free swap memory in kB */ + sscanf(line + 9, "%lu", &st_mem.frskb); + } + else if (!strncmp(line, "Committed_AS:", 13)) { + /* Read the amount of commited memory in kB */ + sscanf(line + 13, "%lu", &st_mem.comkb); + } + } + + int pos = sprintf(buf, "%lu,%u,%lu,%lu,%lu,%u", + st_mem.frmkb, + 0, /* used */ + st_mem.bufkb, + st_mem.camkb, + st_mem.tlmkb, + 0 /* util */); + buf[pos] = '\0'; + set_mod_record(mod, buf); + fclose(fp); + return; +} +static void +set_mem_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + if ((cur_array[4] - cur_array[0] -cur_array[2] -cur_array[3]) < 0) { + for (i = 0; i < 6; i++) + st_array[i] = -1; + return; + } + st_array[0] = cur_array[0]<<10; + st_array[1] = (cur_array[4] - cur_array[0] -cur_array[2] -cur_array[3])<<10; + st_array[2] = cur_array[2]<<10; + st_array[3] = cur_array[3]<<10; + st_array[4] = cur_array[4]<<10; + st_array[5] = st_array[1] * 100.0 / (cur_array[4]<<10); +} + +static struct mod_info mem_info[] = { + {" free", DETAIL_BIT, 0, STATS_NULL}, + {" used", DETAIL_BIT, 0, STATS_NULL}, + {" buff", DETAIL_BIT, 0, STATS_NULL}, + {" cach", DETAIL_BIT, 0, STATS_NULL}, + {" total", DETAIL_BIT, 0, STATS_NULL}, + {" util", SUMMARY_BIT, 0, STATS_NULL} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--mem", mem_usage, mem_info, 6, read_mem_stats, set_mem_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_ncpu.c b/source/tools/monitor/mservice/master/modules/mod_ncpu.c new file mode 100644 index 00000000..10dfa1d0 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_ncpu.c @@ -0,0 +1,119 @@ +#include "tsar.h" + +/* + * Structure for CPU infomation. + */ +struct stats_cpu { + unsigned long long cpu_user; + unsigned long long cpu_nice; + unsigned long long cpu_sys; + unsigned long long cpu_idle; + unsigned long long cpu_iowait; + unsigned long long cpu_steal; + unsigned long long cpu_hardirq; + unsigned long long cpu_softirq; + unsigned long long cpu_guest; +}; + +#define STATS_CPU_SIZE (sizeof(struct stats_cpu)) + +static char *cpu_usage = " --ncpu CPU share (user, system, interrupt, nice, & idle)"; + + +static void +read_cpu_stats(struct module *mod) +{ + int pos = 0; + char line[LEN_1M]; + char buf[LEN_1M]; + char cpuname[16]; + FILE *fp; + struct stats_cpu st_cpu; + + memset(buf, 0, LEN_1M); + memset(&st_cpu, 0, sizeof(struct stats_cpu)); + if ((fp = fopen(STAT, "r")) == NULL) { + return; + } + while (fgets(line, LEN_1M, fp) != NULL) { + if (!strncmp(line, "cpu", 3)) { + /* + * Read the number of jiffies spent in the different modes + * (user, nice, etc.) among all proc. CPU usage is not reduced + * to one processor to avoid rounding problems. + */ + sscanf(line, "%s", cpuname); + if(strcmp(cpuname, "cpu") == 0) + continue; + sscanf(line + strlen(cpuname), "%llu %llu %llu %llu %llu %llu %llu %llu %llu", + &st_cpu.cpu_user, + &st_cpu.cpu_nice, + &st_cpu.cpu_sys, + &st_cpu.cpu_idle, + &st_cpu.cpu_iowait, + &st_cpu.cpu_hardirq, + &st_cpu.cpu_softirq, + &st_cpu.cpu_steal, + &st_cpu.cpu_guest); + + pos += snprintf(buf + pos, LEN_1M - pos, "%s=%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu" ITEM_SPLIT, + /* the store order is not same as read procedure */ + cpuname, + st_cpu.cpu_user, + st_cpu.cpu_sys, + st_cpu.cpu_iowait, + st_cpu.cpu_hardirq, + st_cpu.cpu_softirq, + st_cpu.cpu_idle, + st_cpu.cpu_nice, + st_cpu.cpu_steal, + st_cpu.cpu_guest); + if (strlen(buf) == LEN_1M - 1) { + fclose(fp); + return; + } + } + } + set_mod_record(mod, buf); + fclose(fp); + return; +} + +static void +set_cpu_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + U_64 pre_total, cur_total; + pre_total = cur_total = 0; + + for (i = 0; i < mod->n_col; i++) { + pre_total += pre_array[i]; + cur_total += cur_array[i]; + } + /* set st record */ + for (i = 0; i <= 4; i++) { + if(cur_array[i] >= pre_array[i]) + st_array[i] = (cur_array[i] - pre_array[i]) * 100.0 / (cur_total - pre_total); + } + if(cur_array[5] >= pre_array[5]) + st_array[5] = 100.0 - (cur_array[5] - pre_array[5]) * 100.0 / (cur_total - pre_total); +} + +static struct mod_info cpu_info[] = { + {" user", DETAIL_BIT, 0, STATS_NULL}, + {" sys", DETAIL_BIT, 0, STATS_NULL}, + {" wait", DETAIL_BIT, 0, STATS_NULL}, + {" hirq", DETAIL_BIT, 0, STATS_NULL}, + {" sirq", DETAIL_BIT, 0, STATS_NULL}, + {" util", SUMMARY_BIT, 0, STATS_NULL}, + {" nice", HIDE_BIT, 0, STATS_NULL}, + {" steal", HIDE_BIT, 0, STATS_NULL}, + {" guest", HIDE_BIT, 0, STATS_NULL}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--ncpu", cpu_usage, cpu_info, 9, read_cpu_stats, set_cpu_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_nginx.c b/source/tools/monitor/mservice/master/modules/mod_nginx.c new file mode 100644 index 00000000..0d375e13 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_nginx.c @@ -0,0 +1,290 @@ +#include +#include +#include +#include +#include +#include "tsar.h" + +struct stats_nginx { + unsigned long long naccept; /* accepted connections */ + unsigned long long nhandled; /* handled connections */ + unsigned long long nrequest; /* handled requests */ + unsigned long long nactive; /* number of all open connections including connections to backends */ + unsigned long long nreading; /* nginx reads request header */ + unsigned long long nwriting; /* nginx reads request body, processes request, or writes response to a client */ + unsigned long long nwaiting; /* keep-alive connections, actually it is active - (reading + writing) */ + unsigned long long nrstime; /* reponse time of handled requests */ + unsigned long long nspdy; /* spdy requests */ + unsigned long long nsslhds; /* ssl handshake */ + unsigned long long nssl; /* ssl requests */ + unsigned long long nsslk; /* ssl keepalive requests */ + unsigned long long nsslf; /* ssl failed request */ + unsigned long long nsslv3f; /* sslv3 failed request */ + unsigned long long nhttp2; /* http2 requests */ +}; + +struct hostinfo { + char *host; + int port; + char *server_name; + char *uri; +}; + +static char *nginx_usage = " --nginx nginx statistics"; + +static struct mod_info nginx_info[] = { + {"accept", DETAIL_BIT, 0, STATS_SUB}, + {"handle", DETAIL_BIT, 0, STATS_SUB}, + {" reqs", DETAIL_BIT, 0, STATS_SUB}, + {"active", DETAIL_BIT, 0, STATS_NULL}, + {" read", DETAIL_BIT, 0, STATS_NULL}, + {" write", DETAIL_BIT, 0, STATS_NULL}, + {" wait", DETAIL_BIT, 0, STATS_NULL}, + {" qps", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {" rt", SUMMARY_BIT, 0, STATS_NULL}, + {"sslqps", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {"spdyps", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {" sslf", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {"sslv3f", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {" h2qps", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {"sslhds", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {" sslk", SUMMARY_BIT, 0, STATS_SUB_INTER}, +}; + + +static void +set_nginx_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + for (i = 0; i < 3; i++) { + if (cur_array[i] >= pre_array[i]) { + st_array[i] = cur_array[i] - pre_array[i]; + } else { + st_array[i] = 0; + } + } + + for (i = 3; i < 7; i++) { + st_array[i] = cur_array[i]; + } + + if (cur_array[2] >= pre_array[2]) { + st_array[7] = (cur_array[2] - pre_array[2]) * 1.0 / inter; + } else { + st_array[7] = 0; + } + + if (cur_array[8] >= pre_array[8]) { + if (cur_array[2] > pre_array[2]) { + st_array[8] = (cur_array[8] - pre_array[8]) * 1.0 / (cur_array[2] - pre_array[2]); + } else { + st_array[8] = 0; + } + } + + for (i = 9; i < 16; i++){ + if (cur_array[i] >= pre_array[i]) { + st_array[i] = (cur_array[i] - pre_array[i]) * 1.0 / inter; + } else { + st_array[i] = 0; + } + } +} + + +static void +init_nginx_host_info(struct hostinfo *p) +{ + char *port; + + p->host = getenv("NGX_TSAR_HOST"); + p->host = p->host ? p->host : "127.0.0.1"; + + port = getenv("NGX_TSAR_PORT"); + p->port = port ? atoi(port) : 80; + + p->uri = getenv("NGX_TSAR_URI"); + p->uri = p->uri ? p->uri : "/nginx_status"; + + p->server_name = getenv("NGX_TSAR_SERVER_NAME"); + p->server_name = p->server_name ? p->server_name : "status.taobao.com"; +} + + +static void +read_nginx_stats(struct module *mod, char *parameter) +{ + int write_flag = 0, addr_len, domain; + int m, sockfd, send, pos; + void *addr; + char buf[LEN_4096], request[LEN_4096], line[LEN_4096]; + FILE *stream = NULL; + + struct timeval timeout; + struct hostinfo hinfo; + struct sockaddr_in servaddr; + struct sockaddr_un servaddr_un; + + + init_nginx_host_info(&hinfo); + if (atoi(parameter) != 0) { + hinfo.port = atoi(parameter); + } + struct stats_nginx st_nginx; + memset(&st_nginx, 0, sizeof(struct stats_nginx)); + + if (*hinfo.host == '/') { + addr = &servaddr_un; + addr_len = sizeof(servaddr_un); + bzero(addr, addr_len); + domain = AF_LOCAL; + servaddr_un.sun_family = AF_LOCAL; + strncpy(servaddr_un.sun_path, hinfo.host, sizeof(servaddr_un.sun_path) - 1); + + } else { + addr = &servaddr; + addr_len = sizeof(servaddr); + bzero(addr, addr_len); + domain = AF_INET; + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(hinfo.port); + inet_pton(AF_INET, hinfo.host, &servaddr.sin_addr); + } + + if ((sockfd = socket(domain, SOCK_STREAM, 0)) == -1) { + goto writebuf; + } + + sprintf(request, + "GET %s HTTP/1.0\r\n" + "User-Agent: taobot\r\n" + "Host: %s\r\n" + "Accept:*/*\r\n" + "Connection: Close\r\n\r\n", + hinfo.uri, hinfo.server_name); + + if ((m = connect(sockfd, (struct sockaddr *) addr, addr_len)) == -1 ) { + goto writebuf; + } + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval)); + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval)); + + if ((send = write(sockfd, request, strlen(request))) == -1) { + goto writebuf; + } + + if ((stream = fdopen(sockfd, "r")) == NULL) { + goto writebuf; + } + + while (fgets(line, LEN_4096, stream) != NULL) { + if (!strncmp(line, "Active connections:", sizeof("Active connections:") - 1)) { + sscanf(line + sizeof("Active connections:"), "%llu", &st_nginx.nactive); + write_flag = 1; + } else if (!strncmp(line, + "server accepts handled requests request_time", + sizeof("server accepts handled requests request_time") - 1) + ) { + /*for tengine*/ + if (fgets(line, LEN_4096, stream) != NULL) { + if (!strncmp(line, " ", 1)) { + sscanf(line + 1, "%llu %llu %llu %llu", + &st_nginx.naccept, &st_nginx.nhandled, &st_nginx.nrequest, &st_nginx.nrstime); + write_flag = 1; + } + } + } else if (!strncmp(line, + "server accepts handled requests", + sizeof("server accepts handled requests") - 1) + ) { + /*for nginx*/ + if (fgets(line, LEN_4096, stream) != NULL) { + if (!strncmp(line, " ", 1)) { + sscanf(line + 1, "%llu %llu %llu", + &st_nginx.naccept, &st_nginx.nhandled, &st_nginx.nrequest); + write_flag = 1; + } + } + } else if (!strncmp(line, "Server accepts:", sizeof("Server accepts:") - 1)) { + sscanf(line , "Server accepts: %llu handled: %llu requests: %llu request_time: %llu", + &st_nginx.naccept, &st_nginx.nhandled, &st_nginx.nrequest, &st_nginx.nrstime); + write_flag = 1; + + } else if (!strncmp(line, "Reading:", sizeof("Reading:") - 1)) { + sscanf(line, "Reading: %llu Writing: %llu Waiting: %llu", + &st_nginx.nreading, &st_nginx.nwriting, &st_nginx.nwaiting); + write_flag = 1; + } else if (!strncmp(line, "SSL:", sizeof("SSL:") - 1)) { + sscanf(line, "SSL: %llu SPDY: %llu", + &st_nginx.nssl, &st_nginx.nspdy); + write_flag = 1; + } else if (!strncmp(line, "HTTP2:", sizeof("HTTP2:") - 1)) { + sscanf(line, "HTTP2: %llu", + &st_nginx.nhttp2); + write_flag = 1; + } else if (!strncmp(line, "SSL_failed:", sizeof("SSL_failed:") - 1)) { + sscanf(line, "SSL_failed: %llu", + &st_nginx.nsslf); + write_flag = 1; + } else if (!strncmp(line, "SSLv3_failed:", sizeof("SSLv3_failed:") - 1)) { + sscanf(line, "SSLv3_failed: %llu", + &st_nginx.nsslv3f); + write_flag = 1; + } else if (!strncmp(line, "SSL_handshake:", sizeof("SSL_handshake:") - 1)) { + sscanf(line, "SSL_handshake: %llu", + &st_nginx.nsslhds); + write_flag = 1; + } else if (!strncmp(line, "SSL_keepalive_reqs:", sizeof("SSL_keepalive_reqs:") - 1)) { + sscanf(line, "SSL_keepalive_reqs: %llu", + &st_nginx.nsslk); + write_flag = 1; + } else { + ; + } + } + if (st_nginx.nrequest == 0) { + write_flag = 0; + } + +writebuf: + if (stream) { + fclose(stream); + } + + if (sockfd != -1) { + close(sockfd); + } + + if (write_flag) { + pos = sprintf(buf, "%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld", + st_nginx.naccept, + st_nginx.nhandled, + st_nginx.nrequest, + st_nginx.nactive, + st_nginx.nreading, + st_nginx.nwriting, + st_nginx.nwaiting, + st_nginx.nrequest, + st_nginx.nrstime, + st_nginx.nssl, + st_nginx.nspdy, + st_nginx.nsslf, + st_nginx.nsslv3f, + st_nginx.nhttp2, + st_nginx.nsslhds, + st_nginx.nsslk + ); + buf[pos] = '\0'; + set_mod_record(mod, buf); + } +} + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--nginx", nginx_usage, nginx_info, 16, read_nginx_stats, set_nginx_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_partition.c b/source/tools/monitor/mservice/master/modules/mod_partition.c new file mode 100644 index 00000000..0b75f4a0 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_partition.c @@ -0,0 +1,139 @@ +#include +#include +#include "tsar.h" + +#define TRUE 1 +#define FALSE 0 + +char *partition_usage = " --partition Disk and partition usage"; + + +#define MAXPART 32 + +struct stats_partition { + int bsize; /* block size*/ + unsigned long long blocks; /* total blocks*/ + unsigned long long bfree; /* free for non root user*/ + unsigned long long bavail; /* avail for root*/ + unsigned long long itotal; + unsigned long long ifree; +}; +#define STATS_PARTITION_SIZE (sizeof(struct stats_partition)) + +int +__read_partition_stat(char *fsname, struct stats_partition *sp) +{ + struct statfs fsbuf; + if (!statfs(fsname, &fsbuf)) { + sp->bsize = fsbuf.f_bsize; + sp->blocks = fsbuf.f_blocks; + sp->bfree = fsbuf.f_bfree; + sp->bavail = fsbuf.f_bavail; + sp->itotal = fsbuf.f_files; + sp->ifree = fsbuf.f_ffree; + } + return 0; +} + +int +store_single_partition(char *buf, char *mntpath, struct stats_partition *sp, int size) +{ + int len = 0; + int k = 1; + if (sp->bsize % 1024 != 0) { + return len; + } else { + k = sp->bsize / 1024; + } + len += snprintf(buf + len, size, "%s=%d,%lld,%lld,%lld,%lld,%lld" ITEM_SPLIT, + mntpath, + sp->bsize / k, + sp->bfree * k, + sp->blocks * k, + sp->bavail * k, + sp->ifree, + sp->itotal); + return len; +} + + +void +read_partition_stat(struct module *mod) +{ + int part_nr, pos = 0; + char buf[LEN_1M]; + FILE *mntfile; + struct mntent *mnt = NULL; + struct stats_partition temp; + + memset(buf, 0, LEN_1M); + memset(&temp, 0, sizeof(temp)); + + /* part_nr = count_partition_nr(NULL); */ + + mntfile = setmntent("/etc/mtab", "r"); + + /* init part_nr */ + part_nr = 0; + /* traverse the mount table */ + while ((mnt = getmntent(mntfile)) != NULL) { + /* only recore block filesystems */ + if (! strncmp(mnt->mnt_fsname, "/", 1)) { + /* we only read MAXPART partition */ + if (part_nr >= MAXPART) break; + /* read each partition infomation */ + __read_partition_stat(mnt->mnt_dir, &temp); + + /* print log to the buffer */ + pos += store_single_partition(buf + pos, mnt->mnt_dir, &temp, LEN_1M - pos); + if (strlen(buf) == LEN_1M - 1) { + return; + } + /* successful read */ + part_nr++; + /* move the pointer to the next structure */ + } + } + endmntent(mntfile); + set_mod_record(mod, buf); + return; +} + +static void +set_part_record(struct module *mod, double st_array[], U_64 pre_array[], U_64 cur_array[], int inter) +{ + st_array[0] = cur_array[3] * cur_array[0]; + st_array[1] = (cur_array[2] - cur_array[1]) * cur_array[0]; + st_array[2] = cur_array[2] * cur_array[0]; + + U_64 used = cur_array[2] - cur_array[1]; + U_64 nonroot_total = cur_array[2] - cur_array[1] + cur_array[3]; + + if(nonroot_total != 0) { + st_array[3]= (used * 100.0) / nonroot_total + ((used * 100) % nonroot_total != 0); + } + if (st_array[3] > 100) { + st_array[3] = 100; + } + st_array[4] = cur_array[4]; + st_array[5] = cur_array[5]; + if (cur_array[5] >= cur_array[4] && cur_array[5] != 0) { + st_array[6] = (cur_array[5] - cur_array[4]) * 100.0 / cur_array[5]; + } +} + +static struct mod_info part_info[] = { + {" bfree", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" bused", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" btotl", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" util", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" ifree", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" itotl", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" iutil", DETAIL_BIT, MERGE_SUM, STATS_NULL}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--partition", partition_usage, part_info, 7, read_partition_stat, set_part_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_pcsw.c b/source/tools/monitor/mservice/master/modules/mod_pcsw.c new file mode 100644 index 00000000..413c9365 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_pcsw.c @@ -0,0 +1,67 @@ +#include "tsar.h" + + +char *pcsw_usage = " --pcsw Process (task) creation and context switch"; + +struct stats_pcsw { + unsigned long long context_switch; + unsigned long processes; +}; + +#define STATS_PCSW_SIZE sizeof(struct pcsw_stats) + +enum {PROC, CSWCH}; + + +/* + *************************************************************************** + * Read processes (tasks) creation and context switches statistics from + * /proc/stat + * + *************************************************************************** + */ +void +read_stat_pcsw(struct module *mod) +{ + FILE *fp; + char line[LEN_4096]; + char buf[LEN_4096]; + struct stats_pcsw st_pcsw; + + memset(buf, 0, LEN_4096); + memset(&st_pcsw, 0, sizeof(struct stats_pcsw)); + + if ((fp = fopen(STAT, "r")) == NULL) { + return; + } + while (fgets(line, LEN_4096, fp) != NULL) { + + if (!strncmp(line, "ctxt ", 5)) { + /* Read number of context switches */ + sscanf(line + 5, "%llu", &st_pcsw.context_switch); + } + + else if (!strncmp(line, "processes ", 10)) { + /* Read number of processes created since system boot */ + sscanf(line + 10, "%lu", &st_pcsw.processes); + } + } + int pos = sprintf(buf, "%lld,%ld", + st_pcsw.context_switch, + st_pcsw.processes); + buf[pos] = '\0'; + set_mod_record(mod, buf); + fclose(fp); +} + +static struct mod_info pcsw_info[] = { + {" cswch", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" proc", DETAIL_BIT, 0, STATS_SUB_INTER} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--pcsw", pcsw_usage, pcsw_info, 2, read_stat_pcsw, NULL); +} + diff --git a/source/tools/monitor/mservice/master/modules/mod_percpu.c b/source/tools/monitor/mservice/master/modules/mod_percpu.c new file mode 100644 index 00000000..9cb32568 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_percpu.c @@ -0,0 +1,129 @@ +#include "tsar.h" + +#define STAT_PATH "/proc/stat" + +static char *percpu_usage = " --percpu Per cpu share (user, system, interrupt, nice, & idle)"; + +struct stats_percpu { + unsigned long long cpu_user; + unsigned long long cpu_nice; + unsigned long long cpu_sys; + unsigned long long cpu_idle; + unsigned long long cpu_iowait; + unsigned long long cpu_steal; + unsigned long long cpu_hardirq; + unsigned long long cpu_softirq; + unsigned long long cpu_guest; + char cpu_name[10]; +}; + +#define STATS_PERCPU_SIZE (sizeof(struct stats_percpu)) + +static void +read_percpu_stats(struct module *mod) +{ + int pos = 0, cpus = 0; + FILE *fp; + char line[LEN_1M]; + char buf[LEN_1M]; + struct stats_percpu st_percpu; + + memset(buf, 0, LEN_1M); + memset(&st_percpu, 0, STATS_PERCPU_SIZE); + if ((fp = fopen(STAT_PATH, "r")) == NULL) { + return; + } + while (fgets(line, LEN_1M, fp) != NULL) { + if (!strncmp(line, "cpu", 3)) { + /* + * Read the number of jiffies spent in the different modes + * (user, nice, etc.) among all proc. CPU usage is not reduced + * to one processor to avoid rounding problems. + */ + sscanf(line, "%s %llu %llu %llu %llu %llu %llu %llu %llu %llu", + st_percpu.cpu_name, + &st_percpu.cpu_user, + &st_percpu.cpu_nice, + &st_percpu.cpu_sys, + &st_percpu.cpu_idle, + &st_percpu.cpu_iowait, + &st_percpu.cpu_hardirq, + &st_percpu.cpu_softirq, + &st_percpu.cpu_steal, + &st_percpu.cpu_guest); + if (st_percpu.cpu_name[3] == '\0') //ignore cpu summary stat + continue; + + pos += snprintf(buf + pos, LEN_1M - pos, "%s=%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu" ITEM_SPLIT, + /* the store order is not same as read procedure */ + st_percpu.cpu_name, + st_percpu.cpu_user, + st_percpu.cpu_sys, + st_percpu.cpu_iowait, + st_percpu.cpu_hardirq, + st_percpu.cpu_softirq, + st_percpu.cpu_idle, + st_percpu.cpu_nice, + st_percpu.cpu_steal, + st_percpu.cpu_guest); + if (strlen(buf) == LEN_1M - 1) { + fclose(fp); + return; + } + cpus++; + } + } + set_mod_record(mod, buf); + fclose(fp); + return; +} + +static void +set_percpu_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i, j; + U_64 pre_total, cur_total; + pre_total = cur_total = 0; + + for (i = 0; i < mod->n_col; i++) { + if(cur_array[i] < pre_array[i]){ + for(j = 0; j < 9; j++) + st_array[j] = -1; + return; + } + pre_total += pre_array[i]; + cur_total += cur_array[i]; + } + + /* no tick changes, or tick overflows */ + if (cur_total <= pre_total) + return; + /* set st record */ + for (i = 0; i < 9; i++) { + /* st_array[5] is util, calculate it late */ + if((i != 5) && (cur_array[i] >= pre_array[i])) + st_array[i] = (cur_array[i] - pre_array[i]) * 100.0 / (cur_total - pre_total); + } + + /* util = user + sys + hirq + sirq + nice */ + st_array[5] = st_array[0] + st_array[1] + st_array[3] + st_array[4] + st_array[6]; +} + +static struct mod_info percpu_info[] = { + {" user", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" sys", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" wait", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" hirq", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" sirq", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" util", SUMMARY_BIT, MERGE_SUM, STATS_NULL}, + {" nice", HIDE_BIT, MERGE_SUM, STATS_NULL}, + {" steal", HIDE_BIT, MERGE_SUM, STATS_NULL}, + {" guest", HIDE_BIT, MERGE_SUM, STATS_NULL}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--percpu", percpu_usage, percpu_info, 9, read_percpu_stats, set_percpu_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_pernic.c b/source/tools/monitor/mservice/master/modules/mod_pernic.c new file mode 100644 index 00000000..ba6bd2ef --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_pernic.c @@ -0,0 +1,90 @@ +#include "tsar.h" + +char *pernic_usage = " --pernic Net pernic statistics"; + +#define MAX_NICS 8 + +/* + * Structure for pernic infomation. + */ +struct stats_pernic { + unsigned long long bytein; + unsigned long long byteout; + unsigned long long pktin; + unsigned long long pktout; + char name[16]; +}; + +#define STATS_TRAFFIC_SIZE (sizeof(struct stats_pernic)) + + +/* + * collect pernic infomation + */ +static void +read_pernic_stats(struct module *mod) +{ + int pos = 0, nics = 0; + FILE *fp; + char line[LEN_1M] = {0}; + char buf[LEN_1M] = {0}; + struct stats_pernic st_pernic; + + memset(buf, 0, LEN_1M); + memset(&st_pernic, 0, sizeof(struct stats_pernic)); + + if ((fp = fopen(NET_DEV, "r")) == NULL) { + return; + } + + while (fgets(line, LEN_1M, fp) != NULL) { + memset(&st_pernic, 0, sizeof(st_pernic)); + if (!strstr(line, ":")) { + continue; + } + sscanf(line, "%*[^a-z]%[^:]:%llu %llu %*u %*u %*u %*u %*u %*u " + "%llu %llu %*u %*u %*u %*u %*u %*u", + st_pernic.name, + &st_pernic.bytein, + &st_pernic.pktin, + &st_pernic.byteout, + &st_pernic.pktout); + /* if nic not used, skip it */ + if (st_pernic.bytein == 0) { + continue; + } + + pos += snprintf(buf + pos, LEN_1M - pos, "%s=%lld,%lld,%lld,%lld" ITEM_SPLIT, + st_pernic.name, + st_pernic.bytein, + st_pernic.byteout, + st_pernic.pktin, + st_pernic.pktout); + if (strlen(buf) == LEN_1M - 1) { + fclose(fp); + return; + } + + nics++; + if (nics > MAX_NICS) { + break; + } + } + + set_mod_record(mod, buf); + fclose(fp); + return; +} + +static struct mod_info pernic_info[] = { + {" bytin", SUMMARY_BIT, MERGE_SUM, STATS_SUB_INTER}, + {"bytout", SUMMARY_BIT, MERGE_SUM, STATS_SUB_INTER}, + {" pktin", DETAIL_BIT, MERGE_SUM, STATS_SUB_INTER}, + {"pktout", DETAIL_BIT, MERGE_SUM, STATS_SUB_INTER} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--pernic", pernic_usage, pernic_info, 4, read_pernic_stats, NULL); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_proc.c b/source/tools/monitor/mservice/master/modules/mod_proc.c new file mode 100644 index 00000000..eaae236b --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_proc.c @@ -0,0 +1,216 @@ +#include "tsar.h" + +/* + * Structure for Proc infomation. + */ +struct stats_proc { + unsigned long long user_cpu; + unsigned long long sys_cpu; + unsigned long long total_cpu; + unsigned long long mem; + unsigned long long total_mem; + unsigned long long read_bytes; + unsigned long long write_bytes; +}; + +#define PID_IO "/proc/%u/io" +#define PID_STAT "/proc/%u/stat" +#define PID_STATUS "/proc/%u/status" +#define STATS_PROC_SIZE (sizeof(struct stats_proc)) + +static char *proc_usage = " --proc PROC info (mem cpu usage & io/fd info)"; + + +static void +read_proc_stats(struct module *mod, char *parameter) +{ + int nb = 0, pid[16]; + char buf[LEN_4096]; + char filename[128], line[256]; + FILE *fp; + struct stats_proc st_proc; + + memset(&st_proc, 0, sizeof(struct stats_proc)); + + /* get pid by proc name */ + if (strlen(parameter) > 20) { + return; + } + char cmd[32] = "pidof "; + strncat(cmd, parameter, sizeof(cmd) - strlen(cmd) -1); + char spid[256]; + fp = popen(cmd, "r"); + if (fp == NULL) { + return; + } + if(fscanf(fp, "%s", spid) == EOF) { + pclose(fp); + return; + } + pclose(fp); + /* split pidof into array pid */ + char *p; + p = strtok(spid, " "); + while (p) { + pid[nb] = atoi(p); + if (pid[nb++] <= 0) { + return; + } + if (nb >= 16) { + return; + } + p = strtok(NULL, " "); + } + /* get all pid's info */ + while (--nb >= 0) { + unsigned long long data; + /* read values from /proc/pid/stat */ + sprintf(filename, PID_STAT, pid[nb]); + if ((fp = fopen(filename, "r")) == NULL) { + return; + } + unsigned long long cpudata[4]; + if (fgets(line, 256, fp) == NULL) { + fclose(fp); + return; + } + + if ((p = strstr(line, ")")) == NULL) { + fclose(fp); + return; + } + if (sscanf(p, "%*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu %llu %llu", + &cpudata[0], &cpudata[1], &cpudata[2], &cpudata[3]) == EOF) { + fclose(fp); + return; + } + st_proc.user_cpu += cpudata[0]; + st_proc.user_cpu += cpudata[2]; + st_proc.sys_cpu += cpudata[1]; + st_proc.sys_cpu += cpudata[3]; + fclose(fp); + /* get cpu&mem info from /proc/pid/status */ + sprintf(filename, PID_STATUS, pid[nb]); + if ((fp = fopen(filename, "r")) == NULL) { + return; + } + while (fgets(line, 256, fp) != NULL) { + if (!strncmp(line, "VmRSS:", 6)) { + sscanf(line + 6, "%llu", &data); + st_proc.mem += data * 1024; + } + } + fclose(fp); + /* get io info from /proc/pid/io */ + sprintf(filename, PID_IO, pid[nb]); + if ((fp = fopen(filename, "r")) == NULL) { + return; + } + while (fgets(line, 256, fp) != NULL) { + if (!strncmp(line, "read_bytes:", 11)) { + sscanf(line + 11, "%llu", &data); + st_proc.read_bytes += data; + } + else if (!strncmp(line, "write_bytes:", 12)) { + sscanf(line + 12, "%llu", &data); + st_proc.write_bytes += data; + } + } + fclose(fp); + } + + /* read+calc cpu total time from /proc/stat */ + fp = fopen("/proc/stat", "r"); + if (fp == NULL) { + fclose(fp); + return; + } + unsigned long long cpu_time[10]; + bzero(cpu_time, sizeof(cpu_time)); + if (fscanf(fp, "%*s %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", + &cpu_time[0], &cpu_time[1], &cpu_time[2], &cpu_time[3], + &cpu_time[4], &cpu_time[5], &cpu_time[6], &cpu_time[7], + &cpu_time[8], &cpu_time[9]) == EOF) { + fclose(fp); + return; + } + fclose(fp); + int i; + for(i=0; i < 10;i++) { + st_proc.total_cpu += cpu_time[i]; + } + /* read total mem from /proc/meminfo */ + fp = fopen("/proc/meminfo", "r"); + if (fp == NULL) { + fclose(fp); + return; + } + if (fscanf(fp, "MemTotal: %llu kB", &st_proc.total_mem) == EOF) { + fclose(fp); + return; + } + st_proc.total_mem *= 1024; + fclose(fp); + /* store data to tsar */ + int pos = sprintf(buf, "%lld,%lld,%lld,%lld,%lld,%lld,%lld", + st_proc.user_cpu, + st_proc.sys_cpu, + st_proc.total_cpu, + st_proc.total_mem, + st_proc.mem, + st_proc.read_bytes, + st_proc.write_bytes + ); + if (pos >= 0) buf[pos] = '\0'; + set_mod_record(mod, buf); +} + +static void +set_proc_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + if (cur_array[2] > pre_array[2]) { + st_array[2] = cur_array[2] - pre_array[2]; + } else { + st_array[2] = 0; + return; + } + if (cur_array[0] >= pre_array[0]) { + st_array[0] = (cur_array[0] - pre_array[0]) * 100.0 / st_array[2]; + } else { + st_array[0] = 0; + } + if (cur_array[1] >= pre_array[1]) { + st_array[1] = (cur_array[1] - pre_array[1]) * 100.0 / st_array[2]; + } else { + st_array[1] = 0; + } + st_array[3] = cur_array[4] * 100.0 / cur_array[3]; + st_array[4] = cur_array[4]; + if (cur_array[5] >= pre_array[5]) { + st_array[5] = (cur_array[5] - pre_array[5]) * 1.0 / inter; + } else { + st_array[5] = 0; + } + if (cur_array[6] >= pre_array[6]) { + st_array[6] = (cur_array[6] - pre_array[6]) * 1.0 / inter; + } else { + st_array[5] = 0; + } +} + +static struct mod_info proc_info[] = { + {" user", SUMMARY_BIT, 0, STATS_NULL}, + {" sys", SUMMARY_BIT, 0, STATS_NULL}, + {" total", HIDE_BIT, 0, STATS_NULL}, + {" mem", SUMMARY_BIT, 0, STATS_NULL}, + {" RSS", DETAIL_BIT, 0, STATS_NULL}, + {" read", DETAIL_BIT, 0, STATS_NULL}, + {" write", DETAIL_BIT, 0, STATS_NULL}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--proc", proc_usage, proc_info, 7, read_proc_stats, set_proc_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_squid.c b/source/tools/monitor/mservice/master/modules/mod_squid.c new file mode 100644 index 00000000..63c97790 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_squid.c @@ -0,0 +1,656 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tsar.h" + + +#define RETRY_NUM 3 + +char *squid_usage = " --squid Squid utilities"; + +struct stats_squid { + int usable; + struct squid_counters + { + struct counters_client { + unsigned long long http_requests; + unsigned long long http_hits; + unsigned long long http_kbytes_out; + unsigned long long http_hit_kbytes_out; + + } cc; + struct counters_server { + unsigned long long all_requests; + unsigned long long all_kbytes_in; + unsigned long long all_kbytes_out; + } cs; + } sc; + struct squid_info { + struct mem_usage { + unsigned long long mem_total; + unsigned long long mem_free; + unsigned long long mem_size; + } mu; + struct fd_usage { + unsigned int fd_used; + unsigned int fd_queue; + } fu; + struct info_internal_data { + unsigned int entries; + unsigned int memobjs; + unsigned int hotitems; + } iid; + struct squid_float { + unsigned long long meanobjsize; + unsigned long long responsetime; + unsigned long long disk_hit; + unsigned long long mem_hit; + unsigned long long http_hit_rate; + unsigned long long byte_hit_rate; + } sf; + } si; +}; + + +#define STATS_SQUID_SIZE (sizeof(struct stats_squid)) +#define MAXSQUID 10 + +/* + * here we defined a pointer to a array of structure + * we should call the member like: + * + * (*(s_st_squid + p_idx))[idx].member + * + */ +//typedef struct __stats_squid (* stats_squid)[2]; + +struct stats_squid s_st_squid[MAXSQUID]; + +struct p_squid_info { + struct squid_counters *scp; + struct squid_info * sip; +}; + +#define DIGITS "0123456789" +#define LEFT 0 +#define RIGHT 1 +#define SQUIDDIGITS "0123456789-" +#define MAXINT 2147483647 + +char *key[] = { + "client_http.requests", + "client_http.hits", + "client_http.kbytes_out", + "client_http.hit_kbytes_out" +}; + +char *key_info[] = { + "Total in use", + "Total free", + "Total size", + "Number of file desc currently in use", + "Files queued for open", + "StoreEntries", + "StoreEntries with MemObjects", + "Hot Object Cache Items", + "Mean Object Size", +}; + +char *key_float[] = { + "Average HTTP respone time", + "Mean Object Size:", + "Request Memory Hit Ratios:", + "Request Filesystem Hit Ratios:", + "Request Hit Ratios:", + "Byte Hit Ratios:", + "Request Disk Hit Ratios:", + "HTTP Requests (All):", +}; + +char * +a_trim(char *str, int len) +{ + int i = 0; + char *dest = NULL, *l_str; + dest = (char *)malloc(len); + if (dest == NULL ){ + return NULL; + } + l_str = str; + if (l_str == NULL) { + free(dest); + return NULL; + } + while (*l_str++ != '\0' && len--) { + if (*l_str != ' ' && *l_str != '\t') { + dest[i++] = *l_str; + } + } + dest[i] = '\0'; + return dest; +} + +int +read_a_int_value(char *buf, char *key, unsigned int *ret, int type) +{ + int k; + char *tmp; + /* is str match the keywords? */ + if ((tmp = strstr(buf, key)) != NULL) { + /* is number befor the key string? */ + if (type == LEFT) { + tmp = buf; + } + /* compute the offset */ + k = strcspn(tmp, DIGITS); + sscanf(tmp + k, "%d", ret); + return 1; + + } else { + return 0; + } +} + +int +read_a_long_long_value(char *buf, char *key, unsigned long long *ret, int type) +{ + int k; + char *tmp; + /* is str match the keywords? */ + if ((tmp = strstr(buf, key)) != NULL) { + + /* is number befor the key string? */ + if (type == LEFT) { + tmp = buf; + } + /* compute the offset */ + k = strcspn(tmp, DIGITS); + sscanf(tmp + k, "%lld", ret); + return 1; + + } else { + return 0; + } +} + +/*add for squidclient when counter is nagtive*/ +int +read_a_long_long_value_squid(char *buf, char *key, unsigned long long *ret, int type) +{ + int k; + char *tmp; + /* is str match the keywords? */ + if ((tmp = strstr(buf, key)) != NULL) { + + /* is number befor the key string? */ + if (type == LEFT) { + tmp = buf; + } + /* compute the offset */ + k = strcspn(tmp, SQUIDDIGITS); + sscanf(tmp + k, "%lld", ret); + if (*ret > MAXINT) { + *ret += MAXINT; + } + return 1; + + } else { + return 0; + } +} + +int +read_a_float_value(char *buf, char *key, unsigned long long *ret, int type, int len) +{ + int k; + int r, l; + char *tmp; + char *tmp2; + /* is str match the keywords? */ + if ((tmp = strstr(buf, key)) != NULL) { + + /* is number befor the key string? */ + if (type == LEFT) { + tmp = buf; + } + /* skip the trial number like 5min:*/ + if ((tmp2 = strstr(tmp, "min")) != NULL) { + tmp = tmp2; + } + /* compute the offset */ + k = strcspn(tmp, DIGITS); + sscanf(tmp + k, "%d.%d", &r, &l); + *ret = (unsigned long long)r * len + l; + return 1; + + } else { + return 0; + } +} + +void +collect_cnts(char *l, struct squid_counters *sc) +{ + read_a_long_long_value_squid(l, key[0], + &sc->cc.http_requests, RIGHT); + + read_a_long_long_value(l, key[1], + &sc->cc.http_hits, RIGHT); + + read_a_long_long_value(l, key[2], + &sc->cc.http_kbytes_out, RIGHT); + + read_a_long_long_value(l, key[3], + &sc->cc.http_hit_kbytes_out, RIGHT); +} + + +void +collect_info(char *l, struct squid_info *si) +{ + read_a_long_long_value(l, key_info[0], + &si->mu.mem_total, RIGHT); + + read_a_long_long_value(l, key_info[1], + &si->mu.mem_free, RIGHT); + + read_a_long_long_value(l, key_info[2], + &si->mu.mem_size, RIGHT); + + read_a_int_value(l, key_info[3], + &si->fu.fd_used, RIGHT); + + read_a_int_value(l, key_info[4], + &si->fu.fd_queue, RIGHT); + + /* here don't confuse the order */ + if (read_a_int_value(l, key_info[6], + &si->iid.memobjs, LEFT)) + { + return; + } + + read_a_int_value(l, key_info[5], + &si->iid.entries, LEFT); + + read_a_int_value(l, key_info[7], + &si->iid.hotitems, LEFT); + + read_a_float_value(l, key_float[0], + &si->sf.responsetime, + RIGHT, 100); + + read_a_float_value(l, key_float[1], + &si->sf.meanobjsize, + RIGHT, 100); + read_a_float_value(l, key_float[3], + &si->sf.disk_hit, + RIGHT, 10); + read_a_float_value(l, key_float[2], + &si->sf.mem_hit, + RIGHT, 10); + read_a_float_value(l, key_float[4], + &si->sf.http_hit_rate, + RIGHT, 10); + read_a_float_value(l, key_float[5], + &si->sf.byte_hit_rate, + RIGHT, 10); + read_a_float_value(l, key_float[6], + &si->sf.disk_hit, + RIGHT, 10); + read_a_float_value(l, key_float[7], + &si->sf.responsetime, + RIGHT, 100000); + +} + +int port_list[MAXSQUID] = {0}; + +static int squid_nr = 0; +static int live_squid_nr = 0; + +void +count_squid_nr() +{ + DIR *dp; + char *s_token, *e_token; + static char tmp_s_port[32] = {0}; + struct dirent *dirp; + squid_nr = 0; + if (!(dp = opendir("/etc/squid/"))) { + return; + } + while ((dirp = readdir(dp))) + { + s_token = strstr(dirp->d_name, "squid."); + if (s_token) { + e_token = strstr(s_token + 6, ".conf"); + if (e_token && *(e_token + 5) == '\0') { + memset(tmp_s_port, 0, sizeof(tmp_s_port)); + memcpy(tmp_s_port, s_token + 6, e_token - s_token - 6); + port_list[squid_nr++] = atoi(tmp_s_port); + } + } + } + if (squid_nr > MAXSQUID) { + squid_nr = MAXSQUID; + } + closedir(dp); +} + + +ssize_t +mywrite(int fd, void *buf, size_t len) +{ + return send(fd, buf, len, 0); +} + +ssize_t +myread(int fd, void *buf, size_t len) +{ + return recv(fd, buf, len, 0); +} + +int +client_comm_connect(int sock, const char *dest_host, u_short dest_port, struct timeval *tvp) +{ + int flags, res; + fd_set fdr, fdw; + struct timeval timeout; + struct sockaddr_in to_addr; + const struct hostent *hp = NULL; + + /* set socket fd noblock */ + if ((flags = fcntl(sock, F_GETFL, 0)) < 0) { + return -1; + } + + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { + return -1; + } + + /* Set up the destination socket address for message to send to. */ + if (hp == NULL) { + to_addr.sin_family = AF_INET; + + if ((hp = gethostbyname(dest_host)) == 0) + return (-1); + memcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length); + to_addr.sin_port = htons(dest_port); + } + if (connect(sock, (struct sockaddr *) &to_addr, sizeof(struct sockaddr_in)) != 0) { + if (errno != EINPROGRESS) { + return -1; + + } else { + goto select; + } + + } else { + return -1; + } +select: + FD_ZERO(&fdr); + FD_ZERO(&fdw); + FD_SET(sock, &fdr); + FD_SET(sock, &fdw); + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + res = select(sock + 1, &fdr, &fdw, NULL, &timeout); + if (res < 0) { + return -1; + + } else if (res == 0) { + return -1; + + } else { + return 1; + } +} + +int +parse_squid_info(char *buf, char *cmd, struct p_squid_info *p_si) +{ + char *line; + line = strtok(buf, "\n"); + + while (line != NULL) { + if (!strcmp(cmd, "counters")) { + collect_cnts(line, p_si->scp); + + } else if (!strcmp(cmd, "info")) { + collect_info(line, p_si->sip); + + } else { + fprintf(stderr, "unknown command\n"); + return -1; + } + line = strtok(NULL, "\n"); + } + + if (!strcmp(cmd, "counters") && p_si->scp->cc.http_requests == 0) { + return -1; + } + if (!strcmp(cmd, "info") && p_si->sip->sf.responsetime == 0) { + /* return -1;*/ + } + return 0; +} + +int +__get_squid_info(char *squidoption, char *squidcmd, int port, int index) +{ + char buf[LEN_4096]; + char *hostname = "localhost"; + int len, conn, bytesWritten, fsize = 0; + struct p_squid_info psi = {&s_st_squid[index].sc, &s_st_squid[index].si}; + + if ((conn = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + close(conn); + return -1; + } + if (client_comm_connect(conn, hostname, port, NULL) < 0) { + close(conn); + return -1; + } + int flags; + /* set socket fd noblock */ + if ((flags = fcntl(conn, F_GETFL, 0)) < 0) { + close(conn); + return -1; + } + if (fcntl(conn, F_SETFL, flags & ~O_NONBLOCK) < 0) { + close(conn); + return -1; + } + struct timeval timeout = {10, 0}; + setsockopt(conn, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval)); + setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval)); + + bytesWritten = mywrite(conn, squidcmd, strlen(squidcmd)); + if (bytesWritten < 0) { + close(conn); + return -2; + + } else if (bytesWritten != strlen(squidcmd)) { + close(conn); + return -3; + } + while ((len = myread(conn, buf, sizeof(buf) - fsize -1)) > 0) { + fsize += len; + } + buf[fsize] = '\0'; + /* read error */ + if (fsize < 1000) { + close(conn); + return -1; + } + + if (parse_squid_info(buf, squidoption, &psi) < 0) { + close(conn); + return -1; + } + close(conn); + return 0; + +} + +int +__read_squid_stat(int port, int index) +{ + int i; + /* fullfil the raw infomation here + for each port */ + char *options[2] = {"info", "counters"}; + char msg[2][LEN_512]; + + /* we have two command 'info' & 'counters' to run */ + for (i = 0; i < 2; i++) { + sprintf(msg[i], + "GET cache_object://localhost/%s " + "HTTP/1.1\r\n" + "Host: localhost\r\n" + "Accept:*/*\r\n" + "Connection: close\r\n\r\n", + options[i]); + if (__get_squid_info(options[i], msg[i], port, index) < 0) { + return -1; + } + } + return 0; +} + +int +store_single_port(char *buf, char *itemname, int i) +{ + int len = 0; + len += sprintf(buf, "%s=", itemname); + /* print single port info to buffer here */ + len += sprintf(buf + len, + "%llu,%llu,%llu,%llu,%llu,%llu," + "%u,%u,%u,%u,%u,%llu,%u,%u", + s_st_squid[i].sc.cc.http_requests, + s_st_squid[i].si.sf.responsetime, + s_st_squid[i].si.sf.http_hit_rate, + s_st_squid[i].si.sf.byte_hit_rate, + s_st_squid[i].si.sf.disk_hit, + s_st_squid[i].si.sf.mem_hit, + s_st_squid[i].si.fu.fd_used, + s_st_squid[i].si.fu.fd_queue, + s_st_squid[i].si.iid.entries, + s_st_squid[i].si.iid.memobjs, + s_st_squid[i].si.iid.hotitems, + s_st_squid[i].si.sf.meanobjsize, + squid_nr, + live_squid_nr); + return len; +} + +void +read_squid_stat(struct module *mod, char *parameter) +{ + int i, pos = 0; + char buf[LEN_4096] = {0}; + char itemname[LEN_4096] = {0}; + live_squid_nr = 0; + + count_squid_nr(); + if (squid_nr == 0) { + if (atoi(parameter) != 0) { + port_list[0] = atoi(parameter); + squid_nr = 1; + } else { + port_list[0] = 3128; + squid_nr = 1; + } + } + + memset(s_st_squid, 0, STATS_SQUID_SIZE * MAXSQUID); + /*get the live squid number*/ + for (i = 0; i < squid_nr; i++) { + int retry = 0; + /* read on each port and retry to get squidclient for 3 times*/ + while (__read_squid_stat(port_list[i], i) < 0 && retry < RETRY_NUM) { + retry++; + } + if (retry == RETRY_NUM) { + continue; + } + s_st_squid[i].usable = TRUE; + live_squid_nr++; + } + + /* traverse the port list */ + for (i = 0; i < squid_nr; i++) { + if (!s_st_squid[i].usable) { + continue; + } + /* generate the item name */ + int n = sprintf(itemname, "port%d", port_list[i]); + itemname[n] = '\0'; + + /* print log to buffer */ + pos += store_single_port(buf + pos, itemname, i); + /* print a seperate char */ + pos += sprintf(buf + pos, ITEM_SPLIT); + } + if (pos && squid_nr == live_squid_nr) { + buf[pos] = '\0'; + set_mod_record(mod, buf); + } +} + + +static void +set_squid_record(struct module *mod, double st_array[], U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + + /* set st record */ + if (cur_array[0] >= pre_array[0]) { + st_array[0] = (cur_array[0] - pre_array[0]) / inter; + + } else { + st_array[0] = 0; + } + st_array[1] = cur_array[1] / 100.0; + for (i = 2; i <= 5; i++) st_array[i] = cur_array[i] / 10.0; + for (i = 6; i <= 10; i++) st_array[i] = cur_array[i]; + st_array[11] = (cur_array[11] << 10) / 100.0; + st_array[12] = cur_array[12]; + st_array[13] = cur_array[13]; +} + +static struct mod_info s_info[] = { + {" qps", SUMMARY_BIT, MERGE_SUM, STATS_SUB_INTER}, + {" rt", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" r_hit", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" b_hit", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" d_hit", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" m_hit", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {"fdused", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" fdque", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" objs", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" inmem", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" hot", DETAIL_BIT, MERGE_SUM, STATS_NULL}, + {" size", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {"totalp", DETAIL_BIT, MERGE_AVG, STATS_NULL}, + {" livep", DETAIL_BIT, MERGE_AVG, STATS_NULL} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--squid", squid_usage, s_info, 14, read_squid_stat, set_squid_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_swap.c b/source/tools/monitor/mservice/master/modules/mod_swap.c new file mode 100644 index 00000000..4dbbc65e --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_swap.c @@ -0,0 +1,100 @@ +#include "tsar.h" + +struct stats_swap { + unsigned long long pswpin; + unsigned long long pswpout; + unsigned long long swaptotal; + unsigned long long swapfree; +}; + + +#define STATS_SWAP_SIZE (sizeof(struct stats_swap)) + +static char *swap_usage = " --swap swap usage"; + +/* + ************************************************************* + * Read swapping statistics from /proc/vmstat & /proc/meminfo. + ************************************************************* + */ +static void +read_vmstat_swap(struct module *mod) +{ + FILE *fp; + char line[LEN_4096], buf[LEN_4096]; + struct stats_swap st_swap; + + memset(buf, 0, LEN_4096); + memset(&st_swap, 0, sizeof(struct stats_swap)); + /* read /proc/vmstat*/ + if ((fp = fopen(VMSTAT, "r")) == NULL) { + return ; + } + + while (fgets(line, LEN_4096, fp) != NULL) { + + if (!strncmp(line, "pswpin ", 7)) { + /* Read number of swap pages brought in */ + sscanf(line + 7, "%llu", &st_swap.pswpin); + + } else if (!strncmp(line, "pswpout ", 8)) { + /* Read number of swap pages brought out */ + sscanf(line + 8, "%llu", &st_swap.pswpout); + } + } + fclose(fp); + /* read /proc/meminfo */ + if ((fp = fopen(MEMINFO, "r")) == NULL) { + return; + } + + while (fgets(line, LEN_4096, fp) != NULL) { + if (!strncmp(line, "SwapTotal:", 10)) { + sscanf(line + 10, "%llu", &st_swap.swaptotal); + + } else if (!strncmp(line, "SwapFree:", 9)) { + sscanf(line + 9, "%llu", &st_swap.swapfree); + } + } + fclose(fp); + + sprintf(buf, "%lld,%lld,%lld,%lld", st_swap.pswpin, st_swap.pswpout, st_swap.swaptotal*1024, st_swap.swapfree*1024); + set_mod_record(mod, buf); + return; +} + +static void +set_swap_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + if (cur_array[0] >= pre_array[0]) { + st_array[0] = (cur_array[0] - pre_array[0]) / inter; + + } else { + st_array[0] = 0; + } + + if (cur_array[1] >= pre_array[1]) { + st_array[1] = (cur_array[1] - pre_array[1]) / inter; + + } else { + st_array[1] = 0; + } + + /* calc total swap and use util */ + st_array[2] = cur_array[2]; + st_array[3] = 100.0 - cur_array[3] * 100.0 / cur_array[2]; +} + +static struct mod_info swap_info[] = { + {" swpin", DETAIL_BIT, 0, STATS_NULL}, + {"swpout", DETAIL_BIT, 0, STATS_NULL}, + {" total", DETAIL_BIT, 0, STATS_NULL}, + {" util", DETAIL_BIT, 0, STATS_NULL} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--swap", swap_usage, swap_info, 4, read_vmstat_swap, set_swap_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_tcp.c b/source/tools/monitor/mservice/master/modules/mod_tcp.c new file mode 100644 index 00000000..0ea61d4e --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_tcp.c @@ -0,0 +1,113 @@ +#include "tsar.h" + + +char *tcp_usage = +" --tcp TCP traffic (v4)"; + +/* Structure for TCP statistics */ +struct stats_tcp { + unsigned long long ActiveOpens; + unsigned long long PassiveOpens; + unsigned long long InSegs; + unsigned long long OutSegs; + unsigned long long AttemptFails; + unsigned long long EstabResets; + unsigned long long CurrEstab; + unsigned long long RetransSegs; + unsigned long long InErrs; + unsigned long long OutRsts; +}; + +#define STATS_TCP_SIZE (sizeof(struct stats_tcp)) + +void +read_tcp_stats(struct module *mod) +{ + int sw = FALSE; + FILE *fp; + char line[LEN_1024]; + char buf[LEN_1024]; + struct stats_tcp st_tcp; + + memset(buf, 0, LEN_1024); + memset(&st_tcp, 0, sizeof(struct stats_tcp)); + if ((fp = fopen(NET_SNMP, "r")) == NULL) { + return; + } + + while (fgets(line, LEN_1024, fp) != NULL) { + if (!strncmp(line, "Tcp:", 4)) { + if (sw) { + sscanf(line + 4, "%*u %*u %*u %*d %llu %llu " + "%llu %llu %llu %llu %llu %llu %llu %llu", + &st_tcp.ActiveOpens, + &st_tcp.PassiveOpens, + &st_tcp.AttemptFails, + &st_tcp.EstabResets, + &st_tcp.CurrEstab, + &st_tcp.InSegs, + &st_tcp.OutSegs, + &st_tcp.RetransSegs, + &st_tcp.InErrs, + &st_tcp.OutRsts); + break; + + } else { + sw = TRUE; + } + } + } + + fclose(fp); + + int pos = sprintf(buf, "%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld", + st_tcp.ActiveOpens, + st_tcp.PassiveOpens, + st_tcp.InSegs, + st_tcp.OutSegs, + st_tcp.EstabResets, + st_tcp.AttemptFails, + st_tcp.CurrEstab, + st_tcp.RetransSegs); + + buf[pos] = '\0'; + set_mod_record(mod, buf); +} + +static void +set_tcp_record(struct module *mod, double st_array[], + U_64 pre_array[], U_64 cur_array[], int inter) +{ + int i; + for (i = 0; i < 6; i++) { + if (cur_array[i] >= pre_array[i]) { + st_array[i] = (cur_array[i] - pre_array[i]) * 1.0 / inter; + } + } + /* 6 is for st_tcp.CurrEstab */ + st_array[6] = cur_array[6]; + /* as for st_tcp.RetransSegs, we calculate the retransfer radio. Retrans/outSegs */ + if ((cur_array[7] >= pre_array[7]) && (cur_array[3] > pre_array[3])) { + st_array[7] = (cur_array[7]- pre_array[7]) * 100.0 / (cur_array[3]- pre_array[3]); + } + if (st_array[7] > 100.0) { + st_array[7] = 100.0; + } +} + +static struct mod_info tcp_info[] = { + {"active", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"pasive", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" iseg", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"outseg", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"EstReset", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"AtmpFail", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"CurrEstab", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"retran", SUMMARY_BIT, 0, STATS_SUB_INTER} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--tcp", tcp_usage, tcp_info, 8, read_tcp_stats, set_tcp_record); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_tcpx.c b/source/tools/monitor/mservice/master/modules/mod_tcpx.c new file mode 100644 index 00000000..f8b7c5ca --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_tcpx.c @@ -0,0 +1,137 @@ +#include "tsar.h" + +char * tcpx_usage=" --tcpx TCP connection data"; + +struct stats_tcpx{ + unsigned long long tcprecvq; + unsigned long long tcpsendq; + unsigned long long tcpest; + unsigned long long tcptimewait; + unsigned long long tcpfinwait1; + unsigned long long tcpfinwait2; + unsigned long long tcplistenq; + unsigned long long tcplistenincq; + unsigned long long tcplistenover; + unsigned long long tcpnconnest; + unsigned long long tcpnconndrop; + unsigned long long tcpembdrop; + unsigned long long tcprexmitdrop; + unsigned long long tcppersistdrop; + unsigned long long tcpkadrop; +}; + +static void +read_stat_tcpx(struct module *mod) +{ + int sw; + FILE *fp_tcp; + FILE *fp_snmp; + FILE *fp_netstat; + char buf[LEN_4096], line[LEN_4096]; + struct stats_tcpx st_tcpx; + + memset(buf, 0, LEN_4096); + memset(&st_tcpx, 0, sizeof(struct stats_tcpx)); + + fp_tcp = fopen(TCP, "r"); + if (fp_tcp == NULL) { + return; + } + + fp_snmp = fopen(NET_SNMP, "r"); + if (fp_snmp == NULL) { + fclose(fp_tcp); + return; + } + fp_netstat = fopen(NETSTAT, "r"); + if (fp_netstat == NULL) { + fclose(fp_snmp); + fclose(fp_tcp); + return; + } + st_tcpx.tcplistenq = 0; + st_tcpx.tcplistenincq = 0; + + sw = 0; + while (fgets(line, LEN_4096, fp_netstat) !=NULL) { + if (!strncmp(line, "TcpExt:", 7)) { + if (!sw) {sw = 1; continue;} + sscanf(line + 7, + "%*u %*u %*u %*u %*u %*u %*u %*u %*u " + "%*u %*u %*u %*u %*u %*u %*u %*u %*u " + "%*u %llu %*u %*u %*u %*u %*u %*u %*u " + "%*u %*u %*u %*u %*u %*u %*u %*u %*u " + "%*u %*u %*u %*u %*u %*u %*u %*u %*u " + "%*u %*u %*u %*u %*u %*u %*u %*u %*u " + "%*u %*u %*u %llu %*u %*u %*u %llu", + &st_tcpx.tcplistenover, + &st_tcpx.tcpembdrop, + &st_tcpx.tcprexmitdrop); + break; + } + } + sw = 0; + unsigned long activeopen, passiveopen; + activeopen = 0; + passiveopen = 0; + while (fgets(line, LEN_4096, fp_snmp) !=NULL) { + if (!strncmp(line, "Tcp:", 4)) { + if (!sw) {sw = 1; continue;} + sscanf(line + 4, "%*u %*u %*u %*d %lu %lu", + &activeopen, &passiveopen); + break; + } + } + + st_tcpx.tcpnconnest = activeopen + passiveopen; + st_tcpx.tcpnconndrop = 0; + st_tcpx.tcppersistdrop = 0; + st_tcpx.tcpkadrop = 0; + + sprintf(buf, + "%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu," + "%llu,%llu,%llu,%llu,%llu,%llu,%llu", + st_tcpx.tcprecvq, + st_tcpx.tcpsendq, + st_tcpx.tcpest, + st_tcpx.tcptimewait, + st_tcpx.tcpfinwait1, + st_tcpx.tcpfinwait2, + st_tcpx.tcplistenq, + st_tcpx.tcplistenincq, + st_tcpx.tcplistenover, + st_tcpx.tcpnconnest, + st_tcpx.tcpnconndrop, + st_tcpx.tcpembdrop, + st_tcpx.tcprexmitdrop, + st_tcpx.tcppersistdrop, + st_tcpx.tcpkadrop); + set_mod_record(mod, buf); + fclose(fp_tcp); + fclose(fp_snmp); + fclose(fp_netstat); +} + +static struct mod_info tcpx_info[]={ + {" recvq", DETAIL_BIT, 0, STATS_NULL}, + {" sendq", DETAIL_BIT, 0, STATS_NULL}, + {" est", DETAIL_BIT, 0, STATS_NULL}, + {" twait", DETAIL_BIT, 0, STATS_NULL}, + {"fwait1", DETAIL_BIT, 0, STATS_NULL}, + {"fwait2", DETAIL_BIT, 0, STATS_NULL}, + {" lisq", DETAIL_BIT, 0, STATS_NULL}, + {"lising", DETAIL_BIT, 0, STATS_NULL}, + {"lisove", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" cnest", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" ndrop", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" edrop", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" rdrop", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" pdrop", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" kdrop", DETAIL_BIT, 0, STATS_SUB_INTER}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--tcpx", tcpx_usage, tcpx_info, 15, read_stat_tcpx, NULL); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_traffic.c b/source/tools/monitor/mservice/master/modules/mod_traffic.c new file mode 100644 index 00000000..658b3afa --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_traffic.c @@ -0,0 +1,114 @@ +#include "tsar.h" + +char *traffic_usage = " --traffic Net traffic statistics"; + +/* + * Structure for traffic infomation. + */ +struct stats_traffic { + unsigned long long bytein; + unsigned long long byteout; + unsigned long long pktin; + unsigned long long pktout; + unsigned long long pkterrin; + unsigned long long pktdrpin; + unsigned long long pkterrout; + unsigned long long pktdrpout; +} ; + +#define STATS_TRAFFIC_SIZE (sizeof(struct stats_traffic)) + + +/* + * collect traffic infomation + */ +static void +read_traffic_stats(struct module *mod, char *parameter) +{ + int len = 0, num = 0, n_prefix = 3, i; + FILE *fp; + char *p = NULL; + char line[LEN_4096] = {0}; + char buf[LEN_4096] = {0}; + char mod_parameter[LEN_256], *token; + char *prefixes[10] = {"eth", "em", "en"}; + struct stats_traffic total_st, cur_st; + + memset(buf, 0, LEN_4096); + memset(&total_st, 0, sizeof(struct stats_traffic)); + memset(&cur_st, 0, sizeof(struct stats_traffic)); + + if ((fp = fopen(NET_DEV, "r")) == NULL) { + return; + } + + memset(&total_st, 0, sizeof(cur_st)); + + if (parameter != NULL) { + strncpy(mod_parameter, parameter, LEN_256); + token = strtok(mod_parameter, W_SPACE); + while (token != NULL && n_prefix < 10) { + prefixes[n_prefix++] = token; + token = strtok(NULL, W_SPACE); + } + } + + while (fgets(line, LEN_4096, fp) != NULL) { + for (i = 0; i < n_prefix; i++) { + if (strstr(line, prefixes[i])) { + memset(&cur_st, 0, sizeof(cur_st)); + p = strchr(line, ':'); + sscanf(p + 1, "%llu %llu %llu %llu %*u %*u %*u %*u " + "%llu %llu %llu %llu %*u %*u %*u %*u", + &cur_st.bytein, + &cur_st.pktin, + &cur_st.pkterrin, + &cur_st.pktdrpin, + &cur_st.byteout, + &cur_st.pktout, + &cur_st.pkterrout, + &cur_st.pktdrpout); + + num++; + total_st.bytein += cur_st.bytein; + total_st.byteout += cur_st.byteout; + total_st.pktin += cur_st.pktin; + total_st.pktout += cur_st.pktout; + total_st.pkterrin += cur_st.pkterrin; + total_st.pktdrpin += cur_st.pktdrpin; + total_st.pkterrout += cur_st.pkterrout; + total_st.pktdrpout += cur_st.pktdrpout; + + break; + } + } + } + + len = sprintf(buf, "%lld,%lld,%lld,%lld,%lld,%lld", + total_st.bytein, + total_st.byteout, + total_st.pktin, + total_st.pktout, + total_st.pkterrin + total_st.pkterrout, + total_st.pktdrpin + total_st.pktdrpout); + buf[len] = '\0'; + if(num > 0) { + set_mod_record(mod, buf); + } + fclose(fp); +} + +static struct mod_info traffic_info[] ={ + {" bytin", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {"bytout", SUMMARY_BIT, 0, STATS_SUB_INTER}, + {" pktin", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"pktout", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"pkterr", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"pktdrp", DETAIL_BIT, 0, STATS_SUB_INTER} +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--traffic", traffic_usage, traffic_info, 6, read_traffic_stats, NULL); +} diff --git a/source/tools/monitor/mservice/master/modules/mod_udp.c b/source/tools/monitor/mservice/master/modules/mod_udp.c new file mode 100644 index 00000000..e1f63ad5 --- /dev/null +++ b/source/tools/monitor/mservice/master/modules/mod_udp.c @@ -0,0 +1,73 @@ +#include "tsar.h" + +#define UDP_DETAIL_HDR(d) \ + " idgm"d" odgm"d"noport"d"idmerr" + +char *udp_usage = +" --udp UDP traffic (v4)"; + +/* Structure for UDP statistics */ +struct stats_udp { + unsigned long long InDatagrams; + unsigned long long OutDatagrams; + unsigned long long NoPorts; + unsigned long long InErrors; +}; + +#define STATS_UDP_SIZE (sizeof(struct stats_udp)) + +void +read_udp_stats(struct module *mod) +{ + int sw = FALSE; + FILE *fp; + char line[LEN_1024]; + char buf[LEN_1024]; + struct stats_udp st_udp; + + memset(buf, 0, LEN_1024); + memset(&st_udp, 0, sizeof(struct stats_udp)); + if ((fp = fopen(NET_SNMP, "r")) == NULL) { + return; + } + + while (fgets(line, LEN_1024, fp) != NULL) { + + if (!strncmp(line, "Udp:", 4)) { + if (sw) { + sscanf(line + 4, "%llu %llu %llu %llu", + &st_udp.InDatagrams, + &st_udp.NoPorts, + &st_udp.InErrors, + &st_udp.OutDatagrams); + break; + + } else { + sw = TRUE; + } + } + } + + fclose(fp); + + int pos = sprintf(buf, "%lld,%lld,%lld,%lld", + st_udp.InDatagrams, + st_udp.OutDatagrams, + st_udp.NoPorts, + st_udp.InErrors); + buf[pos] = '\0'; + set_mod_record(mod, buf); +} + +static struct mod_info udp_info[] = { + {" idgm", DETAIL_BIT, 0, STATS_SUB_INTER}, + {" odgm", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"noport", DETAIL_BIT, 0, STATS_SUB_INTER}, + {"idmerr", DETAIL_BIT, 0, STATS_SUB_INTER}, +}; + +void +mod_register(struct module *mod) +{ + register_mod_fields(mod, "--udp", udp_usage, udp_info, 4, read_udp_stats, NULL); +} diff --git a/source/tools/monitor/mservice/master/src/.gitignore b/source/tools/monitor/mservice/master/src/.gitignore new file mode 100644 index 00000000..b672fdea --- /dev/null +++ b/source/tools/monitor/mservice/master/src/.gitignore @@ -0,0 +1 @@ +obj diff --git a/source/tools/monitor/mservice/master/src/Makefile b/source/tools/monitor/mservice/master/src/Makefile new file mode 100644 index 00000000..56e28f60 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/Makefile @@ -0,0 +1,31 @@ +CC = gcc +SRC = tsar.c config.c debug.c framework.c output_file.c output_print.c output_db.c output_tcp.c output_nagios.c httpserver.c common.c +OBJ = $(patsubst %.c, %.o,$(SRC)) + +BIN = mservice + +ODIR = obj + +CFLAGS = -MD -g -O2 -Wall -I../include -I$(ODIR)/include +LDFLAGS += -lm -ldl -rdynamic -lpthread + +all: $(BIN) + +$(BIN): $(OBJ) + @echo LINK $(BIN) + $(CC) $^ -o $(BIN) -I$(INCLUDE_DIR) $(CFLAGS) $(LDFLAGS) + +$(OBJ): $(ODIR) + +$(ODIR)/%.o : %.c + @echo CC $< + @$(CC) $(CFLAGS) -c -o $@ $< + +$(ODIR): + @mkdir -p $@ + +clean: + rm -rf *.o *.d $(BIN) $(ODIR); + +OBJS = *.o +-include $(OBJS:.o=.d) diff --git a/source/tools/monitor/mservice/master/src/common.c b/source/tools/monitor/mservice/master/src/common.c new file mode 100644 index 00000000..8f03ed1f --- /dev/null +++ b/source/tools/monitor/mservice/master/src/common.c @@ -0,0 +1,281 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" + + +int +is_digit(const char *str) +{ + if (*str == '-') { + str++; + } + /*dont handle minus value in tsar.data */ + while (*str) { + if (!isdigit(*str++)) { + return 0; + } + } + return 1; +} + + +/* + * convert record to array + */ +int +convert_record_to_array(U_64 *array, int l_array, const char *record) +{ + int i = 0; + char *ptr; + U_64 num; + + if (l_array <= 0 || !record || !strlen(record)) { + return 0; + } + + do { + num = strtoull(record, &ptr, 10); + array[i++] = num; + if (strpbrk(ptr, DATA_SPLIT) == NULL) break; + record = ptr + 1; + } while(i < l_array); + + return i; +} + + +int +merge_one_string(U_64 *array, int l_array, char *string, struct module *mod, int n_item) +{ + int i, len; + U_64 array_2[MAX_COL_NUM] = {0}; + struct mod_info *info = mod->info; + + if ((len = convert_record_to_array(array_2, l_array, string)) <= 0) { + return 0; + } + + for (i=0; i < len; i++) { + switch (info[i].merge_mode) { + case MERGE_SUM: + array[i] += array_2[i]; + break; + case MERGE_AVG: + array[i] = (array[i] * (n_item - 1) + array_2[i]) / n_item; + break; + default: + ; + } + } + return 1; +} + + +char* +strtok_next_item(char *record, int *start) +{ + char *s_token, *e_token, *n_record; + + if (!record || !strlen(record) || strlen(record) <= *start) { + return NULL; + } + + n_record = record + *start; + e_token = strpbrk(n_record, ITEM_SPLIT); + if (!e_token) { + return NULL; + } + s_token = strpbrk(n_record, ITEM_SPSTART); + if (!s_token) { + return NULL; + } + if (e_token < s_token) { + return NULL; + } + + *start = e_token - record + 2; + return s_token + 1; +} + + +int +merge_mult_item_to_array(U_64 *array, struct module *mod) +{ + int pos = 0; + int n_item = 1; + char *item; + + memset(array, 0, sizeof(U_64) * mod->n_col); + while ((item = strtok_next_item(mod->record, &pos)) != NULL) { + if (!merge_one_string(array, mod->n_col, item, mod, n_item)) { + return 0; + } + n_item++; + } + return 1; +} + + +int +get_strtok_num(const char *str, const char *split) +{ + int num = 0; + char *token, n_str[LEN_1M] = {0}; + + if (!str || !strlen(str)) { + return 0; + } + + memcpy(n_str, str, strlen(str)); + /* set print opt line */ + token = strtok(n_str, split); + while (token) { + num++; + token = strtok(NULL, split); + } + + return num; +} + + +/* + * get__mod_hdr; hdr format:HDR_SPLIT"hdr1"HDR_SLIT"hdr2" + */ +void +get_mod_hdr(char hdr[], const struct module *mod) +{ + int i, pos = 0; + struct mod_info *info = mod->info; + + for (i = 0; i < mod->n_col; i++) { + if (mod->spec) { + if (SPEC_BIT == info[i].summary_bit) { + if (strlen(info[i].hdr) > 6) { + info[i].hdr[6] = '\0'; + } + pos += sprintf(hdr + pos, "%s%s", info[i].hdr, PRINT_DATA_SPLIT); + } + + } else { + if (((DATA_SUMMARY == conf.print_mode) && (SUMMARY_BIT == info[i].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (HIDE_BIT != info[i].summary_bit))) + { + if (strlen(info[i].hdr) > 6) { + info[i].hdr[6] = '\0'; + } + pos += sprintf(hdr + pos, "%s%s", info[i].hdr, PRINT_DATA_SPLIT); + } + } + } +} + + +/* + get data from tsar.data + */ +int +get_st_array_from_file(int have_collect) +{ + int i, ret = 0; + char detail[LEN_1M] = {0}; + char pre_time[32] = {0}; + char *s_token; + FILE *fp; + struct module *mod; + static char pre_line[LEN_10M] = {0}; + static char line[LEN_10M] = {0}; + + if (!have_collect) { + collect_record(0); + } + + /* update module parameter */ + conf.print_merge = MERGE_ITEM; + + sprintf(line, "%ld", statis.cur_time); + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (mod->enable && strlen(mod->record)) { + memset(&detail, 0, sizeof(detail)); + /* save collect data to output_file */ + sprintf(detail, "%s%s%s%s", SECTION_SPLIT, mod->opt_line, STRING_SPLIT, mod->record); + strcat(line, detail); + } + } + + if (strlen(line)) { + strcat(line, "\n"); + } + + /* if fopen PRE_RECORD_FILE sucess then store data to pre_record */ + if ((fp = fopen(PRE_RECORD_FILE, "r"))) { + if (!fgets(pre_line, LEN_10M, fp)) { + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + ret = -1; + goto out; + } else { + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + } + } else { + ret = -1; + goto out; + } + + /* set print_interval */ + s_token = strpbrk(pre_line, SECTION_SPLIT); + if (!s_token) { + ret = -1; + goto out; + } + memcpy(pre_time, pre_line, s_token - pre_line); + if (!(conf.print_interval = statis.cur_time - atol(pre_time))) { + ret = -1; + goto out; + } + + /* read pre_line to mod->record and store to pre_array */ + read_line_to_module_record(pre_line); + init_module_fields(); + collect_record_stat(); + + /* read cur_line and stats operation */ + read_line_to_module_record(line); + collect_record_stat(); + ret = 0; + +out: + /* store current record to PRE_RECORD_FILE */ + if ((fp = fopen(PRE_RECORD_FILE, "w"))) { + strcat(line, "\n"); + if (fputs(line, fp) < 0) { + do_debug(LOG_ERR, "fputs error:%s", strerror(errno)); + } + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + chmod(PRE_RECORD_FILE, 0666); + } + + return ret; +} diff --git a/source/tools/monitor/mservice/master/src/config.c b/source/tools/monitor/mservice/master/src/config.c new file mode 100644 index 00000000..570454e7 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/config.c @@ -0,0 +1,436 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" + + +/* add mod to tsar */ +void +parse_mod(const char *mod_name) +{ + int i; + struct module *mod; + char *token; + + token = strtok(NULL, W_SPACE); + if (token && strcasecmp(token, "on") && strcasecmp(token, "enable")) { + return; + } + + /* check if the mod load already */ + for ( i = 0; i < statis.total_mod_num; i++ ) + { + mod = mods[i]; + if (!strcmp(mod->name, mod_name)) { + return; + } + } + if (statis.total_mod_num >= MAX_MOD_NUM) { + do_debug(LOG_ERR, "Max mod number is %d ignore mod %s\n", MAX_MOD_NUM, mod_name); + return; + } + mod = mods[statis.total_mod_num++] = malloc(sizeof(struct module)); + if (mod == NULL) { + do_debug(LOG_ERR, "Failed to alloc memory for mod %s\n", mod_name); + return; + } + memset(mod, '\0', sizeof(struct module)); + + strncpy(mod->name, mod_name, LEN_32); + token = strtok(NULL, W_SPACE); + if (token) { + size_t p = strlen(token); + if (p < LEN_256) { + strncpy(mod->parameter, token, p); + } else { + p = 0; + } + + /*if exist more parameters, add them */ + while((token = strtok(NULL, W_SPACE)) != NULL) { + size_t l = strlen(token); + if (p + l + 1 >= LEN_256) { + break; + } + mod->parameter[p++] = ' '; + strncpy(mod->parameter + p, token, l); + p += l; + } + mod->parameter[p] = '\0'; + } +} + +void +special_mod(const char *spec_mod) +{ + int i = 0, j = 0; + char mod_name[LEN_32]; + struct module *mod = NULL; + + memset(mod_name, 0, LEN_32); + sprintf(mod_name, "mod_%s", spec_mod + 5); + for ( i = 0; i < statis.total_mod_num; i++ ) + { + mod = mods[i]; + if (!strcmp(mod->name, mod_name)) { + /* set special field */ + load_modules(); + char *token = strtok(NULL, W_SPACE); + struct mod_info *info = mod->info; + for (j=0; j < mod->n_col; j++) { + char *p = info[j].hdr; + while (*p == ' ') { + p++; + } + if (strstr(token, p)) { + info[j].summary_bit = SPEC_BIT; + mod->spec = 1; + } + } + } + } +} + +void +parse_int(int *var) +{ + char *token = strtok(NULL, W_SPACE); + + if (token == NULL) { + do_debug(LOG_FATAL, "Bungled line"); + } + *var = strtol(token, NULL, 0); +} + +void +parse_string(char *var) +{ + char *token = strtok(NULL, W_SPACE); + + if (token != NULL && var != NULL) { + strncpy(var, token, strlen(token)); + } +} + +void +parse_add_string(char *var) +{ + char *token = strtok(NULL, W_SPACE); + + if (token != NULL && var != NULL) { + if (var[0] != '\0') { + strcat(var, ","); + } + strncat(var, token, strlen(token)); + } +} + +void +set_debug_level() +{ + char *token = strtok(NULL, W_SPACE); + + if (token) { + if (!strcmp(token, "INFO")) { + conf.debug_level = LOG_INFO; + + } else if (!strcmp(token, "WARN")) { + conf.debug_level = LOG_WARN; + + } else if (!strcmp(token, "DEBUG")) { + conf.debug_level = LOG_DEBUG; + + } else if (!strcmp(token, "ERROR")) { + conf.debug_level = LOG_ERR; + + } else if (!strcmp(token, "FATAL")) { + conf.debug_level = LOG_FATAL; + + } else { + conf.debug_level = LOG_ERR; + } + } +} + +/* parse every config line */ +static int +parse_line(char *buff) +{ + char *token; + int i; + + if ((token = strtok(buff, W_SPACE)) == NULL) { + /* ignore empty lines */ + (void) 0; + + } else if (token[0] == '#') { + /* ignore comment lines */ + (void) 0; + + } else if (strstr(token, "mod_")) { + parse_mod(token); + + } else if (strstr(token, "spec_")) { + special_mod(token); + + } else if (!strcmp(token, "output_interface")) { + parse_string(conf.output_interface); + + } else if (!strcmp(token, "output_file_path")) { + parse_string(conf.output_file_path); + + } else if (!strcmp(token, "output_db_addr")) { + parse_string(conf.output_db_addr); + + } else if (!strcmp(token, "output_db_mod")) { + parse_add_string(conf.output_db_mod); + + } else if (!strcmp(token, "output_tcp_mod")) { + parse_add_string(conf.output_tcp_mod); + } else if (!strcmp(token, "output_tcp_addr")) { + for(i = 0; i < MAX_TCP_ADDR_NUM; i++){ + parse_string(conf.output_tcp_addr[i]); + if(conf.output_tcp_addr[i][0] != 0){ + conf.output_tcp_addr_num++; + } else { + break; + } + } + } else if (!strcmp(token, "output_tcp_merge")) { + parse_string(conf.output_tcp_merge); + + } else if (!strcmp(token, "output_nagios_mod")) { + parse_add_string(conf.output_nagios_mod); + + } else if (!strcmp(token, "output_stdio_mod")) { + parse_add_string(conf.output_stdio_mod); + + } else if (!strcmp(token, "debug_level")) { + set_debug_level(); + + } else if (!strcmp(token, "include")) { + get_include_conf(); + + } else if (!strcmp(token, "server_addr")) { + parse_string(conf.server_addr); + + } else if (!strcmp(token, "server_port")) { + parse_int(&conf.server_port); + + } else if (!strcmp(token, "cycle_time")) { + parse_int(&conf.cycle_time); + + } else if (!strcmp(token, "max_day")) { + parse_int(&conf.print_max_day); + + } else if (!strcmp(token, "send_nsca_cmd")) { + parse_string(conf.send_nsca_cmd); + + } else if (!strcmp(token, "send_nsca_conf")) { + parse_string(conf.send_nsca_conf); + + } else if (!strcmp(token, "threshold")) { + get_threshold(); + + } else if (!strcmp(token, "cron_period")) { + parse_int(&conf.cron_period); + + } else { + return 0; + } + return 1; +} + +static void +process_input_line(char *config_input_line, int len, const char *file_name) +{ + char *token; + + if ((token = strchr(config_input_line, '\n'))) { + *token = '\0'; + } + if ((token = strchr(config_input_line, '\r'))) { + *token = '\0'; + } + if (config_input_line[0] == '#') { + goto final; + } else if (config_input_line[0] == '\0') { + goto final; + } + /* FIXME can't support wrap line */ + if (!parse_line(config_input_line)) { + do_debug(LOG_INFO, "parse_config_file: unknown keyword in '%s' at file %s\n", + config_input_line, file_name); + } + +final: + memset(config_input_line, '\0', len); +} + +void +parse_config_file(const char *file_name) +{ + FILE *fp; + char config_input_line[LEN_1024] = {0}; + + if (!(fp = fopen(file_name, "r"))) { + do_debug(LOG_FATAL, "Unable to open configuration file: %s", file_name); + } + + memset(&conf, '\0', sizeof(conf)); + memset(&statis, '\0', sizeof(statis)); + conf.debug_level = LOG_ERR; + conf.print_detail = FALSE; + conf.print_max_day = 365; + sprintf(conf.output_interface, "file"); + conf.cron_period = 60; + while (fgets(config_input_line, LEN_1024, fp)) { + process_input_line(config_input_line, LEN_1024, file_name); + } + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } +} + +/* deal with the include statment */ +void +get_include_conf() +{ + char *token = strtok(NULL, W_SPACE); + char *p; + FILE *stream, *fp; + char cmd[LEN_1024] = {0}; + char buf[LEN_1024] = {0}; + char config_input_line[LEN_1024] = {0}; + + if (token) { + memset(cmd, '\0', LEN_1024); + sprintf(cmd, "ls %s 2>/dev/null", token); + if (strchr(cmd, ';') != NULL || strchr(cmd, '|') != NULL || strchr(cmd, '&') != NULL) { + do_debug(LOG_ERR, "include formart Error:%s\n", cmd); + } + stream = popen(cmd, "r"); + if (stream == NULL) { + do_debug(LOG_ERR, "popen failed. Error:%s\n", strerror(errno)); + return; + } + memset(buf, '\0', LEN_1024); + while (fgets(buf, LEN_1024, stream)) { + do_debug(LOG_INFO, "parse file %s", buf); + p = buf; + while (p) { + if (*p == '\r' || *p == '\n') { + *p = '\0'; + break; + } + p++; + } + if (!(fp = fopen(buf, "r"))) { + do_debug(LOG_ERR, "Unable to open configuration file: %s Error msg: %s\n", buf, strerror(errno)); + continue; + } + memset(config_input_line, '\0', LEN_1024); + while (fgets(config_input_line, LEN_1024, fp)) { + process_input_line(config_input_line, LEN_1024, buf); + } + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + } + if (pclose(stream) == -1) + do_debug(LOG_WARN, "pclose error\n"); + } +} + +/* get nagios alert threshold value */ +void +get_threshold() +{ + /* set nagios value */ + char *token = strtok(NULL, W_SPACE); + char tmp[4][LEN_32]; + + if (conf.mod_num >= MAX_MOD_NUM) { + do_debug(LOG_FATAL, "Too many mod threshold\n"); + } + sscanf(token, "%[^;];%[.N0-9];%[.N0-9];%[.N0-9];%[.N0-9];", + conf.check_name[conf.mod_num], tmp[0], tmp[1], tmp[2], tmp[3]); + + if (!strcmp(tmp[0], "N")) { + conf.wmin[conf.mod_num] = 0; + + } else { + conf.wmin[conf.mod_num] = atof(tmp[0]); + } + if (!strcmp(tmp[1], "N")) { + conf.wmax[conf.mod_num] = 0; + + } else { + conf.wmax[conf.mod_num] = atof(tmp[1]); + } + if (!strcmp(tmp[2], "N")) { + conf.cmin[conf.mod_num] = 0; + + } else { + conf.cmin[conf.mod_num]=atof(tmp[2]); + } + if (!strcmp(tmp[3], "N")) { + conf.cmax[conf.mod_num] = 0; + + } else { + conf.cmax[conf.mod_num] = atof(tmp[3]); + } + conf.mod_num++; +} + +void +set_special_field(const char *s) +{ + int i = 0, j = 0; + struct module *mod = NULL; + + for (i = 0; i < statis.total_mod_num; i++) + { + mod = mods[i]; + struct mod_info *info = mod->info; + for (j=0; j < mod->n_col; j++) { + char *p = info[j].hdr; + while (*p == ' ') { + p++; + } + if (strstr(s, p)) { + info[j].summary_bit = SPEC_BIT; + mod->spec = 1; + } + } + } +} + +void +set_special_item(const char *s) +{ + int i = 0; + struct module *mod = NULL; + + for (i = 0; i < statis.total_mod_num; i++) + { + mod = mods[i]; + strncpy(mod->print_item, s, LEN_256); + } +} diff --git a/source/tools/monitor/mservice/master/src/debug.c b/source/tools/monitor/mservice/master/src/debug.c new file mode 100644 index 00000000..d7d8be71 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/debug.c @@ -0,0 +1,51 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" + + +void +_do_debug(log_level_t level, const char *file, int line, const char *fmt, ...) +{ + char *timestr; + time_t timep; + va_list argp; + struct tm *local; + + /* FIXME */ + if (level >= conf.debug_level) { + + time(&timep); + local = localtime(&timep); + timestr = asctime(local); + + fprintf(stderr, "[%.*s] %s:%d ", + (int)(strlen(timestr) - 1), timestr, file, line); + + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + fflush(stderr); + va_end(argp); + } + + if (level == LOG_FATAL) { + fprintf(stderr, "\n"); + exit(1); + } +} diff --git a/source/tools/monitor/mservice/master/src/framework.c b/source/tools/monitor/mservice/master/src/framework.c new file mode 100644 index 00000000..a49a3b33 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/framework.c @@ -0,0 +1,531 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" + + + +void +register_mod_fields(struct module *mod, const char *opt, const char *usage, + struct mod_info *info, int n_col, void *data_collect, void *set_st_record) +{ + sprintf(mod->opt_line, "%s", opt); + sprintf(mod->usage, "%s", usage); + mod->info = info; + mod->n_col = n_col; + mod->data_collect = data_collect; + mod->set_st_record = set_st_record; +} + + +void +set_mod_record(struct module *mod, const char *record) +{ + if (record) { + sprintf(mod->record, "%s", record); + } +} + + +/* + * load module from dir + */ +void +load_modules() +{ + int i; + char buff[LEN_128] = {0}; + char mod_path[LEN_128] = {0}; + struct module *mod = NULL; + int (*mod_register) (struct module *); + + /* get the full path of modules */ + //sprintf(buff, DEFAULT_MODULE_PATH); + sprintf(buff, "%s/tools/monitor/modules",getenv("SYSAK_WORK_PATH")); + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + + if (strlen(mod->name) == 0) { + continue; + } + + if (!mod->lib) { + snprintf(mod_path, LEN_128, "%s/%s.so", buff, mod->name); + if (!(mod->lib = dlopen(mod_path, RTLD_NOW|RTLD_GLOBAL))) { + do_debug(LOG_ERR, "load_modules: dlopen module %s err %s\n", mod->name, dlerror()); + + } else { + mod_register = dlsym(mod->lib, "mod_register"); + if (dlerror()) { + do_debug(LOG_ERR, "load_modules: dlsym module %s err %s\n", mod->name, dlerror()); + break; + + } else { + mod_register(mod); + mod->enable = 1; + mod->spec = 0; + do_debug(LOG_INFO, "load_modules: load new module '%s' to mods\n", mod_path); + } + } + } + } +} + + +/* + * reload modules by mods, if not find in mods, then set module disable + * return 1 if mod load ok + * return 0 else + */ +int +reload_modules(const char *s_mod) +{ + int i; + int reload = 0; + char buf[LEN_512], name[LEN_64], *token, *param; + + if (!s_mod || !strlen(s_mod)) { + return reload; + } + + strncpy(buf, s_mod, strlen(s_mod) + 1); + + for (i = 0; i < statis.total_mod_num; i++) + mods[i]->enable = 0; + + token = strtok(buf, DATA_SPLIT); + while (token != NULL) { + strncpy(name, token, strlen(token) + 1); + + /* extract the parameter specified in the command line */ + param = strchr(name, PARAM_SPLIT); + if (param != NULL) { + *param = '\0'; + ++param; + } + + for (i = 0; i < statis.total_mod_num; i++) { + if (strcmp(name, mods[i]->name) == 0 + || strcmp(name, mods[i]->opt_line) == 0) { + reload = 1; + mods[i]->enable = 1; + + if (param != NULL) { + strncpy(mods[i]->parameter, param, strlen(param) + 1); + } + + break; + } + } + + token = strtok(NULL, DATA_SPLIT); + } + + return reload; +} + +#ifdef OLDTSAR +/* + * reload check modules by mods, if not find in mods, then set module disable + */ +void +reload_check_modules() +{ + int i; + struct module *mod; + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!strcmp(mod->name, "mod_apache") + || !strcmp(mod->name, "mod_cpu") + || !strcmp(mod->name, "mod_mem") + || !strcmp(mod->name, "mod_load") + || !strcmp(mod->name, "mod_partition") + || !strcmp(mod->name, "mod_io") + || !strcmp(mod->name, "mod_tcp") + || !strcmp(mod->name, "mod_traffic") + || !strcmp(mod->name, "mod_nginx") + || !strcmp(mod->name, "mod_swap")) + { + mod->enable = 1; + + } else { + mod->enable = 0; + } + } +} +/*end*/ +#endif + +/* + * 1. alloc or realloc store array + * 2. set mod->n_item + */ +void +init_module_fields() +{ + int i; + struct module *mod = NULL; + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + + if (MERGE_ITEM == conf.print_merge) { + mod->n_item = 1; + + } else { + /* get mod->n_item first, and mod->n_item will be reseted in reading next line */ + mod->n_item = get_strtok_num(mod->record, ITEM_SPLIT); + } + + if (mod->n_item) { + mod->pre_array = (U_64 *)calloc(mod->n_item * mod->n_col, sizeof(U_64)); + mod->cur_array = (U_64 *)calloc(mod->n_item * mod->n_col, sizeof(U_64)); + mod->st_array = (double *)calloc(mod->n_item * mod->n_col, sizeof(double)); + if (conf.print_tail) { + mod->max_array = (double *)calloc(mod->n_item * mod->n_col, sizeof(double)); + mod->mean_array = (double *)calloc(mod->n_item * mod->n_col, sizeof(double)); + mod->min_array = (double *)calloc(mod->n_item * mod->n_col, sizeof(double)); + } + } + } +} + + +/* + * 1. realloc store array when mod->n_item is modify + */ +void +realloc_module_array(struct module *mod, int n_n_item) +{ + if (n_n_item > mod->n_item) { + if (mod->pre_array) { + mod->pre_array = (U_64 *)realloc(mod->pre_array, n_n_item * mod->n_col * sizeof(U_64)); + mod->cur_array = (U_64 *)realloc(mod->cur_array, n_n_item * mod->n_col * sizeof(U_64)); + mod->st_array = (double *)realloc(mod->st_array, n_n_item * mod->n_col * sizeof(double)); + if (conf.print_tail) { + mod->max_array = (double *)realloc(mod->max_array, n_n_item * mod->n_col *sizeof(double)); + mod->mean_array =(double *)realloc(mod->mean_array, n_n_item * mod->n_col *sizeof(double)); + mod->min_array = (double *)realloc(mod->min_array, n_n_item * mod->n_col *sizeof(double)); + } + + } else { + mod->pre_array = (U_64 *)calloc(n_n_item * mod->n_col, sizeof(U_64)); + mod->cur_array = (U_64 *)calloc(n_n_item * mod->n_col, sizeof(U_64)); + mod->st_array = (double *)calloc(n_n_item * mod->n_col, sizeof(double)); + if (conf.print_tail) { + mod->max_array = (double *)calloc(n_n_item * mod->n_col, sizeof(double)); + mod->mean_array =(double *)calloc(n_n_item * mod->n_col, sizeof(double)); + mod->min_array = (double *)calloc(n_n_item * mod->n_col, sizeof(double)); + } + } + } +} + +/* + * set st result in st_array + */ +void +set_st_record(struct module *mod) +{ + int i, j, k = 0; + struct mod_info *info = mod->info; + + mod->st_flag = 1; + + for (i = 0; i < mod->n_item; i++) { + /* custom statis compute */ + if (mod->set_st_record) { + mod->set_st_record(mod, &mod->st_array[i * mod->n_col], + &mod->pre_array[i * mod->n_col], + &mod->cur_array[i * mod->n_col], + conf.print_interval); + } + + for (j=0; j < mod->n_col; j++) { + if (!mod->set_st_record) { + switch (info[j].stats_opt) { + case STATS_SUB: + if (mod->cur_array[k] < mod->pre_array[k]) { + mod->pre_array[k] = mod->cur_array[k]; + mod->st_flag = 0; + + } else { + mod->st_array[k] = mod->cur_array[k] - mod->pre_array[k]; + } + break; + case STATS_SUB_INTER: + if (mod->cur_array[k] < mod->pre_array[k]) { + mod->pre_array[k] = mod->cur_array[k]; + mod->st_flag = 0; + + } else { + mod->st_array[k] = (mod->cur_array[k] -mod->pre_array[k]) / conf.print_interval; + } + break; + default: + mod->st_array[k] = mod->cur_array[k]; + } + mod->st_array[k] *= 1.0; + } + + if (conf.print_tail) { + if (0 == mod->n_record) { + mod->max_array[k] = mod->mean_array[k] = mod->min_array[k] = mod->st_array[k] * 1.0; + + } else { + if (mod->st_array[k] - mod->max_array[k] > 0.1) { + mod->max_array[k] = mod->st_array[k]; + } + if (mod->min_array[k] - mod->st_array[k] > 0.1 && mod->st_array[k] >= 0) { + mod->min_array[k] = mod->st_array[k]; + } + if (mod->st_array[k] >= 0) { + mod->mean_array[k] = ((mod->n_record - 1) *mod->mean_array[k] + mod->st_array[k]) / mod->n_record; + } + } + } + k++; + } + } + + mod->n_record++; +} + + +/* + * if diable = 1, then will disable module when record is null + */ +void +collect_record() +{ + int i; + struct module *mod = NULL; + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + + memset(mod->record, 0, sizeof(mod->record)); + if (mod->data_collect) { + mod->data_collect(mod, mod->parameter); + } + } +} + + +/* + * compute mod->st_array and swap cur_info to pre_info + * return: 1 -> ok + * 0 -> some mod->n_item have modify will reprint header + */ +int +collect_record_stat() +{ + int i, n_item, ret, no_p_hdr = 1; + U_64 *tmp, array[MAX_COL_NUM] = {0}; + struct module *mod = NULL; + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + + memset(array, 0, sizeof(array)); + mod->st_flag = 0; + ret = 0; + + if ((n_item = get_strtok_num(mod->record, ITEM_SPLIT))) { + /* not merge mode, and last n_item != cur n_item, then reset mod->n_item and set reprint header flag */ + if (MERGE_ITEM != conf.print_merge && n_item && n_item != mod->n_item) { + no_p_hdr = 0; + /* reset struct module fields */ + realloc_module_array(mod, n_item); + } + + mod->n_item = n_item; + /* multiple item because of having ITEM_SPLIT */ + if (strpbrk(mod->record, ITEM_SPLIT)) { + /* merge items */ + if (MERGE_ITEM == conf.print_merge) { + mod->n_item = 1; + ret = merge_mult_item_to_array(mod->cur_array, mod); + + } else { + char *item; + int num = 0; + int pos = 0; + + while ((item = strtok_next_item(mod->record, &pos)) != NULL) { + if ((ret=convert_record_to_array(&mod->cur_array[num * mod->n_col], mod->n_col, item)) <= 0) { + break; + } + num++; + } + } + + } else { /* one item */ + ret = convert_record_to_array(mod->cur_array, mod->n_col, mod->record); + } + + /* get st record */ + if (no_p_hdr && mod->pre_flag && ret) { + set_st_record(mod); + } + + if (!ret) { + mod->pre_flag = 0; + + } else { + mod->pre_flag = 1; + } + + } else { + mod->pre_flag = 0; + } + /* swap cur_array to pre_array */ + tmp = mod->pre_array; + mod->pre_array = mod->cur_array; + mod->cur_array = tmp; + } + + return no_p_hdr; +} + + +/* + * free module info + */ +void +free_modules() +{ + int i; + struct module *mod; + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (mod->lib) { + dlclose(mod->lib); + } + + if (mod->cur_array) { + free(mod->cur_array); + mod->cur_array = NULL; + free(mod->pre_array); + mod->pre_array = NULL; + free(mod->st_array); + mod->st_array = NULL; + } + + if (mod->max_array) { + free(mod->max_array); + free(mod->mean_array); + free(mod->min_array); + mod->max_array = NULL; + mod->mean_array = NULL; + mod->min_array = NULL; + } + free(mod); + } +} + + +/* + * read line from file to mod->record and return timestamp + */ +time_t +read_line_to_module_record(char *line) +{ + int i; + struct module *mod; + char *s_token, *e_token; + char mod_opt[LEN_64]; + + line[strlen(line) - 1] = '\0'; + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (mod->enable) { + sprintf(mod_opt, "%s%s%s", SECTION_SPLIT, mod->opt_line, STRING_SPLIT); + memset(mod->record, 0, sizeof(mod->record)); + + s_token = strstr(line, mod_opt); + if (!s_token) { + continue; + } + + s_token += strlen(mod->opt_line) + 2; + e_token = strpbrk(s_token, SECTION_SPLIT); + + if (e_token) { + memcpy(mod->record, s_token, e_token - s_token); + + } else { + memcpy(mod->record, s_token, strlen(line) - (s_token - line)); + } + } + } + return atol(line); +} + + +/* + * if col num is zero then disable module + */ +void +disable_col_zero() +{ + int i, j; + struct module *mod = NULL; + int p_col; + struct mod_info *info; + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + + if (!mod->n_col) { + mod->enable = 0; + + } else { + p_col = 0; + info = mod->info; + + for (j = 0; j < mod->n_col; j++) { + if (((DATA_SUMMARY == conf.print_mode) && (SUMMARY_BIT == info[j].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (HIDE_BIT != info[j].summary_bit))) { + p_col++; + break; + } + } + + if (!p_col) { + mod->enable = 0; + } + } + } +} + diff --git a/source/tools/monitor/mservice/master/src/httpserver.c b/source/tools/monitor/mservice/master/src/httpserver.c new file mode 100644 index 00000000..c288d2eb --- /dev/null +++ b/source/tools/monitor/mservice/master/src/httpserver.c @@ -0,0 +1,115 @@ +#include "tsar.h" + +#define SERVER_PORT 9200 +#define ERROR_MSG "HTTP/1.1 404 Not Found\r\n" + +enum { + REQUEST_METRIC, + REQUEST_MAX +}; + +static int get_request(const char *buf) +{ + char req_str[32]; + + sscanf(buf, "GET /%s HTTP", req_str); + if (strcmp(req_str, "metric") == 0) + return REQUEST_METRIC; + + return REQUEST_MAX; +} + + +void output_http(int sk) +{ + int i, n = 0; + char detail[LEN_1M] = {0}; + struct module *mod; + static char line[LEN_10M] = {0}; + char http_header[64]; + + line[0] = 0; + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (mod->enable && strlen(mod->record)) { + n = snprintf(detail, LEN_1M, "%s %s\n", mod->opt_line, mod->record); + if (n >= LEN_1M - 1) { + do_debug(LOG_FATAL, "mod %s lenth is overflow %d\n", mod->name, n); + } + /* one for \n one for \0 */ + if (strlen(line) + strlen(detail) >= LEN_10M - 2) { + do_debug(LOG_FATAL, "tsar.data line lenth is overflow line %d detail %d\n", strlen(line), strlen(detail)); + } + strcat(line, detail); + } + } + + strcat(line, "\n"); + + sprintf(http_header, "HTTP/1.1 200 OK\r\nContent-Length: %d \r\n\r\n", + (int)strlen(line)); + write(sk, http_header, strlen(http_header)); + write(sk, line, strlen(line)); +} + + +static void handle_metric(int sk) +{ + collect_record(); + output_http(sk); +} + +int http_server(void) +{ + struct sockaddr_in srvaddr; + int sk, res, sockopt = 1; + + sk = socket(AF_INET, SOCK_STREAM, 0); + if(sk < 0) { + printf("create socket error!\n"); + return -1; + } + + srvaddr.sin_family = AF_INET; + srvaddr.sin_port = htons(SERVER_PORT); + srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)); + + res = bind(sk, (struct sockaddr *)&srvaddr, sizeof(srvaddr)); + if(res < 0) { + printf("bind error!\n"); + close(sk); + return -1; + } + + listen(sk, 10); + + while(1) { + struct sockaddr_in cli_addr; + socklen_t len = sizeof(cli_addr); + int csk; + + csk = accept(sk, (struct sockaddr *)&cli_addr, &len); + if(csk < 0) { + printf("accept error!\n"); + close(sk); + return -1; + } + + char buff[1024] = {0}; + int size = read(csk, buff, sizeof(buff)); + + if (size > 0 && get_request(buff) == REQUEST_METRIC) + handle_metric(csk); + else + write(csk, ERROR_MSG, strlen(ERROR_MSG)); + + close(csk); + } + + close(sk); + + return 0; +} diff --git a/source/tools/monitor/mservice/master/src/output_db.c b/source/tools/monitor/mservice/master/src/output_db.c new file mode 100644 index 00000000..acdc6f84 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/output_db.c @@ -0,0 +1,216 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include +#include "tsar.h" + + +/* + * send sql to remote db + */ +void +send_sql_txt(int fd, int have_collect) +{ + int i = 0, j, len; + char s_time[LEN_64] = {0}; + char host_name[LEN_64] = {0}; + struct module *mod; + static char sqls[LEN_10M] = {0}; + + /* get hostname */ + if (0 != gethostname(host_name, sizeof(host_name))) { + do_debug(LOG_FATAL, "send_sql_txt: gethostname err, errno=%d", errno); + } + while (host_name[i]) { + if (!isprint(host_name[i++])) { + host_name[i-1] = '\0'; + break; + } + } + + /* get st_array */ + if (get_st_array_from_file(have_collect)) { + return; + } + + /* only output from output_db_mod */ + reload_modules(conf.output_db_mod); + + sprintf(s_time, "%ld", time(NULL)); + + /* print summary data */ + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + + } else { + if (!mod->st_flag) { + char sql_hdr[LEN_256] = {0}; + /* set sql header */ + memset(sql_hdr, '\0', sizeof(sql_hdr)); + sprintf(sql_hdr, "insert into `%s` (host_name, time) VALUES ('%s', '%s');", + mod->opt_line + 2, host_name, s_time); + strcat(sqls, sql_hdr); + + } else { + char str[LEN_32] = {0}; + char sql_hdr[LEN_256] = {0}; + struct mod_info *info = mod->info; + + /* set sql header */ + memset(sql_hdr, '\0', sizeof(sql_hdr)); + sprintf(sql_hdr, "insert into `%s` (host_name, time", mod->opt_line + 2); + + /* get value */ + for (j = 0; j < mod->n_col; j++) { + strcat(sql_hdr, ", `"); + char *p = info[j].hdr; + while (*p == ' ') { + p++; + } + strncat(sql_hdr, p, LEN_128); + strcat(sql_hdr, "`"); + } + strcat(sql_hdr, ") VALUES ('"); + strcat(sql_hdr, host_name); + strcat(sql_hdr, "', '"); + strcat(sql_hdr, s_time); + strcat(sql_hdr, "'"); + strcat(sqls, sql_hdr); + + /* get value */ + for (j = 0; j < mod->n_col; j++) { + memset(str, 0, sizeof(str)); + sprintf(str, ", '%.1f'", mod->st_array[j]); + strcat(sqls, str); + } + strcat(sqls, ");"); + } + } + } + len = strlen(sqls); + if (write(fd, sqls, len) != len) { + do_debug(LOG_ERR, "output_db write error:%s", strerror(errno)); + } +} + +struct sockaddr_in * +str2sa(char *str) +{ + int port; + char *c; + static struct sockaddr_in sa; + + memset(&sa, 0, sizeof(sa)); + str = strdup(str); + if (str == NULL) { + goto out_nofree; + } + + if ((c = strrchr(str, ':')) != NULL) { + *c++ = '\0'; + port = atol(c); + + } else { + port = 0; + } + + if (*str == '*' || *str == '\0') { /* INADDR_ANY */ + sa.sin_addr.s_addr = INADDR_ANY; + + } else { + if (!inet_pton(AF_INET, str, &sa.sin_addr)) { + struct hostent *he; + + if ((he = gethostbyname(str)) == NULL) { + do_debug(LOG_FATAL, "str2sa: Invalid server name, '%s'", str); + + } else { + sa.sin_addr = *(struct in_addr *) *(he->h_addr_list); + } + } + } + sa.sin_port = htons(port); + sa.sin_family = AF_INET; + + free(str); +out_nofree: + return &sa; +} + +void +output_db(int have_collect) +{ + int fd, flags, res; + fd_set fdr, fdw; + struct timeval timeout; + struct sockaddr_in db_addr; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + do_debug(LOG_FATAL, "can't get socket"); + } + + /* set socket fd noblock */ + if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { + close(fd); + return; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(fd); + return; + } + + /* get db server address */ + db_addr = *str2sa(conf.output_db_addr); + + if (connect(fd, (struct sockaddr*)&db_addr, sizeof(db_addr)) != 0) { + if (errno != EINPROGRESS) { // EINPROGRESS + close(fd); + return; + + } else { + goto select; + } + + } else { + goto send; + } + +select: + FD_ZERO(&fdr); + FD_ZERO(&fdw); + FD_SET(fd, &fdr); + FD_SET(fd, &fdw); + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + res = select(fd + 1, &fdr, &fdw, NULL, &timeout); + if (res <= 0) { + close(fd); + return; + } + +send: + send_sql_txt(fd, have_collect); + close(fd); +} diff --git a/source/tools/monitor/mservice/master/src/output_file.c b/source/tools/monitor/mservice/master/src/output_file.c new file mode 100644 index 00000000..ebf80ef9 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/output_file.c @@ -0,0 +1,68 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" + + +void +output_file() +{ + int i, ret = 0, n = 0; + FILE *fp = NULL; + char detail[LEN_1M] = {0}; + char s_time[LEN_256] = {0}; + struct module *mod; + static char line[LEN_10M] = {0}; + + if (!(fp = fopen(conf.output_file_path, "a"))) { + do_debug(LOG_FATAL, "output_file: can't open or create data file = %s err=%d\n", conf.output_file_path, errno); + } + setbuf(fp, NULL); + + line[0] = 0; + sprintf(s_time, "%ld", statis.cur_time); + strcat(line, s_time); + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (mod->enable && strlen(mod->record)) { + /* save collect data to output_file */ + n = snprintf(detail, LEN_1M, "%s%s%s%s", SECTION_SPLIT, mod->opt_line, STRING_SPLIT, mod->record); + if (n >= LEN_1M - 1) { + do_debug(LOG_FATAL, "mod %s lenth is overflow %d\n", mod->name, n); + } + /* one for \n one for \0 */ + if (strlen(line) + strlen(detail) >= LEN_10M - 2) { + do_debug(LOG_FATAL, "tsar.data line lenth is overflow line %d detail %d\n", strlen(line), strlen(detail)); + } + strcat(line, detail); + ret = 1; + } + } + strcat(line, "\n"); + + if (ret) { + if (fputs(line, fp) < 0) { + do_debug(LOG_ERR, "write line error\n"); + } + } + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } +} diff --git a/source/tools/monitor/mservice/master/src/output_nagios.c b/source/tools/monitor/mservice/master/src/output_nagios.c new file mode 100644 index 00000000..49eaf60c --- /dev/null +++ b/source/tools/monitor/mservice/master/src/output_nagios.c @@ -0,0 +1,166 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include +#include "tsar.h" + + +#define PRE_RECORD_FILE "/tmp/.tsar.tmp" + + +void +output_nagios() +{ + int i = 0, j = 0, k = 0, l = 0, result = 0, now_time; + char s_time[LEN_64] = {0}; + char host_name[LEN_64] = {0}; + struct module *mod; + static char output[LEN_10M] = {0}; + static char output_err[LEN_10M] = {0}; + + /* if cycle time ok*/ + now_time = statis.cur_time - statis.cur_time%60; + if (conf.cycle_time == 0 || now_time%conf.cycle_time != 0) { + return; + } + + /* get hostname */ + if (0 != gethostname(host_name, sizeof(host_name))) { + do_debug(LOG_FATAL, "send to nagios: gethostname err, errno=%d \n", errno); + } + while (host_name[i]) { + if (!isprint(host_name[i++])) { + host_name[i-1] = '\0'; + break; + } + } + + /* update module parameter */ + conf.print_merge = MERGE_NOT; + + /* get st_array */ + if (get_st_array_from_file(0)) { + return; + } + + /* only output from output_nagios_mod */ + reload_modules(conf.output_nagios_mod); + + sprintf(s_time, "%ld", time(NULL)); + + /* print summary data */ + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + + } else { + if (!mod->st_flag) { + printf("name %s\n", mod->name); + printf("do nothing\n"); + + } else { + char opt[LEN_32]; + char check[LEN_64]; + char *n_record = strdup(mod->record); + char *token = strtok(n_record, ITEM_SPLIT); + char *s_token; + double *st_array; + struct mod_info *info = mod->info; + + j = 0; + /* get mod_name.(item_name).col_name value */ + while (token) { + memset(check, 0, sizeof(check)); + strncat(check, mod->name + 4, LEN_32); + strcat(check, "."); + s_token = strpbrk(token, ITEM_SPSTART); + /* multi item */ + if (s_token){ + memset(opt, 0, sizeof(opt)); + strncat(opt, token, s_token - token); + strcat(check, opt); + strcat(check, "."); + } + /* get value */ + st_array = &mod->st_array[j * mod->n_col]; + token = strtok(NULL, ITEM_SPLIT); + j++; + for (k = 0; k < mod->n_col; k++) { + char *p; + char check_item[LEN_64]; + + memset(check_item, 0, LEN_64); + memcpy(check_item, check, LEN_64); + p = info[k].hdr; + while (*p == ' ') { + p++; + } + strncat(check_item, p, LEN_64); + for (l = 0; l < conf.mod_num; l++){ + /* cmp tsar item with naigos item*/ + if (!strcmp(conf.check_name[l], check_item)) { + char value[LEN_32]; + memset(value, 0, sizeof(value)); + sprintf(value, "%0.2f", st_array[k]); + strncat(output, check_item, LEN_64); + strcat(output, "="); + strncat(output, value, LEN_32); + strcat(output, " "); + if (conf.cmin[l] != 0 && st_array[k] >= conf.cmin[l]) { + if (conf.cmax[l] == 0 || (conf.cmax[l] != 0 && st_array[k] <= conf.cmax[l])) { + result = 2; + strncat(output_err, check_item, LEN_64); + strcat(output_err, "="); + strncat(output_err, value, LEN_32); + strcat(output_err, " "); + continue; + } + } + if (conf.wmin[l] != 0 && st_array[k] >= conf.wmin[l]) { + if (conf.wmax[l] == 0 || (conf.wmax[l] != 0 && st_array[k] <= conf.wmax[l]) ) { + if (result != 2) { + result = 1; + } + strncat(output_err, check_item, LEN_64); + strcat(output_err, "="); + strncat(output_err, value, LEN_32); + strcat(output_err, " "); + } + } + } + } + } + } + free(n_record); + } + } + } + if (!strcmp(output_err, "")) { + strcat(output_err, "OK"); + } + /* send to nagios server*/ + char nagios_cmd[LEN_1024]; + sprintf(nagios_cmd, "echo \"%s;tsar;%d;%s|%s\"|%s -H %s -p %d -to 10 -d \";\" -c %s", host_name, result, output_err, output, conf.send_nsca_cmd, conf.server_addr, conf.server_port, conf.send_nsca_conf); + do_debug(LOG_DEBUG, "send to naigos:%s\n", nagios_cmd); + if (system(nagios_cmd) != 0) { + do_debug(LOG_WARN, "nsca run error:%s\n", nagios_cmd); + } + printf("%s\n", nagios_cmd); +} diff --git a/source/tools/monitor/mservice/master/src/output_print.c b/source/tools/monitor/mservice/master/src/output_print.c new file mode 100644 index 00000000..08e38145 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/output_print.c @@ -0,0 +1,1225 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" +#include + + +/* + * adjust print opt line + */ +void +adjust_print_opt_line(char *n_opt_line, const char *opt_line, int hdr_len) +{ + int pad_len; + char pad[LEN_128] = {0}; + + if (hdr_len > strlen(opt_line)) { + pad_len = (hdr_len - strlen(opt_line)) / 2; + + memset(pad, '-', pad_len); + strcat(n_opt_line, pad); + strcat(n_opt_line, opt_line); + memset(pad, '-', hdr_len - pad_len - strlen(opt_line)); + strcat(n_opt_line, pad); + + } else { + strncat(n_opt_line, opt_line, hdr_len); + } +} + + +/* + * print header and update mod->n_item + */ +void +print_header() +{ + int i; + char header[LEN_1M] = {0}; + char opt_line[LEN_1M] = {0}; + char hdr_line[LEN_1M] = {0}; + char opt[LEN_256] = {0}; + char n_opt[LEN_256] = {0}; + char mod_hdr[LEN_256] = {0}; + char *token, *s_token, *n_record; + struct module *mod = NULL; + + if (conf.running_mode == RUN_PRINT_LIVE) { + sprintf(opt_line, "Time %s", PRINT_SEC_SPLIT); + sprintf(hdr_line, "Time %s", PRINT_SEC_SPLIT); + + } else { + sprintf(opt_line, "Time %s", PRINT_SEC_SPLIT); + sprintf(hdr_line, "Time %s", PRINT_SEC_SPLIT); + } + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + + memset(n_opt, 0, sizeof(n_opt)); + memset(mod_hdr, 0, sizeof(mod_hdr)); + get_mod_hdr(mod_hdr, mod); + + if (strpbrk(mod->record, ITEM_SPLIT) && MERGE_NOT == conf.print_merge) { + n_record = strdup(mod->record); + /* set print opt line */ + token = strtok(n_record, ITEM_SPLIT); + int count = 0; + mod->p_item = -1; + while (token) { + s_token = strpbrk(token, ITEM_SPSTART); + if (s_token) { + memset(opt, 0, sizeof(opt)); + memset(n_opt, 0, sizeof(n_opt)); + strncat(opt, token, s_token - token); + if (*mod->print_item != 0 && fnmatch(mod->print_item, opt, 0)) { + token = strtok(NULL, ITEM_SPLIT); + count++; + continue; + } + mod->p_item = count++; + adjust_print_opt_line(n_opt, opt, strlen(mod_hdr)); + strcat(opt_line, n_opt); + strcat(opt_line, PRINT_SEC_SPLIT); + strcat(hdr_line, mod_hdr); + strcat(hdr_line, PRINT_SEC_SPLIT); + } + token = strtok(NULL, ITEM_SPLIT); + } + free(n_record); + n_record = NULL; + + } else { + memset(opt, 0, sizeof(opt)); + /* set print opt line */ + adjust_print_opt_line(opt, mod->opt_line, strlen(mod_hdr)); + /* set print hdr line */ + strcat(hdr_line, mod_hdr); + strcat(opt_line, opt); + } + strcat(hdr_line, PRINT_SEC_SPLIT); + strcat(opt_line, PRINT_SEC_SPLIT); + } + + sprintf(header, "%s\n%s\n", opt_line, hdr_line); + printf("%s", header); +} + + +void +printf_result(double result) +{ + if (conf.print_detail) { + printf("%6.2f", result); + printf("%s", PRINT_DATA_SPLIT); + return; + } + + if ((1000 - result) > 0.1) { + printf("%6.2f", result); + } else if ( (1000 - result / 1024) > 0.1) { + printf("%5.1f%s", result / 1024, "K"); + } else if ((1000 - result / 1024 / 1024) > 0.1) { + printf("%5.1f%s", result / 1024 / 1024, "M"); + } else if ((1000 - result / 1024 / 1024 / 1024) > 0.1) { + printf("%5.1f%s", result / 1024 / 1024 / 1024, "G"); + } else if ((1000 - result / 1024 / 1024 / 1024 / 1024) > 0.1) { + printf("%5.1f%s", result / 1024 / 1024 / 1024 / 1024, "T"); + } + printf("%s", PRINT_DATA_SPLIT); +} + + +void +print_array_stat(const struct module *mod, const double *st_array) +{ + int i; + struct mod_info *info = mod->info; + + for (i = 0; i < mod->n_col; i++) { + if (mod->spec) { + /* print null */ + if (!st_array || !mod->st_flag || st_array[i] < 0) { + /* print record */ + if (((DATA_SUMMARY == conf.print_mode) && (SPEC_BIT == info[i].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (SPEC_BIT == info[i].summary_bit))) + { + printf("------%s", PRINT_DATA_SPLIT); + } + + } else { + /* print record */ + if (((DATA_SUMMARY == conf.print_mode) && (SPEC_BIT == info[i].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (SPEC_BIT == info[i].summary_bit))) + { + printf_result(st_array[i]); + } + } + + } else { + /* print null */ + if (!st_array || !mod->st_flag || st_array[i] < 0) { + /* print record */ + if (((DATA_SUMMARY == conf.print_mode) && (SUMMARY_BIT == info[i].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (HIDE_BIT != info[i].summary_bit))) + { + printf("------%s", PRINT_DATA_SPLIT); + } + + } else { + /* print record */ + if (((DATA_SUMMARY == conf.print_mode) && (SUMMARY_BIT == info[i].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (HIDE_BIT != info[i].summary_bit))) + { + printf_result(st_array[i]); + } + } + } + } +} + + +/* print current time */ +void +print_current_time() +{ + char cur_time[LEN_32] = {0}; + time_t timep; + struct tm *t; + + time(&timep); + t = localtime(&timep); + if (conf.running_mode == RUN_PRINT_LIVE) { + strftime(cur_time, sizeof(cur_time), "%d/%m/%y-%T", t); + + } else { + strftime(cur_time, sizeof(cur_time), "%d/%m/%y-%R", t); + } + printf("%s%s", cur_time, PRINT_SEC_SPLIT); +} + + +void +print_record() +{ + int i, j; + double *st_array; + struct module *mod = NULL; + + /* print summary data */ + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + if (!mod->n_item) { + print_array_stat(mod, NULL); + printf("%s", PRINT_SEC_SPLIT); + + } else { + for (j = 0; j < mod->n_item; j++) { + if (*mod->print_item != 0 && (mod->p_item != j)) { + continue; + } + st_array = &mod->st_array[j * mod->n_col]; + print_array_stat(mod, st_array); + printf("%s", PRINT_SEC_SPLIT); + } + if (mod->n_item > 1) { + printf("%s", PRINT_SEC_SPLIT); + } + } + } + printf("\n"); +} + + +/* running in print live mode */ +void +running_print_live() +{ + int print_num = 1, re_p_hdr = 0, cost_time = 0, to_sleep = 0; + + struct timeval tv_begin, tv_end; + gettimeofday(&tv_begin, NULL); + collect_record(); + + /* print header */ + print_header(); + + /* set struct module fields */ + init_module_fields(); + + /* skip first record */ + if (collect_record_stat() == 0) { + do_debug(LOG_INFO, "collect_record_stat warn\n"); + } + gettimeofday(&tv_end, NULL); + cost_time = (tv_end.tv_sec - tv_begin.tv_sec)*1000000 + (tv_end.tv_usec - tv_begin.tv_usec); + to_sleep = conf.print_interval*1000000 - cost_time; + if (to_sleep > 0) { + usleep(to_sleep); + } + + /* print live record */ + while (1) { + gettimeofday(&tv_begin, NULL); + collect_record(); + + if (!((print_num) % DEFAULT_PRINT_NUM) || re_p_hdr) { + /* get the header will print every DEFAULT_PRINT_NUM */ + print_header(); + re_p_hdr = 0; + print_num = 1; + } + + if (!collect_record_stat()) { + re_p_hdr = 1; + continue; + } + + /* print current time */ + print_current_time(); + print_record(); + fflush(stdout); + + print_num++; + + /* sleep every interval */ + gettimeofday(&tv_end, NULL); + cost_time = (tv_end.tv_sec - tv_begin.tv_sec)*1000000 + (tv_end.tv_usec - tv_begin.tv_usec); + to_sleep = conf.print_interval*1000000 - cost_time; + if (to_sleep > 0) { + usleep(to_sleep); + } + } +} + + + +/* find where start printting + * number:the suffix number of record data (tsar.data.number) + * return + * 0 ok + * 1 need find last tsar.data file + * 2 find error, find time is later than the last line at tsar.data.x, should stop find any more + * 3 find error, tsar haved stopped after find time, should stop find it + * 4 find error, data not exist, tsar just lost some time data which contains find time + * 5 log format error + * 6 other error + */ +int +find_offset_from_start(FILE *fp, int number) +{ + long fset, fend, file_len, off_start, off_end, offset, line_len; + char *p_sec_token; + time_t now, t_token, t_get; + struct tm stm; + static char line[LEN_10M] = {0}; + + /* get file len */ + if (fseek(fp, 0, SEEK_END) != 0 ) { + do_debug(LOG_FATAL, "fseek error:%s", strerror(errno)); + } + if ((fend = ftell(fp)) < 0) { + do_debug(LOG_FATAL, "ftell error:%s", strerror(errno)); + } + if (fseek(fp, 0, SEEK_SET) != 0) { + do_debug(LOG_FATAL, "fseek error:%s", strerror(errno)); + } + if ((fset = ftell(fp)) < 0) { + do_debug(LOG_FATAL, "ftell error:%s", strerror(errno)); + } + file_len = fend - fset; + + memset(&line, 0, LEN_10M); + if (!fgets(line, LEN_10M, fp)) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + line_len = strlen(line); + + /* get time token */ + time(&now); + if (conf.print_day > conf.print_max_day) { + /*get specify date by --date/-d*/ + stm.tm_year = conf.print_day / 10000 - 1900; + stm.tm_mon = conf.print_day % 10000 / 100 - 1; + stm.tm_mday = conf.print_day % 100; + stm.tm_hour = 0; + stm.tm_min = 0; + stm.tm_sec = 0; + stm.tm_isdst = -1; + t_token = mktime(&stm); + conf.print_day = (now - t_token) / (24 * 60 * 60); + } + + if (conf.print_day >= 0) { + if (conf.print_day > conf.print_max_day) { + conf.print_day = conf.print_max_day; + } + /* get day's beginning plus 8 hours.Set start and end time for print*/ + now = now - now % (24 * 60 * 60) - (8 * 60 * 60); + t_token = now - conf.print_day * (24 * 60 * 60) - (60 * conf.print_nline_interval); + conf.print_start_time = t_token; + conf.print_end_time = t_token + 24 * 60 * 60 + (60 * conf.print_nline_interval); + + } else { + /* set max days for print 6 months*/ + if (conf.print_ndays > conf.print_max_day) { + conf.print_ndays = conf.print_max_day; + } + now = now - now % (60 * conf.print_nline_interval); + if (conf.running_mode == RUN_WATCH) { + if (conf.print_nminute > (conf.print_max_day * 24 * 60)) { + conf.print_nminute = conf.print_max_day * 24 * 60; + } + t_token = now - (60 * conf.print_nminute) - (60 * conf.print_nline_interval); + } else { + t_token = now - conf.print_ndays * (24 * 60 * 60) - (60 * conf.print_nline_interval); + } + conf.print_start_time = t_token; + conf.print_end_time = now + (60 * conf.print_nline_interval); + } + + offset = off_start = 0; + off_end = file_len; + while (1) { + offset = (off_start + off_end) / 2; + memset(&line, 0, LEN_10M); + if (fseek(fp, offset, SEEK_SET) != 0) { + do_debug(LOG_FATAL, "fseek error:%s", strerror(errno)); + } + if (!fgets(line, LEN_10M, fp) && errno != 0) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + memset(&line, 0, LEN_10M); + if (!fgets(line, LEN_10M, fp) && errno != 0) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + if (0 != line[0] && offset > line_len) { + p_sec_token = strpbrk(line, SECTION_SPLIT); + if (p_sec_token) { + *p_sec_token = '\0'; + t_get = atol(line); + if (labs(t_get - t_token) <= 60) { + conf.print_file_number = number; + return 0; + } + + /* Binary Search */ + if (t_get > t_token) { + off_end = offset; + + } else if (t_get < t_token) { + off_start = offset; + } + + } else { + /* fatal error, log format error happen. */ + return 5; + } + + } else { + if (off_end == file_len) { + if (number > 0) { + conf.print_file_number = number - 1; + /* at the end of tsar.data.%d have some data lost during data rotate. stat from previous log file";*/ + return 2; + + } else { + /* researching tsar.data to end and not find log data you need.";*/ + return 3; + } + } + if (off_start == 0) { + conf.print_file_number = number; + /* need to research tsar.data.number+1; */ + return 1; + } + /* here should not be arrived. */ + return 6; + } + + if (offset == (off_start + off_end) / 2) { + if (off_start != 0) { + /* tsar has been down for a while, so the following time's stat we can provied only; */ + conf.print_file_number = number; + return 4; + } + return 6; + } + } +} + + +/* + * set and print record time + */ +long +set_record_time(const char *line) +{ + char *token, s_time[LEN_32] = {0}; + static long pre_time, c_time = 0; + + /* get record time */ + token = strpbrk(line, SECTION_SPLIT); + memcpy(s_time, line, token - line); + + /* swap time */ + pre_time = c_time; + c_time = atol(s_time); + + c_time = c_time - c_time % 60; + pre_time = pre_time - pre_time % 60; + /* if skip record when two lines haveing same minute */ + if (!(conf.print_interval = c_time - pre_time)) { + return 0; + + } else { + return c_time; + } +} + +/* + * check time if corret for pirnt from tsar.data + */ +int +check_time(const char *line) +{ + char *token, s_time[LEN_32] = {0}; + long now_time = 0; + static long pre_time; + + /* get record time */ + token = strpbrk(line, SECTION_SPLIT); + if (token == NULL) { + return 1; + } + if ((token - line) < 32) { + memcpy(s_time, line, token - line); + } + now_time = atol(s_time); + + /* check if time is over print_end_time */ + if (now_time >= conf.print_end_time) { + return 3; + } + /* if time is divide by conf.print_nline_interval*/ + now_time = now_time - now_time % 60; + if (!((now_time - conf.print_start_time) % ( 60 * conf.print_nline_interval)) && now_time > pre_time) { + /* check now and last record time interval */ + if (pre_time && now_time - pre_time == ( 60 * conf.print_nline_interval)) { + pre_time = now_time; + return 0; + } + pre_time = now_time; + + return 1; + + } else { + return 1; + } +} + +void +print_record_time(long c_time) +{ + char s_time[LEN_32] = {0}; + struct tm *t; + + t = localtime(&c_time); + strftime(s_time, sizeof(s_time), "%d/%m/%y-%R", t); + printf("%s%s", s_time, PRINT_SEC_SPLIT); +} + + +void +print_tail(int tail_type) +{ + int i, j, k; + double *m_tail; + struct module *mod = NULL; + + switch (tail_type) { + case TAIL_MAX: + printf("MAX %s", PRINT_SEC_SPLIT); + break; + case TAIL_MEAN: + printf("MEAN %s", PRINT_SEC_SPLIT); + break; + case TAIL_MIN: + printf("MIN %s", PRINT_SEC_SPLIT); + break; + default: + return; + } + + /* print summary data */ + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + switch (tail_type) { + case TAIL_MAX: + m_tail = mod->max_array; + break; + case TAIL_MEAN: + m_tail = mod->mean_array; + break; + case TAIL_MIN: + m_tail = mod->min_array; + break; + default: + return; + } + + k = 0; + for (j = 0; j < mod->n_item; j++) { + if (*mod->print_item != 0 && (mod->p_item != j)) { + k += mod->n_col; + continue; + } + int i; + struct mod_info *info = mod->info; + for (i=0; i < mod->n_col; i++) { + /* print record */ + if (mod->spec) { + if (((DATA_SUMMARY == conf.print_mode) && (SPEC_BIT == info[i].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (SPEC_BIT == info[i].summary_bit))) + { + printf_result(m_tail[k]); + } + + } else { + if (((DATA_SUMMARY == conf.print_mode) && (SUMMARY_BIT == info[i].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (HIDE_BIT != info[i].summary_bit))) + { + printf_result(m_tail[k]); + } + } + k++; + } + printf("%s", PRINT_SEC_SPLIT); + } + if (mod->n_item != 1) { + if (!m_tail) { + print_array_stat(mod, NULL); + } + printf("%s", PRINT_SEC_SPLIT); + } + } + printf("\n"); +} + + +/* + * init_running_print, if sucess then return fp, else return NULL + */ +FILE * +init_running_print() +{ + int i=0, k=0; + FILE *fp, *fptmp; + char filename[LEN_128] = {0}; + static char line[LEN_10M] = {0}; + + /* will print tail*/ + conf.print_tail = 1; + + fp = fopen(conf.output_file_path, "r"); + if (!fp) { + do_debug(LOG_FATAL, "unable to open the log file %s\n", conf.output_file_path); + } + /*log number to use for print*/ + conf.print_file_number = -1; + /* find start offset will print from tsar.data */ + k=find_offset_from_start(fp, i); + if (k == 1) { + /*find all possible record*/ + for (i=1; ; i++) { + memset(filename, 0, sizeof(filename)); + sprintf(filename, "%s.%d", conf.output_file_path, i); + fptmp = fopen(filename, "r"); + if (!fptmp) { + conf.print_file_number = i - 1; + break; + } + + k=find_offset_from_start(fptmp, i); + if (k==0 || k==4) { + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + fp=fptmp; + break; + } + if (k== 2) { + if (fseek(fp, 0, SEEK_SET) != 0) { + do_debug(LOG_FATAL, "fseek error:%s", strerror(errno)); + } + if (fclose(fptmp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + break; + } + if (k == 1) { + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + fp=fptmp; + continue; + } + if (k == 5 || k == 6) { + do_debug(LOG_FATAL, "log format error or find_offset_from_start have a bug. error code=%d\n", k); + } + } + } + + if (k == 5 || k == 6) { + do_debug(LOG_FATAL, "log format error or find_offset_from_start have a bug. error code=%d\n", k); + } + /* get record */ + if (!fgets(line, LEN_10M, fp)) { + do_debug(LOG_FATAL, "can't get enough log info\n"); + } + + /* read one line to init module parameter */ + read_line_to_module_record(line); + + /* print header */ + print_header(); + + /* set struct module fields */ + init_module_fields(); + + set_record_time(line); + return fp; +} + + +/* + * print mode, print data from tsar.data + */ +void +running_print() +{ + int print_num = 1, re_p_hdr = 0; + char filename[LEN_128] = {0}; + long n_record = 0, s_time; + FILE *fp; + static char line[LEN_10M] = {0}; + + /*find the position of the first record to be printed. (eg: middle of tsar.data.2)*/ + fp = init_running_print(); + + /* skip first record */ + if (collect_record_stat() == 0) { + do_debug(LOG_INFO, "collect_record_stat warn\n"); + } + + /*now ,print all printable records*/ + /*(eg: second half of tsar.data.2, then all of tsar.data.1, then tsar.data)*/ + while (1) { + if (!fgets(line, LEN_10M, fp)) { + if (conf.print_file_number <= 0) { + break; + + } else { + conf.print_file_number = conf.print_file_number - 1; + memset(filename, 0, sizeof(filename)); + if (conf.print_file_number == 0) { + sprintf(filename, "%s", conf.output_file_path); + + } else { + sprintf(filename, "%s.%d", conf.output_file_path, conf.print_file_number); + } + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + fp = fopen(filename, "r"); + if (!fp) { + do_debug(LOG_FATAL, "unable to open the log file %s.\n", filename); + } + continue; + } + } + + int k = check_time(line); + if (k == 1) { + continue; + } + if (k == 3) { + break; + } + + /* collect data then set mod->summary */ + read_line_to_module_record(line); + if (!(print_num % DEFAULT_PRINT_NUM) || re_p_hdr) { + /* get the header will print every DEFAULT_PRINT_NUM */ + print_header(); + re_p_hdr = 0; + print_num = 1; + } + + /* exclued the two record have same time */ + if (!(s_time = set_record_time(line))) { + continue; + } + /* reprint header because of n_item's modifing */ + if (!collect_record_stat()) { + re_p_hdr = 1; + continue; + } + + print_record_time(s_time); + print_record(); + n_record++; + print_num++; + memset(line, 0, sizeof(line)); + } + + if (n_record) { + printf("\n"); + print_tail(TAIL_MAX); + print_tail(TAIL_MEAN); + print_tail(TAIL_MIN); + } + + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + fp = NULL; +} + +char * +trim(char* src, int max_len) +{ + int cur_len = 0; + char *index=src; + + while (*index == ' ' && cur_len n) { + break; + } + if (fseek(fp, -2, SEEK_CUR) != 0) { + /* goto file head */ + if (fseek(fp, 0, SEEK_SET) != 0) { + do_debug(LOG_FATAL, "fseek error:%s", strerror(errno)); + } + break; + } + } + + return total_num; +} + +void +running_check(int check_type) +{ + int total_num, len[2] = {0}, i, j, k; + FILE *fp; + char filename[LEN_128] = {0}; + char tmp[10][LEN_4096]; + char host_name[LEN_64] = {0}; + struct module *mod = NULL; + struct stat statbuf; + time_t nowtime, ts[2] = {0}; + double *st_array; + char *line[2]; + static char check[LEN_4096 * 11] = {0}; + + /* get hostname */ + if (0 != gethostname(host_name, sizeof(host_name))) { + do_debug(LOG_FATAL, "tsar -check: gethostname err, errno=%d", errno); + } + i = 0; + while (host_name[i]) { + if (!isprint(host_name[i++])) { + host_name[i-1] = '\0'; + break; + } + } + sprintf(filename, "%s", conf.output_file_path); + fp = fopen(filename, "r"); + if (!fp) { + do_debug(LOG_FATAL, "unable to open the log file %s.\n", filename); + } + /* check file update time */ + stat(filename, &statbuf); + time(&nowtime); + if (nowtime - statbuf.st_mtime > 300) { + do_debug(LOG_FATAL, "/var/log/tsar.data is far away from now, now time is %d, last time is %d", nowtime, statbuf.st_mtime); + } + /*FIX ME*/ + total_num = seek_tail_lines(fp, 2, len); + if (total_num == 0) { + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + sprintf(filename, "%s.1", conf.output_file_path); + fp = fopen(filename, "r"); + if (!fp) { + do_debug(LOG_FATAL, "unable to open the log file %s.\n", filename); + } + /* count tsar.data.1 lines */ + total_num = seek_tail_lines(fp, 2, len); + if (total_num < 2) { + do_debug(LOG_FATAL, "not enough lines at log file %s.\n", filename); + } + + line[0] = malloc(len[0] + 2); + if (!fgets(line[0], len[0] + 2, fp)) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + line[1] = malloc(len[1] + 2); + if (!fgets(line[1], len[1] + 2, fp)) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + + } else if (total_num == 1) { + line[1] = malloc(len[1] + 2); + if (!fgets(line[1], len[1] + 2, fp)) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + sprintf(filename, "%s.1", conf.output_file_path); + fp = fopen(filename, "r"); + if (!fp) { + do_debug(LOG_FATAL, "unable to open the log file %s\n", filename); + } + /* go to the start of the last line at tsar.data.1 */ + total_num = seek_tail_lines(fp, 1, len); + + if (total_num < 1) { + do_debug(LOG_FATAL, "not enough lines at log file %s\n", filename); + } + line[0] = malloc(len[0] + 2); + if (!fgets(line[0], len[0] + 2, fp)) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + + } else { + line[0] = malloc(len[0] + 2); + if (!fgets(line[0], len[0] + 2, fp)) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + line[1] = malloc(len[1] + 2); + if (!fgets(line[1], len[1] + 2, fp)) { + do_debug(LOG_FATAL, "fgets error:%s", strerror(errno)); + } + } + + /*as fp is not used after here,close it */ + if (fclose(fp) < 0) { + do_debug(LOG_FATAL, "fclose error:%s", strerror(errno)); + } + fp = NULL; + + /* set struct module fields */ + init_module_fields(); + + /* read one line to init module parameter */ + ts[0] = read_line_to_module_record(line[0]); + free(line[0]); + collect_record_stat(); + + ts[1] = read_line_to_module_record(line[1]); + free(line[1]); + if (ts[0] && ts[1]) { + conf.print_interval = ts[1] - ts[0]; + if (conf.print_interval == 0) { + do_debug(LOG_FATAL, "running tsar -c too frequently"); + return; + } + } + collect_record_stat(); + + /*display check detail*/ + /* ---------------------------RUN_CHECK_NEW--------------------------------------- */ + if (check_type == RUN_CHECK_NEW) { + printf("%s\ttsar\t", host_name); + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable) { + continue; + } + struct mod_info *info = mod->info; + /* get mod name */ + char *mod_name = strstr(mod->opt_line, "--"); + if (mod_name) { + mod_name += 2; + } + + char opt[LEN_128] = {0}; + char *n_record = strdup(mod->record); + char *token = strtok(n_record, ITEM_SPLIT); + char *s_token; + + for (j = 0; j < mod->n_item; j++) { + memset(opt, 0, sizeof(opt)); + if (token) { + s_token = strpbrk(token, ITEM_SPSTART); + if (s_token) { + strncat(opt, token, s_token - token); + strcat(opt, ":"); + } + } + st_array = &mod->st_array[j * mod->n_col]; + for (k=0; k < mod->n_col; k++) { + if (mod->spec) { + if (!st_array || !mod->st_flag) { + if (((DATA_SUMMARY == conf.print_mode) && (SPEC_BIT == info[k].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (SPEC_BIT == info[k].summary_bit))) + { + printf("%s:%s%s=-%s", mod_name, opt, trim(info[k].hdr, LEN_128), " "); + } + + } else { + if (((DATA_SUMMARY == conf.print_mode) && (SPEC_BIT == info[k].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (SPEC_BIT == info[k].summary_bit))) + { + printf("%s:%s%s=", mod_name, opt, trim(info[k].hdr, LEN_128)); + printf("%0.1f ", st_array[k]); + } + } + + } else { + if (!st_array || !mod->st_flag) { + if (((DATA_SUMMARY == conf.print_mode) && (SUMMARY_BIT == info[k].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (HIDE_BIT != info[k].summary_bit))) + { + printf("%s:%s%s=-%s", mod_name, opt, trim(info[k].hdr, LEN_128), " "); + } + + } else { + if (((DATA_SUMMARY == conf.print_mode) && (SUMMARY_BIT == info[k].summary_bit)) + || ((DATA_DETAIL == conf.print_mode) && (HIDE_BIT != info[k].summary_bit))) + { + printf("%s:%s%s=", mod_name, opt, trim(info[k].hdr, LEN_128)); + printf("%0.1f ", st_array[k]); + } + } + + } + } + if (token) { + token = strtok(NULL, ITEM_SPLIT); + } + } + if (n_record) { + free(n_record); + n_record = NULL; + } + } + printf("\n"); + return; + } +#ifdef OLDTSAR + /*tsar -check output similar as: + v014119.cm3 tsar apache/qps=5.35 apache/rt=165.89 apache/busy=2 apache/idle=148 cpu=3.58 mem=74.93% load1=0.22 load5=0.27 load15=0.20 xvda=0.15 ifin=131.82 ifout=108.86 TCPretr=0.12 df/=4.04% df/home=10.00% df/opt=71.22% df/tmp=2.07% df/usr=21.27% df/var=5.19% + */ + /* ------------------------------RUN_CHECK------------------------------------------- */ + if (check_type == RUN_CHECK) { + //memset(tmp, 0, 10 * LEN_4096); + sprintf(check, "%s\ttsar\t", host_name); + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + if (!mod->enable){ + continue; + } + if (!strcmp(mod->name, "mod_apache")) { + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[0], " apache/qps=- apache/rt=- apache/busy=- apache/idle=-"); + + } else { + sprintf(tmp[0], " apache/qps=%0.2f apache/rt=%0.2f apache/busy=%0.0f apache/idle=%0.0f", st_array[0], st_array[1], st_array[3], st_array[4]); + } + } + } + if (!strcmp(mod->name, "mod_cpu")) { + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[1], " cpu=-"); + + } else { + sprintf(tmp[1], " cpu=%0.2f", st_array[5]); + } + } + } + if (!strcmp(mod->name, "mod_mem")) { + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[2], " mem=-"); + + } else { + sprintf(tmp[2], " mem=%0.2f%%", st_array[5]); + } + } + } + if (!strcmp(mod->name, "mod_load")) { + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[3], " load1=- load5=- load15=-"); + + } else { + sprintf(tmp[3], " load1=%0.2f load5=%0.2f load15=%0.2f", st_array[0], st_array[1], st_array[2]); + } + } + } + if (!strcmp(mod->name, "mod_io")) { + char opt[LEN_128] = {0}; + char item[LEN_128] = {0}; + char *n_record = strdup(mod->record); + char *token = strtok(n_record, ITEM_SPLIT); + char *s_token; + for (j = 0; j < mod->n_item && token != NULL; j++) { + s_token = strpbrk(token, ITEM_SPSTART); + if (s_token) { + memset(opt, 0, sizeof(opt)); + strncat(opt, token, s_token - token); + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(item, " %s=-", opt); + + } else { + sprintf(item, " %s=%0.2f", opt, st_array[10]); + } + strcat(tmp[4], item); + } + token = strtok(NULL, ITEM_SPLIT); + } + if (n_record) { + free(n_record); + n_record = NULL; + } + } + if (!strcmp(mod->name, "mod_traffic")) { + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[5], " ifin=- ifout=-"); + + } else { + sprintf(tmp[5], " ifin=%0.2f ifout=%0.2f", st_array[0] / 1000, st_array[1] / 1000); + } + } + } + if (!strcmp(mod->name, "mod_tcp")) { + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[6], " TCPretr=-"); + + } else { + sprintf(tmp[6], " TCPretr=%0.2f", st_array[7]); + } + } + } + if (!strcmp(mod->name, "mod_partition")) { + char opt[LEN_128] = {0}; + char item[LEN_128] = {0}; + char *n_record = strdup(mod->record); + char *token = strtok(n_record, ITEM_SPLIT); + char *s_token; + for (j = 0; j < mod->n_item && token != NULL; j++) { + s_token = strpbrk(token, ITEM_SPSTART); + if (s_token) { + memset(opt, 0, sizeof(opt)); + strncat(opt, token, s_token - token); + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(item, " df%s=-", opt); + + } else { + sprintf(item, " df%s=%0.2f%%", opt, st_array[3]); + } + strcat(tmp[7], item); + } + token = strtok(NULL, ITEM_SPLIT); + } + if (n_record) { + free(n_record); + n_record = NULL; + } + } + if (!strcmp(mod->name, "mod_nginx")){ + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[8], " nginx/qps=- nginx/rt=-"); + + } else { + sprintf(tmp[8], " nginx/qps=%0.2f nginx/rt=%0.2f", st_array[7], st_array[8]); + } + } + } + if (!strcmp(mod->name, "mod_swap")) { + for (j = 0; j < mod->n_item; j++) { + st_array = &mod->st_array[j * mod->n_col]; + if (!st_array || !mod->st_flag) { + sprintf(tmp[9], " swap/total=- swap/util=-"); + + } else { + sprintf(tmp[9], " swap/total=%0.2f swap/util=%0.2f%%", st_array[2] / 1024 / 1024, st_array[3]); + } + } + } + } + for (j = 0; j < 10; j++) { + strcat(check, tmp[j]); + } + printf("%s\n", check); + } +#endif +} +/*end*/ diff --git a/source/tools/monitor/mservice/master/src/output_tcp.c b/source/tools/monitor/mservice/master/src/output_tcp.c new file mode 100644 index 00000000..f04bd0c7 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/output_tcp.c @@ -0,0 +1,117 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include +#include "tsar.h" + +void +send_data_tcp(char *output_addr, char *data, int len) +{ + int fd, flags, res; + fd_set fdr, fdw; + struct timeval timeout; + struct sockaddr_in db_addr; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + do_debug(LOG_FATAL, "can't get socket"); + } + + /* set socket fd noblock */ + if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { + close(fd); + return; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(fd); + return; + } + + /* get db server address */ + db_addr = *str2sa(output_addr); + + if (connect(fd, (struct sockaddr*)&db_addr, sizeof(db_addr)) != 0) { + if (errno != EINPROGRESS) { // EINPROGRESS + close(fd); + return; + + } else { + goto select; + } + + } else { + goto send; + } + +select: + FD_ZERO(&fdr); + FD_ZERO(&fdw); + FD_SET(fd, &fdr); + FD_SET(fd, &fdw); + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + res = select(fd + 1, &fdr, &fdw, NULL, &timeout); + if (res <= 0) { + close(fd); + return; + } + +send: + if (len > 0 && write(fd, data, len) != len) { + do_debug(LOG_ERR, "output_db write error:dst:%s\terrno:%s\n",output_addr, strerror(errno)); + } + close(fd); +} + +void +output_multi_tcp(int have_collect) +{ + int out_pipe[2]; + int len; + static char data[LEN_10M] = {0}; + int i; + /* only output from output_tcp_mod */ + reload_modules(conf.output_tcp_mod); + + if (!strcasecmp(conf.output_tcp_merge, "on") || !strcasecmp(conf.output_tcp_merge, "enable")) { + conf.print_merge = MERGE_ITEM; + } else { + conf.print_merge = MERGE_NOT; + } + + if (pipe(out_pipe) != 0) { + return; + } + + dup2(out_pipe[1], STDOUT_FILENO); + close(out_pipe[1]); + + running_check(RUN_CHECK_NEW); + + fflush(stdout); + len = read(out_pipe[0], data, LEN_10M); + close(out_pipe[0]); + /*now ,the data to send is gotten*/ + for(i = 0; i < conf.output_tcp_addr_num; i++){ + send_data_tcp(conf.output_tcp_addr[i], data, len); + } +} diff --git a/source/tools/monitor/mservice/master/src/tsar.c b/source/tools/monitor/mservice/master/src/tsar.c new file mode 100644 index 00000000..e861d9d5 --- /dev/null +++ b/source/tools/monitor/mservice/master/src/tsar.c @@ -0,0 +1,369 @@ + +/* + * (C) 2010-2011 Alibaba Group Holding Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "tsar.h" + + +struct statistic statis; +struct configure conf; +struct module *mods[MAX_MOD_NUM]; + +void +usage() +{ + int i; + struct module *mod; + + fprintf(stderr, + "Usage: mservice [options]\n" + "Options:\n" +#ifdef OLDTSAR + /*used for check alert*/ + " -check display last record for alert\n" + /*end*/ +#endif + " --check/-C display last record for alert.example:tsar --check / tsar --check --cpu --io\n" + " --watch/-w display last records in N mimutes. example:tsar --watch 30 / tsar --watch 30 --cpu --io\n" + " --cron/-c run in cron mode, output data to file\n" + " --interval/-i specify intervals numbers, in minutes if with --live, it is in seconds\n" + " --list/-L list enabled modules\n" + " --live/-l running print live mode, which module will print\n" + " --file/-f specify a filepath as input\n" + " --ndays/-n show the value for the past days (default: 1)\n" + " --date/-d show the value for the specify day(n or YYYYMMDD)\n" + " --merge/-m merge multiply item to one\n" + " --detail/-D do not conver data to K/M/G\n" + " --spec/-s show spec field data, tsar --cpu -s sys,util\n" + " --item/-I show spec item data, tsar --io -I sda\n" + " --serv/-S run as service \n" + " --help/-h help\n"); + + fprintf(stderr, + "Modules Enabled:\n" + ); + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + fprintf(stderr, "%s\n", mod->usage); + } + + exit(0); +} + + +struct option longopts[] = { + { "cron", no_argument, NULL, 'c' }, + { "check", no_argument, NULL, 'C' }, + { "watch", required_argument, NULL, 'w' }, + { "interval", required_argument, NULL, 'i' }, + { "list", no_argument, NULL, 'L' }, + { "live", no_argument, NULL, 'l' }, + { "file", required_argument, NULL, 'f' }, + { "ndays", required_argument, NULL, 'n' }, + { "date", required_argument, NULL, 'd' }, + { "merge", no_argument, NULL, 'm' }, + { "detail", no_argument, NULL, 'D' }, + { "spec", required_argument, NULL, 's' }, + { "item", required_argument, NULL, 'I' }, + { "serv", no_argument, NULL, 'S' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, 0, 0}, +}; + + +static void +main_init(int argc, char **argv) +{ + int opt, oind = 0; +#ifdef OLDTSAR + /* check option for tsar1.0 */ + if (argc >= 2) { + if (!strcmp(argv[1], "-check") && argc == 2) { + conf.running_mode = RUN_CHECK; + conf.print_mode = DATA_DETAIL; + conf.print_interval = 60; + conf.print_tail = 0; + conf.print_nline_interval = conf.print_interval; + return; + } + } + /*end*/ +#endif + while ((opt = getopt_long(argc, argv, ":cCw:i:Llf:n:d:s:I:mhDS", longopts, NULL)) != -1) { + oind++; + switch (opt) { + case 'c': + conf.running_mode = RUN_CRON; + break; + case 'C': + conf.running_mode = RUN_CHECK_NEW; + break; + case 'w': + conf.running_mode = RUN_WATCH; + conf.print_nminute = atoi(optarg); + oind++; + break; + case 'i': + conf.print_interval = atoi(optarg); + oind++; + break; + case 'L': + conf.running_mode = RUN_LIST; + break; + case 'l': + conf.running_mode = RUN_PRINT_LIVE; + break; + case 'f': + strncpy(conf.output_file_path, optarg, LEN_128); + break; + case 's': + set_special_field(optarg); + break; + case 'I': + set_special_item(optarg); + break; + case 'n': + conf.print_ndays = atoi(optarg); + oind++; + break; + case 'd': + conf.print_day = atoi(optarg); + oind++; + break; + case 'm': + conf.print_merge = MERGE_ITEM; + break; + case 'D': + conf.print_detail = TRUE; + break; + case 'S': + conf.running_mode = RUN_SERVICE; + break; + case 'h': + usage(); + break; + case ':': + printf("must have parameter\n"); + usage(); + break; + case '?': + if (argv[oind] && strstr(argv[oind], "--")) { + strncat(conf.output_print_mod, argv[oind], LEN_512 - sizeof(DATA_SPLIT)); + strcat(conf.output_print_mod, DATA_SPLIT); + + } else { + usage(); + } + } + } + /* set default parameter */ + if (!conf.print_ndays) { + conf.print_ndays = 1; + } + + if (!conf.print_interval) { + conf.print_interval = DEFAULT_PRINT_INTERVAL; + } + + if (RUN_NULL == conf.running_mode) { + conf.running_mode = RUN_PRINT; + + } else if (conf.running_mode == RUN_CHECK_NEW) { + conf.print_interval = 60; + conf.print_tail = 0; + } + + if (!strlen(conf.output_print_mod)) { + conf.print_mode = DATA_SUMMARY; + + } else { + conf.print_mode = DATA_DETAIL; + } + + strcpy(conf.config_file, DEFAULT_CONF_FILE_PATH); + if (access(conf.config_file, F_OK)) { + do_debug(LOG_FATAL, "main_init: can't find tsar.conf"); + } +} + + +void +shut_down() +{ + free_modules(); + +/* + memset(&conf, 0, sizeof(struct configure)); + memset(mods, 0, sizeof(mods)); + memset(&statis, 0, sizeof(struct statistic)); +*/ +} + + +void +running_list() +{ + int i; + struct module *mod; + + printf("tsar enable follow modules:\n"); + + for (i = 0; i < statis.total_mod_num; i++) { + mod = mods[i]; + printf(" %s\n", mod->name + 4); + } +} + + +void +running_cron() +{ + int have_collect = 0; + /* output interface */ + if (strstr(conf.output_interface, "file")) { + /* output data */ + collect_record(); + output_file(); + have_collect = 1; + } + + if (strstr(conf.output_interface, "db")) { + output_db(have_collect); + } + if (strstr(conf.output_interface, "nagios")) { + output_nagios(); + } + if (strstr(conf.output_interface, "tcp")) { + output_multi_tcp(have_collect); + } +} + +void *cron_thread(void *arg) +{ + while (1) { + statis.cur_time = time(NULL); + running_cron(); + sleep(conf.cron_period); + } +} + +static void serivce_main(void) +{ + pthread_t th; + int res; + + res = pthread_create(&th, NULL, cron_thread, NULL); + if (res) { + printf("create cron thread failed\n"); + return; + } + + http_server(); +} + +int +main(int argc, char **argv) +{ + + parse_config_file(DEFAULT_CONF_FILE_PATH); + + load_modules(); + + statis.cur_time = time(NULL); + + conf.print_day = -1; + + main_init(argc, argv); + /* + * enter running + */ + switch (conf.running_mode) { + case RUN_LIST: + running_list(); + break; + + case RUN_CRON: + conf.print_mode = DATA_DETAIL; + running_cron(); + break; +#ifdef OLDTSAR + /*for check option*/ + case RUN_CHECK: + reload_check_modules(); + /* disable module when n_col is zero */ + running_check(RUN_CHECK); + break; + /*end*/ +#endif + case RUN_CHECK_NEW: + if (reload_modules(conf.output_print_mod)) { + conf.print_mode = DATA_DETAIL; + }; + /* disable module when n_col is zero */ + disable_col_zero(); + running_check(RUN_CHECK_NEW); + break; + case RUN_PRINT: + /* reload module by output_stdio_mod and output_print_mod*/ + reload_modules(conf.output_stdio_mod); + reload_modules(conf.output_print_mod); + + /* disable module when n_col is zero */ + disable_col_zero(); + + /* set conf.print_nline_interval */ + conf.print_nline_interval = conf.print_interval; + + running_print(); + break; + + case RUN_PRINT_LIVE: + /* reload module by output_stdio_mod and output_print_mod*/ + reload_modules(conf.output_stdio_mod); + reload_modules(conf.output_print_mod); + + /* disable module when n_col is zero */ + disable_col_zero(); + + running_print_live(); + break; + case RUN_WATCH: + /* reload module by output_stdio_mod and output_print_mod*/ + reload_modules(conf.output_stdio_mod); + reload_modules(conf.output_print_mod); + + /* disable module when n_col is zero */ + disable_col_zero(); + + /* set conf.print_nline_interval */ + conf.print_nline_interval = conf.print_interval; + + running_print(); + break; + case RUN_SERVICE: + serivce_main(); + break; + + default: + break; + } + + shut_down(); + return 0; +} diff --git a/source/tools/monitor/mservice/master/tools/bytes.sh b/source/tools/monitor/mservice/master/tools/bytes.sh new file mode 100755 index 00000000..e6dea0ac --- /dev/null +++ b/source/tools/monitor/mservice/master/tools/bytes.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +if test $# -ne 2; then + echo "Usage: `basename $0` tsarfile pngfile" 1>&2 + exit 1 +fi + +datafile=$1.tmp + +grep ":" $1 | awk 'function f(a) { if (index(a, "G") > 0) return a * 1000 * 1000; else if (index(a, "M") > 0) return a * 1000; else return a} {printf "%s %.2f %.2f\n", $1, f($2), f($3)}' > $datafile + +start=`head -n1 $datafile | awk '{print $1}'` +end=`tail -n1 $datafile | awk '{print $1}'` +duration="$start - $end" + +gnuplot << EOF +set terminal png +set output "$2" +set title "bytes in/out ($duration)" +set xlabel "time" +set ylabel "K bytes" +set xdata time +set timefmt "%d/%m-%H:%M" +set format x "%H:%M" +plot "$datafile" using 1:2 title "bytes in" with lines, "$datafile" using 1:3 title "bytes out" with lines + +EOF + +rm $datafile diff --git a/source/tools/monitor/mservice/master/tools/cpu.sh b/source/tools/monitor/mservice/master/tools/cpu.sh new file mode 100755 index 00000000..74f81cd8 --- /dev/null +++ b/source/tools/monitor/mservice/master/tools/cpu.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +if test $# -ne 2; then + echo "Usage: `basename $0` tsarfile pngfile" 1>&2 + exit 1 +fi + +datafile=$1.tmp + +grep ":" $1 | grep -v '\-\-' | awk '{print $1 " " $2 " " $3 " " $4 " " $7}' > $datafile + +start=`head -n1 $datafile | awk '{print $1}'` +end=`tail -n1 $datafile | awk '{print $1}'` +duration="$start - $end" + +gnuplot << EOF +set terminal png +set output "$2" +set title "CPU utilization ($duration)" +set xlabel "time" +set ylabel "percent (%)" +set yrange [ 0 : 100 ] +set xdata time +set timefmt "%d/%m-%H:%M" +set format x "%H:%M" +plot "$datafile" using 1:2 title "user" with lines, "$datafile" using 1:3 title "sys" with lines, "$datafile" using 1:4 title "wait" with lines, "$datafile" using 1:5 title "util" with lines + +EOF + +rm $datafile diff --git a/source/tools/monitor/mservice/master/tools/load.sh b/source/tools/monitor/mservice/master/tools/load.sh new file mode 100755 index 00000000..4c5a7917 --- /dev/null +++ b/source/tools/monitor/mservice/master/tools/load.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +if test $# -ne 2; then + echo "Usage: `basename $0` tsarfile pngfile" 1>&2 + exit 1 +fi + +datafile=$1.tmp + +grep ":" $1 | grep -v '\-\-' | awk '{print $1 " " $2 " " $3 " " $4}' > $datafile + +start=`head -n1 $datafile | awk '{print $1}'` +end=`tail -n1 $datafile | awk '{print $1}'` +duration="$start - $end" + +gnuplot << EOF +set terminal png +set output "$2" +set title "load ($duration)" +set xlabel "time" +set xdata time +set timefmt "%d/%m-%H:%M" +set format x "%H:%M" +plot "$datafile" using 1:2 title "load1" with lines, "$datafile" using 1:3 title "load5" with lines, "$datafile" using 1:4 title "load15" with lines +EOF + +rm $datafile diff --git a/source/tools/monitor/mservice/master/tools/mem.sh b/source/tools/monitor/mservice/master/tools/mem.sh new file mode 100755 index 00000000..4cd6be2c --- /dev/null +++ b/source/tools/monitor/mservice/master/tools/mem.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +if test $# -ne 2; then + echo "Usage: `basename $0` tsarfile pngfile" 1>&2 + exit 1 +fi + +datafile=$1.tmp + +grep ":" $1 | awk 'function f(a){if(index(a,"G")>0) return a*1000; else return a} {printf "%s %.2f %.2f %.2f %.2f %.2f\n", $1, f($2),f($3),f($4),f($5),f($6)}' > $datafile + +start=`head -n1 $datafile | awk '{print $1}'` +end=`tail -n1 $datafile | awk '{print $1}'` +duration="$start - $end" +total=`head -n1 $datafile | awk '{print $6}'` + +gnuplot << EOF +set terminal png +set output "$2" +set title "memory utilization, total = ${total}M ($duration)" +set xlabel "time" +set ylabel "M bytes" +set yrange [ 0 : $total * 1.1 ] +set xdata time +set timefmt "%d/%m-%H:%M" +set format x "%H:%M" +plot "$datafile" using 1:2 title "free" with lines, "$datafile" using 1:3 title "used" with lines, "$datafile" using 1:4 title "buff" with lines, "$datafile" using 1:5 title "cache" with lines + +EOF + +rm $datafile diff --git a/source/tools/monitor/mservice/master/tools/packets.sh b/source/tools/monitor/mservice/master/tools/packets.sh new file mode 100755 index 00000000..8fed4d9b --- /dev/null +++ b/source/tools/monitor/mservice/master/tools/packets.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +if test $# -ne 2; then + echo "Usage: `basename $0` tsarfile pngfile" 1>&2 + exit 1 +fi + +datafile=$1.tmp + +grep ":" $1 | awk 'function f(a) { if (index(a, "M") > 0) return a * 1000 * 1000; else if (index(a, "K") > 0) return a * 1000; else return a} {printf "%s %.2f %.2f\n", $1, f($4), f($5)}' > $datafile + +start=`head -n1 $datafile | awk '{print $1}'` +end=`tail -n1 $datafile | awk '{print $1}'` +duration="$start - $end" + +gnuplot << EOF +set terminal png +set output "$2" +set title "packets in/out ($duration)" +set xlabel "time" +set xdata time +set timefmt "%d/%m-%H:%M" +set format x "%H:%M" +plot "$datafile" using 1:2 title "packets in" with lines, "$datafile" using 1:3 title "packets out" with lines + +EOF + +rm $datafile diff --git a/source/tools/monitor/mservice/master/tools/readme.txt b/source/tools/monitor/mservice/master/tools/readme.txt new file mode 100644 index 00000000..404ef233 --- /dev/null +++ b/source/tools/monitor/mservice/master/tools/readme.txt @@ -0,0 +1,26 @@ +画图脚本使用方法 + +流程: +先用tsar生成分类数据,再用脚本处理数据文件生成png图片即可。 + +1、画CPU使用率的图 + tsar --cpu > cpu.txt + ./cpu.sh cpu.txt cpu.png +2、内存使用率的图 + tsar --mem > mem.txt + ./mem.sh mem.txt mem.png +3、画load图 + tsar --load > load.txt + ./load.sh load.txt load.png +4、画TCP重传率 + tsar --tcp > retran.txt + ./retran.sh retran.txt retran.png +5、画in和out的包 + tsar --traffic > traffic.txt + ./packets.sh traffic.txt packets.png +6、画in和out的字节数 + tsar --traffic > traffic.txt + ./bytes.sh traffic.txt bytes.png + + +若遇使用问题请联系叔度(shudu@taobao.com) diff --git a/source/tools/monitor/mservice/master/tools/retran.sh b/source/tools/monitor/mservice/master/tools/retran.sh new file mode 100755 index 00000000..b8286dea --- /dev/null +++ b/source/tools/monitor/mservice/master/tools/retran.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +if test $# -ne 2; then + echo "Usage: `basename $0` tsarfile pngfile" 1>&2 + exit 1 +fi + +datafile=$1.tmp + +grep ":" $1 | grep -v '\-\-' | awk '{print $1 " " $6}' > $datafile + +start=`head -n1 $datafile | awk '{print $1}'` +end=`tail -n1 $datafile | awk '{print $1}'` +duration="$start - $end" + +gnuplot << EOF +set terminal png +set output "$2" +set title "TCP retransmission rate ($duration)" +set xlabel "time" +set ylabel "percent (%)" +set yrange [ 0 : 10 ] +set xdata time +set timefmt "%d/%m-%H:%M" +set format x "%H:%M" +plot "$datafile" using 1:2 title "rate" with lines +EOF + +rm $datafile -- Gitee From 533be09cd044605bae9d68d4904179ab73a305cc Mon Sep 17 00:00:00 2001 From: Wetp Zhang Date: Thu, 17 Feb 2022 11:10:36 +0800 Subject: [PATCH 4/4] add doc for mservice Signed-off-by: Wetp Zhang --- doc/mservice.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 doc/mservice.txt diff --git a/doc/mservice.txt b/doc/mservice.txt new file mode 100644 index 00000000..67997723 --- /dev/null +++ b/doc/mservice.txt @@ -0,0 +1,20 @@ +sysak 监控服务使用说明 + +mservice可在多个工作模式下运行: +1、后台服务模式 + sysak mservice -S + 在后台服务模式下,mservice会提供两种服务 + 1) 定期采集系统各项指标存储到指定的文件中; + 2) 提供http服务,当收到http请求时,将对应的系统指标发回请求端 + 例:客户通过curl http://serverip:9200/metric采集当前系统指标 +2、数据查看模式 + sysak mservice + 自动读取保存到本地文件中的数据,并格式化显示出来 +这2种模式运行时还可以带其他参考,详细参考sysak mservice -h帮助信息 + +服务配置: +1、存储的文件位置以及支持采集的指标项等都可以通过配置文件进行配置 +2、配置文件存放在/etc/sysak/sysakmon.conf +3、修改配置后,需要重启mservice服务 + + -- Gitee