Skip to content
Snippets Groups Projects
log_file.py 5.58 KiB
'''
Created on 18/11/2015

@author: MMPE
'''
import os
from wetb.hawc2.htc_file import HTCFile
from collections import OrderedDict
import time
import math
UNKNOWN = "Unknown"
MISSING = "Log file cannot be found"
PENDING = "Simulation not started yet"
INITIALIZATION = 'Initializing simulation'
SIMULATING = "Simulating"
DONE = "Simulation succeded"

def is_file_open(filename):
    try:
        os.rename(filename, filename + "_")
        os.rename(filename + "_", filename)
        return False
    except OSError as e:
        if "The process cannot access the file because it is being used by another process" not in str(e):
            raise

        if os.path.isfile(filename + "_"):
            os.remove(filename + "_")
        return True

class LogFile(object):
    def __init__(self, log_filename, time_stop):
        self.filename = log_filename
        self.time_stop = time_stop
        self.hawc2version = "Unknown"
        self.reset()
        self.update_status()


    @staticmethod
    def from_htcfile(htcfile, modelpath):
        logfilename = htcfile.simulation.logfile[0]
        if not os.path.isabs(logfilename):
            logfilename = os.path.join(modelpath, logfilename)
        return LogFile(logfilename, htcfile.simulation.time_stop[0])

    def reset(self):
        self.position = 0
        self.lastline = ""
        self.txt = ""
        self.status = UNKNOWN
        self.pct = 0
        self.errors = []
        self.info = []
        self.start_time = None
        self.current_time = 0
        self.remaining_time = None

    def __str__(self):
        return self.txt
    def clear(self):
        os.makedirs(os.path.dirname(self.filename), exist_ok=True)
        with open(self.filename, 'w'):
            pass
        self.reset()

    def extract_time(self, txt):
        i1 = txt.rfind("Global time")
        if i1 == -1:
            return self.current_time
        else:
            time_line = txt[i1:].strip()

        if time_line == "":
            return self.current_time
        try:
            return float(time_line[time_line.index('=') + 1:time_line.index('Iter')])
        except:
            print ("Cannot extract time from #" + time_line + "#")
            pass

    def update_status(self):
        if not os.path.isfile(self.filename):
            self.status = MISSING
        else:
            if self.status == UNKNOWN or self.status == MISSING:
                self.status = PENDING
            with open(self.filename, 'rb') as fid:
                fid.seek(self.position)
                txt = fid.read()
            self.position += len(txt)
            txt = txt.decode(encoding='utf_8', errors='strict')
            self.txt += txt
            if self.status == PENDING and self.position > 0:
                self.status = INITIALIZATION

            if len(txt) > 0:
                if len(txt.strip()):
                    self.lastline = (txt.strip()[max(0, txt.strip().rfind("\n")):]).strip()
                if self.status == INITIALIZATION:
                    init_txt, *rest = txt.split("Starting simulation")
                    if self.hawc2version == "Unknown" and "Version ID" in init_txt:
                        self.hawc2version = txt.split("Version ID : ")[1].split("\n", 1)[0].strip()
                    if "*** ERROR ***" in init_txt:
                        self.errors.extend([l.strip() for l in init_txt.strip().split("\n") if "error" in l.lower()])
                    if rest:
                        txt = rest[0]
                        self.status = SIMULATING

                if self.status == SIMULATING:
                    if self.start_time is None and not 'Elapsed time' in self.lastline:
                        i1 = txt.rfind("Global time")
                        if i1 > -1:
                            self.start_time = (self.extract_time(txt[i1:]), time.time())

                    simulation_txt, *rest = txt.split('Elapsed time')
                    if "*** ERROR ***" in simulation_txt:
                        self.errors.extend([l.strip() for l in simulation_txt.strip().split("\n") if "error" in l.lower()])
                    i1 = simulation_txt.rfind("Global time")
                    if i1 > -1:
                        self.current_time = self.extract_time(simulation_txt[i1:])
                    if self.time_stop > 0:
                        self.pct = int(100 * self.current_time // self.time_stop)
                    try:
                        self.remaining_time = (time.time() - self.start_time[1]) / (self.current_time - self.start_time[0]) * (self.time_stop - self.current_time)
                    except:
                        pass
                    if rest:
                        self.status = DONE
                        self.pct = 100
                        self.elapsed_time = float(rest[0].replace(":", "").strip())

    def error_str(self):
        error_dict = OrderedDict()
        for error in self.errors:
            error_dict[error] = error_dict.get(error, 0) + 1
        return "\n".join([("%d x %s" % (v, k), k)[v == 1] for k, v in error_dict.items()])


    def remaining_time_str(self):
        if self.remaining_time:
            if self.remaining_time < 3600:
                m, s = divmod(self.remaining_time, 60)
                return "%02d:%02d" % (m, math.ceil(s))
            else:
                h, ms = divmod(self.remaining_time, 3600)
                m, s = divmod(ms, 60)
                return "%d:%02d:%02d" % (h, m, math.ceil(s))
        else:
            return "--:--"