code: def log_metrics_msg(
      self,
      metrics_outputs: MetricsOutputs,
      metrics_log_path: str,
      state: TrainerState,
  ) -> None:
      if not self.is_local_rank_0:
          return None
      final_score = metrics_outputs.final_score
      metric_values = metrics_outputs.metric_values
      core = " | ".join(
          [
              f"{k} : {fix_float_to_length(metric_values[k], 8)}"
              for k in sorted(metric_values)
          ]
      )
      step_str = self._step_str(state)
      timer_str = f"[{time.time() - self.timer:.3f}s]"
      msg = (
          f"| epoch {state.epoch:^4d} {step_str} {timer_str} | {core} | "
          f"score : {fix_float_to_length(final_score, 8)} |"
      )
      if self.verbose:
          print(msg)
      with open(metrics_log_path, "a") as f:
          if self.metrics_log_path is not None:
              msg = f"\n{msg}"
          f.write(msg)
      self.timer = time.time()
      self.metrics_log_path = metrics_log_path
  
imports: import os
  import json
  import time
  import shutil
  import getpass
  import platform
  from typing import Any
  from typing import Dict
  from typing import Optional
  from cftool.misc import lock_manager
  from cftool.misc import print_warning
  from cftool.misc import fix_float_to_length
  from ..schema import ITrainer
  from ..schema import StepOutputs
  from ..schema import TrainerState
  from ..schema import MetricsOutputs
  from ..schema import TrainerCallback
  from ..constants import PT_PREFIX
  from ..constants import SCORES_FILE
label_desc: Use image node_id 4 for calling the _LogMetricsMsgCallback obj's underlying member method code with example usage: obj.log_metrics_msg(metrics_outputs, metrics_log_path, state) and returns: None