Projet

Général

Profil

Révision 6f28e159

ID6f28e159c69004a95b5c4b1bb96e3ec3e5dbf451
Parent 2f01b83c
Enfant 0ed36d00

Ajouté par J.T. Sage il y a presque 14 ans

true autoconf, a few extra configuration options (extensible use)

Voir les différences:

plugins/other/nsd3
1 1
#!/usr/bin/python
2 2
#%# family=auto
3
#%# capabilities=suggest autoconf
3
#%# capabilities=autoconf
4 4

  
5 5

  
6 6
"""
7
Munin plugin to monitor NSD3 statistics
8
J.T.Sage <jtsage@gmail.com>, 2010/06/10
9

  
10
To use:
11
ln -s path_to_this_script /etc/munin/plugins/nsd
12

  
13
Configuration
14
[nsd]
15
	user nsd
16
	env.statsfile /var/log/nsd.log
17
	env.pidfile /var/run/nsd3/nsd.pid
18

  
19
Notes:
20
  Note that the plugin has a built in half second pause for the lastest NSD3 
21
  statistics to write.  This is done via a SIGUSR1 signal to the process.  
22
  If your system is sufficiently loaded to the point that half a second
23
  is not enough time for the file to be written to, please update that 
24
  number in the source.  It should be more than long enough for most
25
  users.
7
=head1 NAME
8

  
9
	nsd - Munin plugin to monitor the number of queries a running process
10
	      of nsd3 has recievied.
11

  
12
=head1 APPLICABLE SYSTEMS
13

  
14
	Linux or *nix system with a logging installtion of NSD v3 installed.
15
	  (http://nlnetlabs.nl/projects/nsd/)
16

  
17
=head1 CONFIGURATION
18
	
19
	The plugin needs access to the nsd logfile and the nsd pid file to
20
	force the running nsd process to write the current statistics.
21

  
22
	Tip: To see if it's already set up correctly, just run this plugin 
23
	with the paramater "autoconf".  If you get a "yes", everything should
24
	work like a charm already.
25

  
26
	This configuration section shows the defaults of the plugin:
27

  
28
	The stats line is a set of space-seperated values that you wish to 
29
	retrieve from NSD.  The format is VALUE=Caption.  For spaces in a
30
	caption value, replace them with an underscore (_).
31

  
32
	[nsd]
33
	        env.statsfile /var/log/nsd.log
34
        	env.pidfile /var/run/nsd3/nsd.pid
35
		env.stats "A=A AAAA=AAAA MX=MX PTR=PTR TYPE252=AXFR SNXD=NXDOMAIN RQ=Total_Successful"
36

  
37
	If you need to set a user for the logfile to be readable, and most 
38
	importantly, the process to recieve the signal, you may specify it.
39
	For example:
40

  
41
	[nsd]
42
		user nsd
43

  
44
=head1 INTERPRETATION
45
	
46
	The plugin shows the number of queries that nsd has recieved, 
47
	averaged over a period to gain the number of queries per second.
48
	For most servers, these values will be very low.  In the event
49
	of a misconfiguration, the plugin will return undefined values.
50

  
51
=head1 MAGIC MARKERS
52
	
53
	#%# family=auto
54
	#%# capabilities=autoconf
55

  
56
=head1 VERSION
57

  
58
	v1.0.1
59
	
60
=head1 AUTHOR
61

  
62
	J.T.Sage <jtsage@gmail.com>
63
	
64
=head1 LICENSE
65
	
66
	GPLv2
67
	
68
=cut
26 69
"""
27 70

  
28 71
import os
......
30 73
import subprocess
31 74
import time
32 75
import re
76
import signal
33 77

  
34 78
STATS_FILE = os.environ.get('statsfile', '/var/log/nsd.log')
35 79
PID_FILE = os.environ.get('pidfile', '/var/run/nsd3/nsd.pid')
80
STATS_STRING = os.environ.get('stats', "A=A AAAA=AAAA MX=MX PTR=PTR TYPE252=AXFR SNXD=NXDOMAIN RQ=Total_Succesful")
81

  
82
BOTH_LISTS = STATS_STRING.split()
36 83

  
37 84
def print_config():
38
    """Generates and prints a munin config for a given chart."""
39

  
40
    print "graph_title NSD3 Queries"
41
    print "graph_vlabel qps"
42
    print "graph_category network"
43
    print "graph_info Queries per second"
44
    print "a.label A"
45
    print "a.type DERIVE"
46
    print "a.min 0"
47
    print "aaaa.label AAAA"
48
    print "aaaa.type DERIVE"
49
    print "aaaa.min 0"
50
    print "ptr.label PTR"
51
    print "ptr.type DERIVE"
52
    print "ptr.min 0"
53
    print "mx.label MX"
54
    print "mx.type DERIVE"
55
    print "mx.min 0"
56
    print "type252.label AXFR"
57
    print "type252.type DERIVE"
58
    print "type252.min 0"
59
    print "snxd.label NXDOMAIN"
60
    print "snxd.type DERIVE"
61
    print "snxd.min 0"
62
    print "rq.label Total Successful"
63
    print "rq.type DERIVE"
64
    print "rq.min 0"
65
  
85
	"""Generates and prints a munin config for a given chart."""
86

  
87
	print "graph_title NSD3 Queries"
88
	print "graph_vlabel qps"
89
	print "graph_category network"
90
	print "graph_info Queries per second"
91
	for x in BOTH_LISTS:
92
		val = x.split('=')
93
		name = val[0].lower()
94
		label = val[1].replace('_', ' ')
95
		print name + '.label ' + label
96
		print name + '.type DERIVE'
97
		print name + '.min 0'
98

  
99
	sys.exit(0)
66 100

  
67 101
def print_values():
68
    """Gets NSD's latest stats."""
69
    
70
    pidf = open(PID_FILE, 'r')
71
    pidn = pidf.read()
72
    pidf.close();
73
    statscmd = ['kill', '-SIGUSR1']
74
    statscmd.append(pidn.strip())
75
    dropstats = subprocess.call(statscmd)
76

  
77
    time.sleep(.5) # Wait for the log to write.
78
    statf = open(STATS_FILE, 'r')
79
    stats = tail(statf, 10)
80

  
81
    nstats = []
82
    xstats = []
83

  
84
    for line in stats:
85
        if "XSTATS" in line:
86
            xstats.append(line.strip())
87
        if "NSTATS" in line:
88
            nstats.append(line.strip())
89

  
90
    matches = re.compile(' A=(\d+)').findall(nstats[-1])
91
    if matches == []:
92
        print "a.value 0"
93
    else:
94
        print "a.value " + matches[0]
95

  
96
    matches = re.compile(' AAAA=(\d+)').findall(nstats[-1])
97
    if matches == []:
98
        print "aaaa.value 0"
99
    else:
100
        print "aaaa.value " + matches[0]    
101

  
102
    matches = re.compile(' PTR=(\d+)').findall(nstats[-1])
103
    if matches == []:
104
        print "ptr.value 0"
105
    else:
106
        print "ptr.value " + matches[0]
107

  
108

  
109
    matches = re.compile(' MX=(\d+)').findall(nstats[-1])
110
    if matches == []:
111
        print "mx.value 0"
112
    else:
113
        print "mx.value " + matches[0]
114

  
115
    matches = re.compile(' TYPE252=(\d+)').findall(nstats[-1])
116
    if matches == []:
117
        print "type252.value 0"
118
    else:
119
        print "type252.value " + matches[0]
120

  
121
    matches = re.compile(' SNXD=(\d+) ').findall(xstats[-1])
122
    if matches == []:
123
        print "snxd.value 0"
124
    else:
125
        print "snxd.value " + matches[0]
126

  
127
    matches = re.compile(' RQ=(\d+) ').findall(xstats[-1])
128
    if matches == []:
129
        print "rq.value 0"
130
    else:
131
        print "rq.value " + matches[0]
102
	"""Gets NSD's latest stats."""
103

  
104
	bigfail = False
105
	if ( not os.access(STATS_FILE, os.R_OK) ) :
106
		bigfail = True
107
	if ( not os.access(PID_FILE, os.R_OK) ) :
108
		bigfail = True
109

  
110
	if ( not bigfail ):
111
		pidf = open(PID_FILE, 'r')
112
		pidn = pidf.read()
113
		pidf.close();
114
		try:
115
			os.kill(int(pidn.strip()), signal.SIGUSR1)
116
	        except OSError:
117
			bigfail = True
118

  
119

  
120
	time.sleep(.5) # Wait for the log to write.
121

  
122
	if ( not bigfail ):
123
		statf = open(STATS_FILE, 'r')
124
		stats = tail(statf, 10)
125

  
126
		nstats = []
127
		xstats = []
128

  
129
		for line in stats:
130
			if "XSTATS" in line:
131
				xstats.append(line.strip())
132
			if "NSTATS" in line:
133
				nstats.append(line.strip())
134

  
135
		statsline = nstats[-1] + xstats[-1]
136
	else:
137
		statsline = " "
138

  
139
	relist = []
140
	for x in BOTH_LISTS:
141
                val = x.split('=')
142
                name = val[0].lower()
143
		rxp = val[0]
144
		relist.append([name, rxp])
145

  
146
	for point in relist:
147
		matches = re.compile(' '+point[1]+'=(\d+)').findall(statsline)
148
		if bigfail:
149
			print point[0]+'.value U'
150
		elif matches == []:
151
			print point[0]+'.value 0'
152
		else:
153
			print point[0]+'.value '+matches[0]
132 154

  
133 155
def tail( f, window=20 ):
134
    f.seek( 0, 2 )
135
    bytes= f.tell()
136
    size= window
137
    block= -1
138
    while size > 0 and bytes+block*1024  > 0:
139
        f.seek( block*1024, 2 ) # from the end!
140
        data= f.read( 1024 )
141
        linesFound= data.count('\n')
142
        size -= linesFound
143
        block -= 1
144
    f.seek( block*1024, 2 )
145
    f.readline() # find a newline
146
    lastBlocks= list( f.readlines() )
147
    return lastBlocks[-window:]
156
	f.seek( 0, 2 )
157
	bytes = f.tell()
158
	size = window
159
	block = -1
160
	while size > 0 and bytes+block*1024  > 0:
161
		f.seek( block*1024, 2 ) # from the end!
162
		data = f.read( 1024 )
163
		linesFound = data.count('\n')
164
		size -= linesFound
165
		block -= 1
166
	f.seek( block*1024, 2 )
167
	f.readline() # find a newline
168
	lastBlocks = list( f.readlines() )
169
	return lastBlocks[-window:]
148 170

  
149 171
if __name__ == '__main__':
150
    if len(sys.argv) > 1:
151
        if  sys.argv[1] == 'autoconf':
152
            print 'yes'
153
            sys.exit(0)
154

  
155
    if len(sys.argv) > 1 and sys.argv[1] == 'config':
156
        print_config()
157
        sys.exit(0)
158

  
159
    print_values()
172
	if len(sys.argv) > 1:
173
		if  sys.argv[1] == 'autoconf':
174
			if ( not os.path.isfile(STATS_FILE) ) :
175
				print 'no (Log file not found)'
176
			elif ( not os.path.isfile(PID_FILE) ) :
177
				print 'no (PID file not found)'
178
			elif ( not os.access(STATS_FILE, os.R_OK) ) :
179
				print 'no (Log file exists, access denied for read)'
180
                        elif ( not os.access(PID_FILE, os.R_OK) ) :
181
                                print 'no (PID file exists, access denied for read)'
182
			else:
183
				pidf = open(PID_FILE, 'r')
184
				pidn = pidf.read()
185
				pidf.close();
186
				try:
187
					os.kill(int(pidn.strip()), signal.SIGUSR1)
188
				except OSError as (errno, strerror):
189
					print 'no (Unable to signal process :: '+strerror+')'
190
					sys.exit(0)
191
				print 'yes'
192
			sys.exit(0)
193

  
194
	if len(sys.argv) > 1 and sys.argv[1] == 'config':
195
		print_config()
196
		sys.exit(0)
197

  
198
	print_values()

Formats disponibles : Unified diff