mayaのログをwith構文でファイルに出力

スクリプトの実行ログをファイルに保存しておくと何かと役に立つ。この記事ではmayaのログファイルの出力リダイレクトを簡単に書く方法を紹介しよう


maya をつかっていて「スクリプトエディタのログをファイルに出力したい」という 状況は割とよくあるわけだ。そのような場合, mayaの起動オプションに与える方法, MAYA_CMD_FILE_OUTPUT を使う方法や scriptEditorInfo -writeHistory true -historyFilename "the_filepath.log"; などがある。参考 http://help.autodesk.com/view/MAYAUL/2020/ENU/?guid=__Commands_scriptEditorInfo_html

では、スクリプトを書いている場合、特定の箇所のみログに出力したい場合はどうするかというと、scriptEditorInfo のオンオフでくるんでやることになる。 python を使っている場合そのようなオンオフ挙動には contextmanager を使って、with ステートメントで使えるようすると使い勝手がよい。具体的には

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)

としてやって、たとえばこのように使う

        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)

見てわかると思うが、これでエクスポート処理のみのログを logfile に出力可能だ。


このように特定処理のみでファイルに抜き出しておくと何かと便利だ。バッチで並列で処理していたり、一括処理しているとき、 ログを監視(tail -f とかで)しなが遂行できたりする。もちろん、監視したログの状況に応じて エラーをログファイル付きで自動で報告するといったこともできるだろう。