1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__ = """RRDUtil
15
16 Wrapper routines around the rrdtool library.
17 """
18
19 import logging
20 log = logging.getLogger("zen.RRDUtil")
21
23 """
24 Sanity check on the min, max values
25
26 @param x: RRD min or max value
27 @type x: number
28 @return: Either the number or 'U' (for undefined)
29 @rtype: number or string
30 """
31 if x is None or x == '' or x == -1 or x == '-1':
32 return 'U'
33 return x
34
35
37 """
38 Convert any value that is passed in to a string that is acceptable to use
39 for RRDtool's start and end parameters. Raises ValueError if this is not
40 possible.
41
42 See the AT-STYLE TIME SPECIFICATION and TIME REFERENCE SPECIFICATION
43 sections of the following document.
44
45 http://oss.oetiker.ch/rrdtool/doc/rrdfetch.en.html
46
47 Note: Currently this method is only fixing floats by turning them into
48 strings with no decimal places.
49 """
50
51 try:
52 result = int(val)
53 return str(result)
54 except ValueError:
55 pass
56
57 return str(val)
58
59
61 """
62 Wrapper class around rrdtool
63 """
64
65 - def __init__(self, defaultRrdCreateCommand, defaultCycleTime):
66 """
67 Initializer
68
69 The RRD creation command is only used if the RRD file doesn't
70 exist and no rrdCommand was specified with the save() method.
71
72 @param defaultRrdCreateCommand: RRD creation command
73 @type defaultRrdCreateCommand: string
74 @param defaultCycleTime: expected time to periodically collect data
75 @type defaultCycleTime: integer
76 """
77 self.defaultRrdCreateCommand = defaultRrdCreateCommand
78 self.defaultCycleTime = defaultCycleTime
79 self.dataPoints = 0
80 self.cycleDataPoints = 0
81
82
84 """
85 Report on the number of data points collected in a cycle,
86 and reset the counter for a new cycle.
87
88 @return: number of data points collected during the cycle
89 @rtype: number
90 """
91 result = self.cycleDataPoints
92 self.cycleDataPoints = 0
93 return result
94
95
108
109
110 - def save(self, path, value, rrdType, rrdCommand=None, cycleTime=None,
111 min='U', max='U'):
112 """
113 Save the value provided in the command to the RRD file specified in path.
114
115 If the RRD file does not exist, use the rrdType, rrdCommand, min and
116 max parameters to create the file.
117
118 @param path: name for a datapoint in a path (eg device/component/datasource_datapoint)
119 @type path: string
120 @param value: value to store into the RRD file
121 @type value: number
122 @param rrdType: RRD data type (eg ABSOLUTE, DERIVE, COUNTER)
123 @type rrdType: string
124 @param rrdCommand: RRD file creation command
125 @type rrdCommand: string
126 @param cycleTime: length of a cycle
127 @type cycleTime: number
128 @param min: minimum value acceptable for this metric
129 @type min: number
130 @param max: maximum value acceptable for this metric
131 @type max: number
132 @return: the parameter value converted to a number
133 @rtype: number or None
134 """
135 import rrdtool, os
136
137 if value is None: return None
138
139 self.dataPoints += 1
140 self.cycleDataPoints += 1
141
142 if cycleTime is None:
143 cycleTime = self.defaultCycleTime
144
145 filename = self.performancePath(path) + '.rrd'
146 if not rrdCommand:
147 rrdCommand = self.defaultRrdCreateCommand
148 if not os.path.exists(filename):
149 log.debug("Creating new RRD file %s", filename)
150 dirname = os.path.dirname(filename)
151 if not os.path.exists(dirname):
152 os.makedirs(dirname, 0750)
153
154 min, max = map(_checkUndefined, (min, max))
155 dataSource = 'DS:%s:%s:%d:%s:%s' % ('ds0', rrdType,
156 3*cycleTime, min, max)
157 rrdtool.create(filename,
158 "--step", str(cycleTime),
159 str(dataSource), *rrdCommand.split())
160
161 if rrdType in ('COUNTER', 'DERIVE'):
162 try:
163 value = long(value)
164 except (TypeError, ValueError):
165 return None
166 else:
167 value = float(value)
168 try:
169 rrdtool.update(filename, 'N:%s' % value)
170 log.debug('%s: %r', filename, value)
171 except rrdtool.error, err:
172
173 log.error('rrdtool reported error %s %s', err, path)
174
175 if rrdType in ('COUNTER', 'DERIVE'):
176 startStop, names, values = \
177 rrdtool.fetch(filename, 'AVERAGE',
178 '-s', 'now-%d' % (cycleTime*2),
179 '-e', 'now')
180 values = [ v[0] for v in values if v[0] is not None ]
181 if values: value = values[-1]
182 else: value = None
183 return value
184