docs: def add_event_handler(self, event_name, handler, *args, **kwargs):
          """Add an event handler to be executed when the specified event is fired.
  
          Args:
              event_name: An event to attach the handler to. Valid events are from :class:`~ignite.engine.Events`
                  or any `event_name` added by :meth:`~ignite.engine.Engine.register_events`.
              handler (callable): the callable event handler that should be invoked
              *args: optional args to be passed to `handler`.
              **kwargs: optional keyword args to be passed to `handler`.
  
          Note:
                The handler function's first argument will be `self`, the :class:`~ignite.engine.Engine` object it
                was bound to.
  
                Note that other arguments can be passed to the handler in addition to the `*args` and  `**kwargs`
                passed here, for example during :attr:`~ignite.engine.Events.EXCEPTION_RAISED`.
  
          Example usage:
  
          .. code-block:: python
  
              engine = Engine(process_function)
  
              def print_epoch(engine):
                  print("Epoch: {}".format(engine.state.epoch))
  
              engine.add_event_handler(Events.EPOCH_COMPLETED, print_epoch)
  
          """
          if event_name not in self._allowed_events:
              self._logger.error("attempt to add event handler to an invalid event %s.", event_name)
              raise ValueError("Event {} is not a valid event for this Engine.".format(event_name))
  
          event_args = (Exception(), ) if event_name == Events.EXCEPTION_RAISED else ()
          self._check_signature(handler, 'handler', *(event_args + args), **kwargs)
  
          self._event_handlers[event_name].append((handler, args, kwargs))
          self._logger.debug("added handler for event %s.", event_name)