Source code for COMPS.utils.get_output_tail
import sys
import logging
from COMPS import Client
from COMPS.Data import QueryCriteria, AssetManager
logger = logging.getLogger(__name__)
##########################
utility_metadata = {
'aliases': [ 'tail' ],
'help': 'Get the output tail from a simulation or workItem',
'description': 'This utility displays the last chunk of output for a simulation or workItem. By default, ' +
'it will show the last 1024 bytes of both stdout.txt and stderr.txt.',
'epilog': '''examples:
%(prog)s WorkItem 11111111-2222-3333-4444-000000000000
%(prog)s Simulation latest status.txt -b 200
'''
}
[docs]def fill_parser(p):
p.add_argument('entity_type', choices=_valid_entity_types, type=lambda arg: {x.lower(): x for x in _valid_entity_types}[arg.lower()],
help='Type of the entity to retrieve status for (must be one of Simulation or WorkItem)')
p.add_argument('entity_id', help='Id of the entity to retrieve status for; can pass \'latest\' to get the latest of that entity type')
p.add_argument('filename', default='stdout.txt,stderr.txt', nargs='?', help='Name(s) of the file(s) to retrieve the end of. This can be a comma-delimited list, or an actual (python) list if calling from code (default is stdout.txt and stderr.txt)')
p.add_argument('--bytes', '-b', type=int, default=1024, help='The number of bytes from the end of the output file to display (default=1024)')
##########################
_valid_entity_types = ['Simulation', 'WorkItem']
[docs]def get_tail(entity_type, entity_id, files_to_get, bytes=1024):
if not isinstance(files_to_get, list):
files_to_get = [ files_to_get ]
entity_cls = getattr(sys.modules['COMPS.Data'], entity_type)
entity_state_cls = getattr(sys.modules[f'COMPS.Data.{entity_type}'], f'{entity_type}State')
if entity_id == 'latest':
entity = entity_cls.get(query_criteria=QueryCriteria().select(['id','state'])
.where(f'owner={Client.auth_manager().username}')
.orderby('date_created desc')
.count(1))[0]
else:
entity = entity_cls.get(entity_id, QueryCriteria().select(['id','state']))
logger.info(f'{entity_type} {entity.id}')
if entity.state.value < entity_state_cls.Running.value:
print('Can\'t retrieve output tail; entity has not started running yet!')
return
ofmd = entity.retrieve_output_file_info(files_to_get)
for md in ofmd:
logger.info('')
logger.info(f'{"/".join([md.path_from_root, md.friendly_name])} :')
retrieved_bytes = min(md.length, bytes + 3)
barr_out = AssetManager.retrieve_partial_output_file_from_info(md, -1 * retrieved_bytes)
decoded = False
decode_bytes = retrieved_bytes
while not decoded and decode_bytes >= max(0, retrieved_bytes - 3):
try:
outstr = barr_out[-1*decode_bytes:].decode()
decoded = True
except UnicodeDecodeError:
logger.debug('UnicodeDecodeError! Probably grabbed a chunk in the middle of a multibyte character... trying again')
decode_bytes = decode_bytes - 1
if not decoded:
logger.error('Unable to decode output stream!')
continue
if '\r\n' in outstr:
lines = outstr.split('\r\n')
else:
outstr = outstr.replace('\r','\n')
lines = outstr.split('\n')
for line in lines:
logger.info(' >> {0}'.format(line))
return
[docs]def main(args):
Client.login(args.comps_server)
get_tail(args.entity_type, args.entity_id, args.filename.split(','), args.bytes)