Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

#!/usr/bin/env python 

 

""" 

@file ion/util/procutils.py 

@author Michael Meisinger 

@brief  utility helper functions for processes in capability containers 

""" 

 

import logging 

 

from ion.util import os_process 

import sys 

import traceback 

import re 

import time 

import uuid 

 

import pprint 

import StringIO 

 

import os 

from twisted.internet import defer, reactor 

 

import ion.util.ionlog 

log = ion.util.ionlog.getLogger(__name__) 

 

from ion.core import ioninit 

from ion.core.id import Id 

 

def log_attributes(obj): 

    """ 

    Print an object's attributes 

    """ 

    lstr = "" 

    for attr, value in obj.__dict__.iteritems(): 

        lstr = lstr + str(attr) + ": " +str(value) + ", " 

    log.info(lstr) 

 

def log_message(msg): 

    """ 

    Log an inbound message with all headers unless quiet attribute set. 

    @param msg  carrot BaseMessage instance 

    """ 

 

    if log.getEffectiveLevel() > logging.DEBUG: 

        # This method is extremely expensive to call since it constructs the message before letting 

        # log.debug decide to throw away the string we just spend 3 seconds constructing. 

        return 

 

    body = msg.payload 

    lstr = "" 

    procname = str(body.get('receiver',None)) 

    lstr += "===IN Message=== %s(%s) -> %s: %s:%s:%s===" % (body.get('sender-name', None), 

                    body.get('sender', None), procname, body.get('protocol', None), 

                    body.get('performative', None), body.get('op', None)) 

    if body.get('quiet', False): 

        lstr += " (Q)" 

    else: 

        amqpm = str(msg._amqp_message) 

        # Cut out the redundant or encrypted AMQP body to make log shorter 

        amqpm = re.sub("body='(\\\\'|[^'])*'","*BODY*", amqpm) 

        lstr += '\n---AMQP--- ' + amqpm + "; " 

        for attr in sorted(msg.__dict__.keys()): 

            value = msg.__dict__.get(attr) 

            if attr == '_amqp_message' or attr == 'body' or \ 

                    attr == '_decoded_cache' or attr == 'backend': 

                pass 

            else: 

                lstr += "%s=%r, " % (attr, value) 

        lstr += "\n---ION HEADERS--- " 

        mbody = dict(body) 

        content = mbody.pop('content') 

        for attr in sorted(mbody.keys()): 

            value = mbody.get(attr) 

            lstr += "%s=%r, " % (attr, value) 

        lstr += "\n---CONTENT---\n" 

        if type(content) is dict: 

            for attr in sorted(content.keys()): 

                value = content.get(attr) 

                lstr += "%s=%r, " % (attr, value) 

        else: 

            lstr += repr(content) 

        lstr += "\n=============" 

    log.debug(lstr) 

 

id_seqs = {} 

def create_unique_id(ns): 

    """Creates a unique id for the given name space based on sequence counters. 

    """ 

    if ns is None: 

        ns = ':' 

    nss = str(ns) 

    if nss in id_seqs: nsc = int(id_seqs[nss]) +1 

    else: nsc = 1 

    id_seqs[nss] = nsc 

    return nss + str(nsc) 

 

def create_guid(): 

    """ 

    @retval Return global unique id string 

    """ 

    # I find the guids more readable if they are UPPERCASE 

    return str(uuid.uuid4()).upper() 

 

def get_process_id(some_id): 

    """ 

    @brief Always returns an Id with qualified process id 

    @param some_id any form of id, short or long, Id or str 

    @retval Id with full process id 

    """ 

    if some_id is None: 

        return None 

    parts = str(some_id).rpartition('.') 

    if parts[1] != '': 

        procId = Id(parts[2],parts[0]) 

    else: 

        procId = Id(some_id) 

    return procId 

 

def get_scoped_name(name, scope): 

    """ 

    Returns a name that is scoped. 

    - scope='local': name prefixed by container id. 

    - scope='system': name prefixed by system name. 

    - scope='global': name unchanged. 

    @param name name to be scoped 

    @param scope  one of "local", "system" or "global" 

    """ 

    scoped_name = name 

    if scope == 'local': 

        scoped_name =  str(ioninit.container_instance.id) + "." + name 

    elif scope == 'system': 

        scoped_name =  ioninit.sys_name + "." + name 

    elif scope == 'global': 

        pass 

    else: 

        raise RuntimeError("Unknown scope: %s" % scope) 

    return  scoped_name 

 

def get_class(qualclassname, mod=None): 

    """Imports module and class and returns class object. 

 

    @param qualclassname  fully qualified classname, such as 

        ion.data.dataobject.DataObject if module not given, otherwise class name 

    @param mod instance of module 

    @retval instance of 'type', i.e. a class object 

    """ 

    if mod: 

        clsname = qualclassname 

    else: 

        # Cut the name apart into package, module and class names 

        qualmodname = qualclassname.rpartition('.')[0] 

        modname = qualmodname.rpartition('.')[2] 

        clsname = qualclassname.rpartition('.')[2] 

        mod = get_module(qualmodname) 

 

    cls = getattr(mod, clsname) 

    #log.debug('Class: '+str(cls)) 

    return cls 

 

def get_module(qualmodname): 

    """Imports module and returns module object 

    @param fully qualified modulename, such as ion.data.dataobject 

    @retval instance of types.ModuleType or error 

    """ 

    package = qualmodname.rpartition('.')[0] 

    modname = qualmodname.rpartition('.')[2] 

    #log.info('get_module: from '+package+' import '+modname) 

    mod = __import__(qualmodname, globals(), locals(), [modname]) 

    #log.debug('Module: '+str(mod)) 

    return mod 

 

def asleep(secs): 

    """ 

    @brief Do a reactor-safe sleep call. Call with yield to block until done. 

    @param secs Time, in seconds 

    @retval Deferred whose callback will fire after time has expired 

    """ 

 

    #d = defer.Deferred() 

    #reactor.callLater(secs, d.callback, None) 

 

    # This is a better implementation - the delayed call can now be cancelled by the deferred which prevents dirty reactor! 

    def deferLaterCancel(deferred): 

       delayedCall.cancel() 

    d = defer.Deferred(deferLaterCancel) 

    delayedCall = reactor.callLater(secs, d.callback, None) 

    return d 

 

def currenttime(): 

    """ 

    @retval current UTC time as float with seconds in epoch and fraction 

    """ 

    return time.time() 

 

def currenttime_ms(): 

    """ 

    @retval current UTC time as int with milliseconds in epoch 

    """ 

    return int(currenttime() * 1000) 

 

 

def isnan(x): 

    """ 

    Python 2.5 does not support isnan in the math module. 

    Using string conversion is the safest method - comparison with self does not always work... 

    http://stackoverflow.com/questions/944700/how-to-check-for-nan-in-python 

    """ 

 

    return str(float(x)).lower() == 'nan' 

 

 

 

 

def get_ion_path(filename): 

    """ 

    @brief running twisted and trial can do nasty things to the path and the current working directory. This method 

    solves that problem for a relative path to a file. It will normalize the results so that the path is accessible 

    in both trial test cases where the CWD is ioncore-python/bin and in a twistd -n cc case where the CWD is ioncore-python. 

    @param filename is a path to a file. If some funny business with the way ion is run mucks up the relative path, 

    this method tries to correct it. 

    @retval an absolute path to the first file found that fits the pattern specified in filename 

    """ 

 

    # Deal with path problems - maybe too smart, there is room to get the wrong file this way!!! 

    if not os.path.exists(filename): 

 

        cwd = os.path.abspath('.') 

 

        myfile = filename 

 

        # Strip off any leading relative path stuff 

        if myfile[0:3] == '../': 

            while myfile[0:3] == '../': 

                myfile = myfile[3:] 

 

 

        # Now create an absolute path to the file - deal with the fact that the CWD may be 

        # ioncore-python or ioncore-python/bin 

        while cwd != '/': 

 

            head, tail = os.path.split(cwd) 

 

            test_name = os.path.join(head, myfile) 

 

            if os.path.exists(test_name): 

                filename = test_name 

                break 

            else: 

 

                cwd = head 

        else: 

            raise IOError('Could not find the data file you specified: "%s"' % filename) 

 

 

    log.info('Found file on path: "%s"' % filename) 

 

    return filename 

 

 

 

 

def get_last_or_default(alist, default=None): 

 

    try: 

        res = alist[-1] 

    except IndexError, ie: 

        log.debug('get_last_or_default: using default!') 

        res=default 

    return res 

 

 

def pprint_to_string(obj): 

 

    fstream = StringIO.StringIO() 

 

    pprint.pprint(obj, stream=fstream) 

 

    result = fstream.getvalue() 

    fstream.close() 

    return result 

 

 

def capture_function_stdout(func, *args, **kwargs): 

 

    fstream = StringIO.StringIO() 

    stdout = sys.stdout 

    sys.stdout = fstream 

 

    try: 

        func(*args,**kwargs) 

        result = fstream.getvalue() 

 

    finally: 

        fstream.close() 

        sys.stdout=stdout 

 

    return result 

 

@defer.inlineCallbacks 

def print_memory_usage(): 

    """ 

    @brief Prints the memory usage of the container processes. 

 

    Performs a ps command as a subprocess and retrieves the RSS and VSIZE of the 

    twistd container processes. 

 

    @TODO convert to use the twisted subprocess! 

    """ 

    cc_pids = os.getenv("ION_TEST_CASE_PIDS","") 

    pids = cc_pids + str(os.getpid()) if cc_pids == "" else ",".join((cc_pids,str(os.getpid()))) 

 

 

    pid_arg = "-p" + pids 

    #CentOS doesn't handle the spaces between options and arguments 

    ps_args = ["-oargs,command,rss,vsize",  pid_arg] 

    p = os_process.OSProcess(binary="/bin/ps", spawnargs=ps_args) 

    result = yield p.spawn() 

    std_output = result.get("outlines", None) 

 

    if std_output is None or std_output == []: 

        defer.returnValue( "print_memory_usage Failed!") 

 

    header = "=================================================================================" 

    ret = "\n%s\nOS Process Status Memory Use: \n%s%s" % (header,std_output[0],header) 

    defer.returnValue(ret)