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
36
38 """
39 Wrapper class around rrdtool
40 """
41
42 - def __init__(self, defaultRrdCreateCommand, defaultCycleTime):
43 """
44 Initializer
45
46 The RRD creation command is only used if the RRD file doesn't
47 exist and no rrdCommand was specified with the save() method.
48
49 @param defaultRrdCreateCommand: RRD creation command
50 @type defaultRrdCreateCommand: string
51 @param defaultCycleTime: expected time to periodically collect data
52 @type defaultCycleTime: integer
53 """
54 self.defaultRrdCreateCommand = defaultRrdCreateCommand
55 self.defaultCycleTime = defaultCycleTime
56 self.dataPoints = 0
57 self.cycleDataPoints = 0
58
59
61 """
62 Report on the number of data points collected in a cycle,
63 and reset the counter for a new cycle.
64
65 @return: number of data points collected during the cycle
66 @rtype: number
67 """
68 result = self.cycleDataPoints
69 self.cycleDataPoints = 0
70 return result
71
72
85
86
87 - def save(self, path, value, rrdType, rrdCommand=None, cycleTime=None,
88 min='U', max='U'):
89 """
90 Save the value provided in the command to the RRD file specified in path.
91
92 If the RRD file does not exist, use the rrdType, rrdCommand, min and
93 max parameters to create the file.
94
95 @param path: name for a datapoint in a path (eg device/component/datasource_datapoint)
96 @type path: string
97 @param value: value to store into the RRD file
98 @type value: number
99 @param rrdType: RRD data type (eg ABSOLUTE, DERIVE, COUNTER)
100 @type rrdType: string
101 @param rrdCommand: RRD file creation command
102 @type rrdCommand: string
103 @param cycleTime: length of a cycle
104 @type cycleTime: number
105 @param min: minimum value acceptable for this metric
106 @type min: number
107 @param max: maximum value acceptable for this metric
108 @type max: number
109 @return: the parameter value converted to a number
110 @rtype: number or None
111 """
112 import rrdtool, os
113
114 if value is None: return None
115
116 self.dataPoints += 1
117 self.cycleDataPoints += 1
118
119 if cycleTime is None:
120 cycleTime = self.defaultCycleTime
121
122 filename = self.performancePath(path) + '.rrd'
123 if not rrdCommand:
124 rrdCommand = self.defaultRrdCreateCommand
125 if not os.path.exists(filename):
126 log.debug("Creating new RRD file %s", filename)
127 dirname = os.path.dirname(filename)
128 if not os.path.exists(dirname):
129 os.makedirs(dirname, 0750)
130
131 min, max = map(_checkUndefined, (min, max))
132 dataSource = 'DS:%s:%s:%d:%s:%s' % ('ds0', rrdType,
133 3*cycleTime, min, max)
134 rrdtool.create(filename,
135 "--step", str(cycleTime),
136 str(dataSource), *rrdCommand.split())
137
138 if rrdType in ('COUNTER', 'DERIVE'):
139 try:
140 value = long(value)
141 except (TypeError, ValueError):
142 return None
143 else:
144 value = float(value)
145 try:
146 rrdtool.update(filename, 'N:%s' % value)
147 log.debug('%s: %r', filename, value)
148 except rrdtool.error, err:
149
150 log.error('rrdtool reported error %s %s', err, path)
151
152 if rrdType in ('COUNTER', 'DERIVE'):
153 startStop, names, values = \
154 rrdtool.fetch(filename, 'AVERAGE',
155 '-s', 'now-%d' % (cycleTime*2),
156 '-e', 'now')
157 values = [ v[0] for v in values if v[0] is not None ]
158 if values: value = values[-1]
159 else: value = None
160 return value
161