Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log manager for Python based nodes #631

Merged
merged 8 commits into from
Jan 25, 2020
96 changes: 96 additions & 0 deletions meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,101 @@ def fromDict(self, d):
self.sessionUid = d.get('sessionUid', '')


class LogManager:
dateTimeFormatting = '%H:%M:%S'

def __init__(self, chunk):
self.chunk = chunk
self.chunk.statusChanged.connect(self.clear)
self.progressBar = False
self.cleared = False
self.logger = logging.getLogger(chunk.node.getName())

class Formatter(logging.Formatter):
def format(self, record):
# Make level name lower case
record.levelname = record.levelname.lower()
return logging.Formatter.format(self, record)

def configureLogger(self):
for handler in self.logger.handlers[:]:
self.logger.removeHandler(handler)
handler = logging.FileHandler(self.chunk.logFile)
formatter = self.Formatter('[%(asctime)s.%(msecs)03d][%(levelname)s] %(message)s', self.dateTimeFormatting)
handler.setFormatter(formatter)
self.logger.addHandler(handler)

def clear(self):
if self.chunk.statusName == 'RUNNING' and not self.cleared:
open(self.chunk.logFile, 'w').close()
self.configureLogger()
self.cleared = True
# When the node gets ran again the log needs to be cleared
elif self.chunk.statusName in ['ERROR', 'SUCCESS']:
for handler in self.logger.handlers[:]:
# Stops the file being locked
handler.close()
self.cleared = False
self.progressBar = False

def waitUntilCleared(self):
while not self.cleared:
time.sleep(0.01)

def add(self, message, level=logging.INFO):
assert not self.progressBar
self.waitUntilCleared()

self.logger.log(level, message)

def makeProgressBar(self, end, message=''):
assert end > 0
assert not self.progressBar
self.waitUntilCleared()

self.progressEnd = end
self.currentProgressTics = 0
self.progressBar = True

with open(self.chunk.logFile, 'a') as f:
if message:
f.write(message+'\n')
f.write('0% 10 20 30 40 50 60 70 80 90 100%\n')
f.write('|----|----|----|----|----|----|----|----|----|----|\n')
f.close()

def updateProgressBar(self, value):
assert self.progressBar
assert value <= self.progressEnd
self.waitUntilCleared()

tics = round((value/self.progressEnd)*51)

with open(self.chunk.logFile, 'a') as f:
for i in range(tics-self.currentProgressTics):
f.write('*')
f.close()

self.currentProgressTics = tics

def completeProgressBar(self):
assert self.progressBar

with open(self.chunk.logFile, 'a') as f:
f.write('\n')
f.close()

self.progressBar = False

def textToLevel(self, text):
if text == 'critical': return logging.CRITICAL
elif text == 'error': return logging.ERROR
elif text == 'warning': return logging.WARNING
elif text == 'info': return logging.INFO
elif text == 'debug': return logging.DEBUG
else: return logging.NOTSET


runningProcesses = {}


Expand All @@ -142,6 +237,7 @@ def __init__(self, node, range, parent=None):
super(NodeChunk, self).__init__(parent)
self.node = node
self.range = range
self.log = LogManager(self)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    def __init__(self, node, range, parent=None):
        ...
        self.logManager = LogManager(self)
        ...

    @property
    def logging(self):
        return self.logManager.logger

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have called the property logger instead of logging because it makes more sense imo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I agree.

self.status = StatusData(node.name, node.nodeType, node.packageName, node.packageVersion)
self.statistics = stats.Statistics()
self.statusFileLastModTime = -1
Expand Down
27 changes: 20 additions & 7 deletions meshroom/nodes/aliceVision/Publish.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from __future__ import print_function

__version__ = "1.1"
__version__ = "1.2"

from meshroom.core import desc
import shutil
import glob
import os
import logging


class Publish(desc.Node):
Expand All @@ -30,6 +31,15 @@ class Publish(desc.Node):
description="",
value="",
uid=[0],
),
desc.ChoiceParam(
name='verboseLevel',
label='Verbose Level',
description='''verbosity level (critical, error, warning, info, debug).''',
value='info',
values=['critical', 'error', 'warning', 'info', 'debug'],
exclusive=True,
uid=[],
),
]

Expand All @@ -41,23 +51,26 @@ def resolvedPaths(self, inputFiles, outDir):
return paths

def processChunk(self, chunk):
print("Publish")
chunk.log.logger.setLevel(chunk.log.textToLevel(chunk.node.verboseLevel.value))

if not chunk.node.inputFiles:
print("Nothing to publish")
chunk.log.add('Nothing to publish', logging.WARNING)
return
if not chunk.node.output.value:
return

outFiles = self.resolvedPaths(chunk.node.inputFiles.value, chunk.node.output.value)

if not outFiles:
raise RuntimeError("Publish: input files listed, but nothing to publish. "
"Listed input files: {}".format(chunk.node.inputFiles.value))
error = 'Publish: input files listed, but nothing to publish'
chunk.log.add(error, logging.ERROR)
chunk.log.add('Listed input files: {}'.format([i.value for i in chunk.node.inputFiles.value]))
raise RuntimeError(error)

if not os.path.exists(chunk.node.output.value):
os.mkdir(chunk.node.output.value)

for iFile, oFile in outFiles.items():
print('Publish file', iFile, 'into', oFile)
chunk.log.add('Publish file {} into {}'.format(iFile, oFile))
shutil.copyfile(iFile, oFile)
print('Publish end')
chunk.log.add('Publish end')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chunk.logging.info('Publish end')