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.