Repository: pytorch/ignite

Issue:
Missing `close` method in `WandBLogger` and `PolyaxonLogger` ?
## 🐛 Bug description

Just found it unexpected. Not sure this is intended. There are `close` method overrides in provided loggers except for `WandBLogger` and `PolyaxonLogger`. [wandb states that wandb process have to close if we are on jupyter or colab env](https://docs.wandb.ai/integrations/huggingface#6-finish-your-w-and-b-run-notebook-only). Not sure about PolyaxonLogger.

We need to have one API to close all loggers even if users want to change using different loggers.



Discussion:
@ydcjeff thanks for the report (sorry for the delay) ! Yes, I agree it would make sense to have a unified API. As for PolyaxonLogger I think there is not special need for closing it AFAIK.

Resolving patch:
diff --git a/ignite/contrib/handlers/polyaxon_logger.py b/ignite/contrib/handlers/polyaxon_logger.py
--- a/ignite/contrib/handlers/polyaxon_logger.py
+++ b/ignite/contrib/handlers/polyaxon_logger.py
@@ -87,6 +87,8 @@ class PolyaxonLogger(BaseLogger):
                 optimizer=optimizer,
                 param_name='lr'  # optional
             )
+            # to manually end a run
+            plx_logger.close()
 
     Args:
         args: Positional arguments accepted from
@@ -101,6 +103,7 @@ def __init__(self, *args: Any, **kwargs: Any):
             from polyaxon.tracking import Run
 
             self.experiment = Run(*args, **kwargs)
+
         except ImportError:
             try:
                 from polyaxon_client.tracking import Experiment
@@ -113,6 +116,12 @@ def __init__(self, *args: Any, **kwargs: Any):
                     "For Polyaxon v0.x please install it with command: \n pip install polyaxon-client"
                 )
 
+    def close(self) -> None:
+        try:
+            self.experiment.end()
+        except:
+            pass
+
     def __getattr__(self, attr: Any) -> Any:
         return getattr(self.experiment, attr)
 
diff --git a/ignite/contrib/handlers/tensorboard_logger.py b/ignite/contrib/handlers/tensorboard_logger.py
--- a/ignite/contrib/handlers/tensorboard_logger.py
+++ b/ignite/contrib/handlers/tensorboard_logger.py
@@ -128,7 +128,7 @@ class TensorboardLogger(BaseLogger):
                 log_handler=GradsHistHandler(model)
             )
 
-            # We need to close the logger with we are done
+            # We need to close the logger when we are done
             tb_logger.close()
 
         It is also possible to use the logger as context manager:
diff --git a/ignite/contrib/handlers/wandb_logger.py b/ignite/contrib/handlers/wandb_logger.py
--- a/ignite/contrib/handlers/wandb_logger.py
+++ b/ignite/contrib/handlers/wandb_logger.py
@@ -81,6 +81,9 @@ class WandBLogger(BaseLogger):
                 param_name='lr'  # optional
             )
 
+            # We need to close the logger when we are done
+            wandb_logger.close()
+
         If you want to log model gradients, the model call graph, etc., use the logger as wrapper of wandb. Refer
         to the documentation of wandb.watch for details:
 
@@ -115,6 +118,8 @@ def score_function(engine):
                 global_step_transform=global_step_from_engine(trainer)
             )
             evaluator.add_event_handler(Events.COMPLETED, model_checkpoint, {'model': model})
+
+
     """
 
     def __init__(self, *args: Any, **kwargs: Any):
@@ -133,6 +138,9 @@ def __init__(self, *args: Any, **kwargs: Any):
     def __getattr__(self, attr: Any) -> Any:
         return getattr(self._wandb, attr)  # type: ignore[misc]
 
+    def close(self) -> None:
+        self._wandb.finish()
+
     def _create_output_handler(self, *args: Any, **kwargs: Any) -> "OutputHandler":
         return OutputHandler(*args, **kwargs)
 


Test patch:
diff --git a/tests/ignite/contrib/handlers/test_polyaxon_logger.py b/tests/ignite/contrib/handlers/test_polyaxon_logger.py
--- a/tests/ignite/contrib/handlers/test_polyaxon_logger.py
+++ b/tests/ignite/contrib/handlers/test_polyaxon_logger.py
@@ -254,6 +254,7 @@ def dummy_handler(engine, logger, event_name):
     plx_logger.attach(trainer, log_handler=dummy_handler, event_name=Events.EPOCH_COMPLETED)
 
     trainer.run(data, max_epochs=n_epochs)
+    plx_logger.close()
 
 
 def test_integration_as_context_manager():
diff --git a/tests/ignite/contrib/handlers/test_wandb_logger.py b/tests/ignite/contrib/handlers/test_wandb_logger.py
--- a/tests/ignite/contrib/handlers/test_wandb_logger.py
+++ b/tests/ignite/contrib/handlers/test_wandb_logger.py
@@ -219,6 +219,16 @@ def test_output_handler_with_global_step_from_engine():
     )
 
 
+def test_wandb_close():
+    optimizer = torch.optim.SGD([torch.Tensor(0)], lr=0.01)
+    wrapper = OptimizerParamsHandler(optimizer=optimizer, param_name="lr")
+    mock_logger = MagicMock(spec=WandBLogger)
+    mock_logger.log = MagicMock()
+    mock_engine = MagicMock()
+    wrapper(mock_engine, mock_logger, Events.ITERATION_STARTED)
+    mock_logger.close()
+
+
 @pytest.fixture
 def no_site_packages():
     import sys