| Trees | Indices | Help |
|---|
|
|
1 # -*- Mode: Python -*-
2 # vi:si:et:sw=4:sts=4:ts=4
3 #
4 # Flumotion - a streaming media server
5 # Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com).
6 # All rights reserved.
7
8 # This file may be distributed and/or modified under the terms of
9 # the GNU General Public License version 2 as published by
10 # the Free Software Foundation.
11 # This file is distributed without any warranty; without even the implied
12 # warranty of merchantability or fitness for a particular purpose.
13 # See "LICENSE.GPL" in the source distribution for more information.
14
15 # Licensees having purchased or holding a valid Flumotion Advanced
16 # Streaming Server license may use this file in accordance with the
17 # Flumotion Advanced Streaming Server Commercial License Agreement.
18 # See "LICENSE.Flumotion" in the source distribution for more information.
19
20 # Headers in this file shall remain intact.
21
22
23 import os
24 import random
25 import rrdtool
26 import datetime
27 import time
28
29 from dateutil import rrule
30
31 from flumotion.admin import multi
32 from flumotion.common import log, common
33 from flumotion.component.base import scheduler
34
35 # register the unjellyable
36 from flumotion.common import componentui
37
38
39 """RRD resource poller daemon for Flumotion.
40
41 Makes periodic observations on components' UI states, recording them to
42 RRD files. One can then extract graphs using rrdtool graph. For example,
43 to show a stream bandwidth graph for the last 30 minutes with the
44 example configuration file, in the source tree as
45 conf/rrdmon/default.xml, the following command makes a graph:
46
47 rrdtool graph --end now --start end-30min --width 400 out.png \
48 DEF:ds0=/tmp/stream-bitrate.rrd:http-streamer:AVERAGE \
49 AREA:ds0#0000FF:"Stream bandwidth (bytes/sec)"
50
51 It would be possible to expose these graphs via HTTP, but I don't know
52 how useful this might be.
53
54 See L{flumotion.admin.rrdmon.config} for information on how to configure
55 the RRD resource poller.
56 """
57
58
60 return source['rrd-file']
61
63 return source['name']
64
66 return source['sample-frequency']
67
69 def makeDS():
70 if source['is-gauge']:
71 return 'DS:%s:GAUGE:%d:U:U' % (source['name'],
72 2*source['sample-frequency'])
73 else:
74 return 'DS:%s:DERIVE:%d:0:U' % (source['name'],
75 2*source['sample-frequency'])
76 return source['rrd-ds-spec'] or makeDS()
77
81 return [archiveGetRRA(archive) for archive in source['archives']]
82
84 return source['manager']
85
87 return source['component-id']
88
90 return source['ui-state-key']
91
92
94 logName = 'rrdmon'
95
97 self.debug('started rrd monitor')
98 self.multi = multi.MultiAdminModel()
99 self.scheduler = scheduler.Scheduler()
100 self.ensureRRDFiles(sources)
101 self.connectToManagers(sources)
102 self.startScheduler(sources)
103
105 for source in sources:
106 rrdfile = sourceGetFileName(source)
107 if not os.path.exists(rrdfile):
108 try:
109 self.info('Creating RRD file %s', rrdfile)
110 rrdtool.create(rrdfile,
111 "-s", str(sourceGetSampleFrequency(source)),
112 sourceGetDS(source),
113 *sourceGetRRAList(source))
114 except rrdtool.error, e:
115 self.warning('Could not create RRD file %s',
116 rrdfile)
117 self.debug('Failure reason: %s',
118 log.getExceptionMessage(e))
119
121 for source in sources:
122 connectionInfo = sourceGetConnectionInfo(source)
123 self.multi.addManager(connectionInfo, tenacious=True)
124
126 r = random.Random()
127 now = scheduler.now()
128
129 def eventStarted(event):
130 self.pollData(*event.content)
131 def eventStopped(event):
132 pass
133
134 self.scheduler.subscribe(eventStarted, eventStopped)
135
136 for source in sources:
137 freq = sourceGetSampleFrequency(source)
138
139 # randomly offset the polling
140 offset = datetime.timedelta(seconds=r.randint(0,freq))
141
142 data = (str(sourceGetConnectionInfo(source)),
143 sourceGetComponentId(source),
144 sourceGetUIStateKey(source),
145 sourceGetName(source),
146 sourceGetFileName(source))
147
148 self.scheduler.addEvent(now+offset,
149 now+offset+datetime.timedelta(seconds=1),
150 data,
151 datetime.timedelta(seconds=freq))
152
157
158 if managerId in self.multi.admins:
159 admin = self.multi.admins[managerId]
160
161 flowName, componentName = common.parseComponentId(componentId)
162
163 flows = stateListToDict(admin.planet.get('flows'))
164 if flowName not in flows:
165 self.warning('not polling %s%s:%s: no such flow %s',
166 managerId, componentId, uiStateKey,
167 flowName)
168 return
169
170 components = stateListToDict(flows[flowName].get('components'))
171 if componentName not in components:
172 self.warning('not polling %s%s:%s: no such component %s',
173 managerId, componentId, uiStateKey,
174 componentId)
175 return
176
177 state = components[componentName]
178
179 def gotUIState(uiState):
180 if not uiState.hasKey(uiStateKey):
181 self.warning('while polling %s%s:%s: uiState has no '
182 'key %s', managerId, componentId,
183 uiStateKey, uiStateKey)
184 else:
185 try:
186 value = '%d:%s' % (int(time.time()),
187 uiState.get(uiStateKey))
188 self.log("polled %s%s:%s, updating ds %s = %s",
189 managerId, componentId, uiStateKey,
190 dsName, value)
191 rrdtool.update(rrdFile, "-t", dsName, value)
192 except rrdtool.error, e:
193 self.warning('error updating rrd file %s for '
194 '%s%s:%s', rrdFile, managerId,
195 componentId, uiStateKey)
196 self.debug('error reason: %s',
197 log.getExceptionMessage(e))
198
199 def errback(failure):
200 self.warning('not polling %s%s:%s: failed to get ui '
201 'state')
202 self.debug('reason: %s', log.getFailureMessage(failure))
203
204 d = admin.componentCallRemote(state, 'getUIState')
205 d.addCallbacks(gotUIState, errback)
206
| Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Thu Aug 7 15:45:52 2008 | http://epydoc.sourceforge.net |