Zabbix低级发现结合jstat命令自动监控Java进程(jdk 1.8版本)

简介:
  1. jstat无法使用的问题

因为java是tomcat启动的,所以使用jstat命令,报not found错误。

解决方法,网上很多都不行,以下可以

20160326153651784

简单的说,就是sudo -u tomcat /usr/java/jdk/bin/jstat -gcutil 22631

2.vim /etc/sudoers

增加这两行

1
2
zabbix ALL=(tomcat) NOPASSWD: /bin/netstat , /usr/bin/omreport , /usr/java/jdk/bin/jstat , /usr/bin/python
tomcat ALL=(ALL) NOPASSWD: /bin/kill , /bin/chown , /usr/java/jdk/bin/jstat , /usr/bin/python , /bin/netstat , /usr/bin/omreport

就是zabbix必须sudo成tomcat

3.jstat的输出变化

java1.8取消了永久区

1
2
3
sudo  -u tomcat  /usr/java/jdk/bin/jstat  -gc 22631
  S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
19968.0 20992.0  0.0   4810.3 88576.0  42080.7   393216.0   32415.5   43952.0 42767.3 5296.0 5074.8     25    0.428   2      0.150    0.578

与1.7的不同,去掉了Perm

MC:方法区大小

MU:方法区使用大小

CCSC:压缩类空间大小

CCSU:压缩类空间使用大小

4.zabbix agentd配置变化

1
2
3
cat  /usr/local/zabbix/etc/zabbix_agentd .conf.d /discovery_java_status .conf 
UserParameter=java.discovery, /usr/bin/python  /usr/local/zabbix/bin/java_discovery .py
UserParameter=java.discovery_status[*], /usr/bin/python  /usr/local/zabbix/bin/jstat_status .py $1 $2

cd /usr/local/zabbix/bin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cat  java_discovery.py
#/usr/bin/python
#This script is used to discovery disk on the server
import  subprocess
import  os
import  socket
import  json
import  glob
  
java_names_file= 'java_names.txt'
javas=[]
if  os.path.isfile(java_names_file):
#   print 'java_names_file exists!'
#####
##### here should use % (java_names_file) instead of using the python variable java_names_file directly inside the '''   ''' quotes
#####
  
    args= '' 'awk -F' : ' ' {print $1 ':' $2} ' %s' ''   % (java_names_file)
    t=subprocess.Popen(args,shell=True,stdout=subprocess.PIPE).communicate()[0]
elif  glob.glob( '/opt/xx/*_tomcat' ) and not os.path.isdir( '/opt/logs/logstash' ) and not os.path.isdir( '/opt/app/elasticsearch/config' ):
    t=subprocess.Popen( 'cd /opt/xx && ls *_tomcat|grep _tomcat' ,shell=True,stdout=subprocess.PIPE)
   
for  java  in  t.stdout.readlines():
     if  len(java) != 0:
        javas.append({ '{#JAVA_NAME}' :java.strip( '\n' ).strip( ':' )})
print json.dumps({ 'data' :javas},indent=4,separators=( ',' , ':' ))

自己做修改,修改命令 cd /opt/xx && ls *_tomcat|grep _tomcat

这里说明以下,tomcat应用最好起统一的名字,比如xx_tomcat等,这样写脚本起来方便

cd /usr/local/zabbix/bin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
cat  jstat_status.py
#!/usr/bin/python
  
import  subprocess
import  sys
import  os
  
__maintainer__ =  "John Wang"
  
jps =  '/usr/java/jdk/bin/jps'
jstat =  '/usr/java/jdk/bin/jstat'
zabbix_sender =  "/usr/local/zabbix/bin/zabbix_sender"
zabbix_conf =  "/usr/local/zabbix/etc/zabbix_agentd.conf"      
send_to_zabbix = 1
ip=os.popen( "ifconfig|grep 'inet '|grep -v '127.0'|xargs|awk -F '[ :]' '{print $3}'" ).readline().rstrip()
serverip= "你的zabbix服务端ip"
  
#"{#JAVA_NAME}":"tomcat_web_1"
  
  
def usage():
     "" "Display program usage" ""
  
     print  "\nUsage : " , sys.argv[0],  " java_name alive|all"
     print  "Modes : \n\talive : Return pid of running processs\n\tall : Send jstat stats as well"
     sys. exit (1)
  
  
class Jprocess:
  
     def __init__(self, arg):
         self.pdict = {
         "jpname" : arg,
         }
  
         self.zdict = {
         "Heap_used"  : 0,
                 "Heap_ratio"  : 0,
         "Heap_max"  : 0,
         "Perm_used"  : 0,
                 "Perm_ratio"  : 0,
         "Perm_max"   : 0,
                 "S0_used"    : 0,
                 "S0_ratio"   : 0,
                 "S0_max"     : 0,
                 "S1_used"    : 0,
                 "S1_ratio"   : 0,
                 "S1_max"     : 0,
                 "Eden_used"  : 0,
                 "Eden_ratio"  : 0,
                 "Eden_max"   : 0,
                 "Old_used"   : 0,
                 "Old_ratio"  : 0,
                 "Old_max"    : 0,
                 "YGC"        : 0,
                 "YGCT"       : 0,
                 "YGCT_avg"       : 0,
                 "FGC"        : 0,
                 "FGCT"       : 0,
                 "FGCT_avg"       : 0,
                 "GCT"        : 0,
                 "GCT_avg"        : 0,
                  
         }
  
  
     def chk_proc(self):
#  ps -ef|grep java|grep tomcat_web_1|awk '{print $2}'
#                print self.pdict['jpname']
                 pidarg =  '' 'ps -ef|grep java|grep %s|grep -v grep|awk ' {print $2} ' ' ''  %(self.pdict[ 'jpname' ]) 
                 pidout = subprocess.Popen(pidarg,shell=True,stdout=subprocess.PIPE) 
                 pid = pidout.stdout.readline().strip( '\n'
                 if  pid !=  ""  :
                    self.pdict[ 'pid' ] = pid
#                   print "Process found :", java_name, "with pid :", self.pdict['pid']
                 else :
                    self.pdict[ 'pid' ] =  ""
#                   print "Process not found"
                 return  self.pdict[ 'pid' ]
  
     def get_jstats(self):
         if  self.pdict[ 'pid' ] ==  "" :
             return  False
         self.pdict.update(self.fill_jstats( "-gc" ))
         self.pdict.update(self.fill_jstats( "-gccapacity" ))
         self.pdict.update(self.fill_jstats( "-gcutil" ))
  
#        print "\nDumping collected stat dictionary\n-----\n", self.pdict, "\n-----\n"
  
     def fill_jstats(self, opts):
#        print "\nGetting", opts, "stats for process", self.pdict['pid'], "with command : sudo", jstat, opts, self.pdict['pid'] ,"\n"
         jstatout = subprocess.Popen([ 'sudo' , '-u' , 'tomcat' , jstat, opts, self.pdict[ 'pid' ]], stdout=subprocess.PIPE)
         stdout, stderr = jstatout.communicate()
         legend, data = stdout. split ( '\n' ,1)
         mydict = dict(zip(legend. split (), data. split ()))
         return  mydict
  
     def compute_jstats(self):
         if  self.pdict[ 'pid' ] ==  "" :
             return  False
         self.zdict[ 'S0_used' ] =  format (float(self.pdict[ 'S0U' ]) * 1024, '0.2f' )
         self.zdict[ 'S0_max' ] =   format (float(self.pdict[ 'S0C' ]) * 1024, '0.2f' )
         self.zdict[ 'S0_ratio' ] =  format (float(self.pdict[ 'S0' ]), '0.2f' )
 
         self.zdict[ 'S1_used' ] =  format (float(self.pdict[ 'S1U' ]) * 1024, '0.2f' )
         self.zdict[ 'S1_max' ] =  format (float(self.pdict[ 'S1C' ]) * 1024, '0.2f' )
         self.zdict[ 'S1_ratio' ] =  format (float(self.pdict[ 'S1' ]), '0.2f' )
  
         self.zdict[ 'Old_used' ] =  format (float(self.pdict[ 'OU' ]) * 1024, '0.2f' )
         self.zdict[ 'Old_max' ] =   format (float(self.pdict[ 'OC' ]) * 1024, '0.2f' )
         self.zdict[ 'Old_ratio' ] =  format (float(self.pdict[ 'O' ]), '0.2f' )
 
         self.zdict[ 'Eden_used' ] =  format (float(self.pdict[ 'EU' ]) * 1024, '0.2f' )
         self.zdict[ 'Eden_max' ] =  format (float(self.pdict[ 'EC' ]) * 1024, '0.2f' )
         self.zdict[ 'Eden_ratio' ] =  format (float(self.pdict[ 'E' ]), '0.2f' )            
# self.zdict['Perm_used'] = format(float(self.pdict['PU']) * 1024,'0.2f')
# self.zdict['Perm_max'] = format(float(self.pdict['PC']) * 1024,'0.2f')
# self.zdict['Perm_ratio'] = format(float(self.pdict['P']),'0.2f')
                 
         self.zdict[ 'Heap_used' ] =  format ((float(self.pdict[ 'EU' ]) + float(self.pdict[ 'S0U' ]) + float(self.pdict[ 'S1U' ])  + float(self.pdict[ 'OU' ])) * 1024, '0.2f' )
         self.zdict[ 'Heap_max' ] =  format ((float(self.pdict[ 'EC' ]) + float(self.pdict[ 'S0C' ]) + float(self.pdict[ 'S1C' ])  + float(self.pdict[ 'OC' ])) * 1024, '0.2f' )
         self.zdict[ 'Heap_ratio' ] =  format (float(self.zdict[ 'Heap_used' ]) / float(self.zdict[ 'Heap_max' ])*100, '0.2f' )
 
         self.zdict[ 'YGC' ] = self.pdict[ 'YGC' ]
         self.zdict[ 'FGC' ] = self.pdict[ 'FGC' ]
         self.zdict[ 'YGCT' ] =  format (float(self.pdict[ 'YGCT' ]), '0.3f' )
         self.zdict[ 'FGCT' ] =  format (float(self.pdict[ 'FGCT' ]), '0.3f' )
         self.zdict[ 'GCT' ] =  format (float(self.pdict[ 'GCT' ]), '0.3f'
     
         if  self.pdict[ 'YGC' ] ==  '0' :
            self.zdict[ 'YGCT_avg' ] =  '0'
         else
            self.zdict[ 'YGCT_avg' ] =  format (float(self.pdict[ 'YGCT' ]) /float (self.pdict[ 'YGC' ]), '0.3f' )
         if  self.pdict[ 'FGC' ] ==  '0' :
            self.zdict[ 'FGCT_avg' ] =  '0'
         else :
            self.zdict[ 'FGCT_avg' ] =  format (float(self.pdict[ 'FGCT' ]) /float (self.pdict[ 'FGC' ]), '0.3f' )
         if  self.pdict[ 'YGC' ] ==  '0'  and self.pdict[ 'FGC' ] ==  '0' :
            self.zdict[ 'GCT_avg' ] =  '0' 
         else :
            self.zdict[ 'GCT_avg' ] =  format (float(self.pdict[ 'GCT' ])/(float(self.pdict[ 'YGC' ]) + float(self.pdict[ 'FGC' ])), '0.3f'
                   
  
        # print "Dumping zabbix stat dictionary\n-----\n", self.zdict, "\n-----\n"
  
     def send_to_zabbix(self, metric):
####      {#JAVA_NAME} tomcat_web_1 
####      UserParameter=java.discovery,/usr/bin/python /opt/app/zabbix/sbin/java_discovery.py
####      UserParameter=java.discovery_status[*],/opt/app/zabbix/sbin/jstat_status.sh $1 $2 $3 $4 
####      java.discovery_status[tomcat_web_1,Perm_used]
####      java.discovery_status[{#JAVA_NAME},Perm_used]
         key =  "java.discovery_status["  + self.pdict[ 'jpname' ] +  ","  + metric +  "]"
  
         if  self.pdict[ 'pid' ] !=  ""  and  send_to_zabbix > 0:
            #print key + ":" + str(self.zdict[metric])
            try:
                                       
                  subprocess.call([zabbix_sender,  "-c" , zabbix_conf,  "-k" , key,  "-o" , str(self.zdict[metric])], stdout=FNULL,stderr=FNULL, shell=False) 
            except OSError, detail:
                  print  "Something went wrong while exectuting zabbix_sender : " , detail
         else :
            print  "Simulation: the following command would be execucted :\n" , zabbix_sender,  "-c" , zabbix_conf,  "-k" , key,  "-o" , self.zdict[metric],  "\n"
  
  
accepted_modes = [ 'alive' 'all' ]
  
  
if  len(sys.argv) == 3 and sys.argv[2]  in  accepted_modes:
     java_name = sys.argv[1]
     mode = sys.argv[2]
else :
     usage()
  
  
#Check if process is running / Get PID
jproc = Jprocess(java_name) 
pid = jproc.chk_proc()
  
  
if  pid !=  ""  and  mode ==  'all' :
    jproc.get_jstats()
   # print jproc.zdict
    jproc.compute_jstats()               
    FNULL =  open (os.devnull,  'w' )
    for  key  in  jproc.zdict:
        #print key,jproc.zdict[key]
        jproc.send_to_zabbix(key)
    FNULL.close()
    print pid
  
else :
    print 0
1
2
3
4
5
6
7
8
9
说明,跟参考文章的不同点
1. 'sudo'  改成 'sudo' , '-u' , 'tomcat'
2.注释perm段,因为jdk1.8 jstat输出没有了
3.send_to_zabbix 提示TypeError: cannot concatenate  'str'  and  'int'  objects
self.zdict[metric]换成str(self.zdict[metric])
4.[zabbix_sender,  "-c" , zabbix_conf,  "-k" , key,  "-o" , str(self.zdict[metric])], stdout=FNULL,stderr=FNULL, shell=False)
这行改为
[zabbix_sender,  "-c" , zabbix_conf,  "-k" , key,  "-o" , str(self.zdict[metric]),  "-z" , serverip,  "-s" , ip]
原因在于zabbix_sender 发送数据的需要指定-s,具体参考上面ttlsa的链接

5.重启zabbix_agentd

6.模板的话

http://john88wang.blog.51cto.com/2165294/1708302 里面有,讲解也很详细。

7.zabbix_get和zabbix_send 测试

zabbix_get

/usr/local/zabbix/bin/zabbix_get -s $ip -p 10050 -k java.discovery_status[你的应用名字,all]

zabbix_send

/usr/local/zabbix/bin/zabbix_sender -c /usr/local/zabbix/etc/zabbix_agentd.conf -k "java.discovery_status[你的应用名字,GCT_avg]" -o '0.021' -s xx -z serverip

xx表示为zabbix_agentd里面的hostname,这里要注意一下

如果你这个hostname与web界面不一样,那么/var/log/zabbix_agentd.log(log是排错的重要手段)会报错,no active checks on server [xx:10051]: host [xx] not found

最好改成一致

hostname=你的客户端ip,我的web界面都是ip(太low了,需要改成ip+服务,看起来方便)

8.模板我改成了30分钟,正常30分钟出图

wKioL1g09smD6xLWAAGy6q_hH4Y467.png-wh_50

首先看最新数据,有没有应用集,有那么你就成功了。

坑太多了,如果有问题,提出一起谈论下。

后期,这个脚本还是要修改的,增加第三步jstat输出的四个变量

MC:方法区大小

MU:方法区使用大小

CCSC:压缩类空间大小

CCSU:压缩类空间使用大小


最后提醒,一定要确认zabbix是否能获取数据

sudo -u zabbix /usr/bin/python /usr/local/zabbix/bin/jstat_status.py xx_tomcat all

因为碰到有几台机器不能出图,所以做一下最后的check

1.cat /etc/hosts

ip hostname

2.cat /etc/sudoers

zabbix ALL=(tomcat) NOPASSWD:/bin/netstat,/usr/bin/omreport,/usr/java/jdk/bin/jstat,/usr/bin/python

tomcat ALL=(ALL) NOPASSWD:/bin/kill,/bin/chown,/usr/java/jdk/bin/jstat,/usr/bin/python,/bin/netstat,/usr/bin/omreport

3.sudo -u zabbix /usr/bin/python /usr/local/zabbix/bin/jstat_status.py xx_tomcat all

没有数据,很有可能是zabbix权限问题。排查的第一点。终于完成了。

最后更新 2017.1.4

  1. 步骤一定要按评论里面一步步操作

  2. sudo -u zabbix /usr/local/zabbix/bin/zabbix_sender -c /usr/local/zabbix/etc/zabbix_agentd.conf -k "java.discovery_status[xx_tomcat,GCT_avg]" -o '0.022' -s xx -z xx

当你尝试zabbix_sender的时候,我在线上,有几台没有出图。

原因在于,xx_tomcat是可以的,但是如果是这样xx-xx-xx_tomcat是会fail的

如果你用strace跟踪zabbix_sender

wKiom1hss0mQ8FYjAACKtRb0X_M198.png-wh_50





最终只有2和0的区别,其他没显示,strace跟踪不行。

3.如果要调试,请参考

gdb 调试zabbix_server解决zabbix_sender不成功的问题

https://www.tiege.me/?p=188

此文章总结了根本原因

1、类型一定要是zabbix_trap类型;

2、allowed ip要填写zabbix_sender的ip地址,如果有多个,使用,分割;

3、zabbix_sender命令中的-s参数hostname要和server的web界面上一致;


终于完了。




本文转自 liqius 51CTO博客,原文链接:http://blog.51cto.com/szgb17/1812342,如需转载请自行联系原作者

相关文章
|
1月前
|
运维 监控 Java
使用jps命令查看Java进程
`jps`是Java开发者和系统管理员的得力助手,它简化了Java进程监控的过程,使得快速检查应用运行状态变得轻而易举。通过合理利用其提供的参数,可以高效地进行故障排查、性能监控及日常管理任务,确保Java应用稳定运行。
64 2
|
26天前
|
监控 数据可视化 Java
如何使用JDK自带的监控工具JConsole来监控线程池的内存使用情况?
如何使用JDK自带的监控工具JConsole来监控线程池的内存使用情况?
|
2月前
|
监控
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
|
2月前
|
监控 Ubuntu API
Python脚本监控Ubuntu系统进程内存的实现方式
通过这种方法,我们可以很容易地监控Ubuntu系统中进程的内存使用情况,对于性能分析和资源管理具有很大的帮助。这只是 `psutil`库功能的冰山一角,`psutil`还能够提供更多关于系统和进程的详细信息,强烈推荐进一步探索这个强大的库。
43 1
|
2月前
|
监控 数据可视化 Java
使用JDK自带的监控工具JConsole来监控线程池的内存使用情况
使用JDK自带的监控工具JConsole来监控线程池的内存使用情况
|
3月前
|
数据采集 监控 API
如何监控一个程序的运行情况,然后视情况将进程杀死并重启
这篇文章介绍了如何使用Python的psutil和subprocess库监控程序运行情况,并在程序异常时自动重启,包括多进程通信和使用日志文件进行断点重续的方法。
|
3月前
|
网络协议
Mac根据端口查询进程id的命令
这篇文章介绍了在Mac操作系统上如何使用两种命令来查询监听特定端口的进程ID。第一种方法是使用`netstat -anp tcp -v | grep 端口号`,例如`netstat -anp tcp -v | grep 80`,这将列出所有使用端口80的TCP连接及其相关信息。第二种方法是使用`lsof -P -n -i:端口号`,例如`lsof -P -n -i:8080`,这将显示使用指定端口的进程列表,包括进程ID、用户、文件描述符等信息。文章通过示例展示了如何使用这些命令,并提供了输出结果的截图。
307 2
|
3月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
4月前
|
Java 运维
开发与运维命令问题之使用jstack命令查看Java进程的线程栈如何解决
开发与运维命令问题之使用jstack命令查看Java进程的线程栈如何解决
66 2

推荐镜像

更多