class_docstr: Base class for log writers, triggered at every reset and step by finite env.
  
  What to do with a specific log depends on the implementation of subclassing :class:`LogWriter`.
  The general principle is that, it should handle logs above its loglevel (inclusive),
  and discard logs that are not acceptable. For instance, console loggers obviously can't handle an image.
class_docstr_tok: ["Base","class","for","log","writers",",","triggered","at","every","reset","and","step","by","finite","env",".","What","to","do","with","a","specific","log","depends","on","the","implementation","of","subclassing",":","class",":","`","LogWriter","`",".","The","general","principle","is","that",",","it","should","handle","logs","above","its","loglevel","(","inclusive",")",",","and","discard","logs","that","are","not","acceptable",".","For","instance",",","console","loggers","obviously","ca","n't","handle","an","image","."]
docstr: Callback for finite env, on each step.
code: def on_env_step(
      self,
      env_id: int,
      obs: ObsType,
      rew: float,
      done: bool,
      info: InfoDict,
  ) -> None:
      """Callback for finite env, on each step."""
  
      # Update counter
      self.global_step += 1
      self.step_count += 1
  
      self.active_env_ids.add(env_id)
      self.episode_lengths[env_id] += 1
      # TODO: reward can be a list of list for MARL
      self.episode_rewards[env_id].append(rew)
  
      values: Dict[str, Any] = {}
  
      for key, (loglevel, value) in info["log"].items():
          if (
              loglevel >= self.loglevel
          ):  # FIXME: this is actually incorrect (see last FIXME)
              values[key] = value
      self.episode_logs[env_id].append(values)
  
      self.log_step(rew, values)
  
      if done:
          # Update counter
          self.global_episode += 1
          self.episode_count += 1
  
          self.log_episode(
              self.episode_lengths[env_id],
              self.episode_rewards[env_id],
              self.episode_logs[env_id],
          )
  
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 8 for calling the LogWriter obj's underlying member method code with example usage: obj.on_env_step(env_id, obs, rew, done, info) without return types