Outputting Maya logs to a file using with statement
Saving script execution logs to a file can be quite useful. This article introduces a simple way to redirect Maya's log output
When working with Maya, the need to "output Script Editor logs to a file" is quite common. In such cases, there are methods like using Maya's startup options, using MAYA_CMD_FILE_OUTPUT, or
scriptEditorInfo -writeHistory true -historyFilename "the_filepath.log";
Reference: http://help.autodesk.com/view/MAYAUL/2020/ENU/?guid=__Commands_scriptEditorInfo_html
But when writing scripts, how do you output only specific parts to the log? You would need to wrap those parts with scriptEditorInfo on/off commands.
When using Python, a contextmanager can make such on/off behavior more convenient by allowing it to be used with a with statement. Specifically:
from pathlib import Path
import contextlib
@contextlib.contextmanager
def redirect_log(logfile_path):
# type: (Text) -> Generator[None, None, None]
"""Function: Context manager for redirecting maya's log to given logfile.
aiming to Use as `with` statement.
Scenario: giving None to logfile_path
then: do nothing
Scenario: given existing path
then: redirect to path before, do main job then re-redirect to original
Scenario: given non-existing path
then: touch file, redirect to path before, do main job then re-redirect to original
"""
import maya.cmds as cmds
if not logfile_path:
yield
return
logfile = Path(logfile_path)
logfile.touch()
is_original_redirected = cmds.scriptEditorInfo(q=True, writeHistory=True)
original_log = cmds.scriptEditorInfo(q=True, historyFilename=True)
try:
cmds.scriptEditorInfo(historyFilename=logfile.as_posix(), writeHistory=True)
yield
finally:
cmds.scriptEditorInfo(writeHistory=False)
if is_original_redirected:
cmds.scriptEditorInfo(writeHistory=True)
if original_log:
cmds.scriptEditorInfo(historyFilename=original_log)
And you would use it like this:
with redirect_log(logfile):
try:
export(filename)
except Exception as e:
import traceback
logger.error(traceback.format_exc())
logger.error(e)
failed.append(f)
def export(filename):
logger.info("export start %s", filename)
hogemage
...
logger.info("export finish %s", filename)
As you can see, this allows you to output only the export process logs to the logfile.
Extracting logs for specific processes in this way can be very convenient. When processing in parallel batches or doing bulk operations, you can monitor the logs (e.g., with tail -f) while performing tasks. Of course, you could also automatically report errors with the log file attached, depending on the monitored log status.