Dump logs to the console.

def logs(stage, period, tail, config_file):
    """Dump logs to the console."""
    config = _load_config(config_file)
    if stage is None:
        stage = config['devstage']

    cfn = boto3.client('cloudformation')
    try:
        stack = cfn.describe_stacks(StackName=config['name'])['Stacks'][0]
    except botocore.exceptions.ClientError:
        print('{} has not been deployed yet.'.format(config['name']))
        return
    function = _get_from_stack(stack, 'Output', 'FunctionArn').split(':')[-1]
    version = _get_from_stack(stack, 'Parameter', stage.title() + 'Version')
    api_id = _get_from_stack(stack, 'Output', 'ApiId')

    try:
        start = float(period[:-1])
    except ValueError:
        raise ValueError('Invalid period ' + period)
    if period[-1] == 's':
        start = time.time() - start
    elif period[-1] == 'm':
        start = time.time() - start * 60
    elif period[-1] == 'h':
        start = time.time() - start * 60 * 60
    elif period[-1] == 'd':
        start = time.time() - start * 60 * 60 * 24
    elif period[-1] == 'w':
        start = time.time() - start * 60 * 60 * 24 * 7
    else:
        raise ValueError('Invalid period ' + period)
    start = int(start * 1000)

    logs = boto3.client('logs')
    lambda_log_group = '/aws/lambda/' + function
    log_groups = [lambda_log_group]
    if api_id:
        log_groups.append('API-Gateway-Execution-Logs_' + api_id + '/' + stage)
    log_version = '[' + version + ']'
    log_start = {g: start for g in log_groups}
    while True:
        kwargs = {}
        events = []
        for log_group in log_groups:
            while True:
                try:
                    l = logs.filter_log_events(logGroupName=log_group,
                                               startTime=log_start[log_group],
                                               interleaved=True, **kwargs)
                except botocore.exceptions.ClientError:
                    # the log group does not exist yet
                    l = {'events': []}
                if log_group == lambda_log_group:
                    events += [ev for ev in l['events']
                               if log_version in ev['logStreamName']]
                else:
                    events += l['events']
                if len(l['events']):
                    log_start[log_group] = l['events'][-1]['timestamp'] + 1
                if 'nextToken' not in l:
                    break
                kwargs['nextToken'] = l['nextToken']
        events.sort(key=lambda ev: ev['timestamp'])
        for ev in events:
            tm = datetime.fromtimestamp(ev['timestamp'] / 1000)
            print(tm.strftime('%b %d %X ') + ev['message'].strip())
        if not tail:
            break
        time.sleep(5)