class_docstr: Write log messages to console periodically.
  
  It tracks an average meter for each metric, which is the average value since last ``clear()`` till now.
  The display format for each metric is ``<name> <latest_value> (<average_value>)``.
  
  Non-single-number metrics are auto skipped.
class_docstr_tok: ["Write","log","messages","to","console","periodically",".","It","tracks","an","average","meter","for","each","metric",",","which","is","the","average","value","since","last","``","clear","(",")","``","till","now",".","The","display","format","for","each","metric","is","``","<","name",">","<","latest_value",">","(","<","average_value",">",")","``",".","Non-single-number","metrics","are","auto","skipped","."]
code: def log_episode(
      self,
      length: int,
      rewards: List[float],
      contents: List[Dict[str, Any]],
  ) -> None:
      # Aggregate step-wise to episode-wise
      episode_wise_contents: Dict[str, list] = defaultdict(list)
  
      for step_contents in contents:
          for name, value in step_contents.items():
              if isinstance(value, float):
                  episode_wise_contents[name].append(value)
  
      # Generate log contents and track them in average-meter.
      # This should be done at every step, regardless of periodic or not.
      logs: Dict[str, float] = {}
      for name, values in episode_wise_contents.items():
          logs[name] = self.aggregation(values, name)  # type: ignore
  
      for name, value in logs.items():
          self.metric_counts[name] += 1
          self.metric_sums[name] += value
  
      if (
          self.episode_count % self.log_every_n_episode == 0
          or self.episode_count == self.total_episodes
      ):
          # Only log periodically or at the end
          self.console_logger.info(self.generate_log_message(logs))
  
imports: from __future__ import annotations
  import logging
  from collections import defaultdict
  from enum import IntEnum
  from pathlib import Path
  from typing import TYPE_CHECKING, Any, Callable, Dict, Generic, List, Sequence, Set, Tuple, TypeVar
  import numpy
  import pandas
  from qlib.log import get_module_logger
label_desc: Use image node_id 3 for calling the ConsoleWriter obj's underlying member method code with example usage: obj.log_episode(length, rewards, contents) without return types