bosr: Note: I took the liberty to remove the `test_no_tensorboardX` test as it did not seem relevant anymore. As an alternative, we could check that the `SummaryWriter` class is indeed from PyTorch?
vfdev-5: @bosr thanks for the PR ! 

> As an alternative, we could check that the SummaryWriter class is indeed from PyTorch?

Yes, I think we will need this, otherwise coverage wont be "happy" with the code coverage delta...

vfdev-5: @bosr do you need any help with tests ?
bosr: Ah ah, why not ;) I’ll write to you this evening. You saw my multiple failures on my fake branch? 

Romain

> On 10 Sep 2019, at 11:50, vfdev <notifications@github.com> wrote:
> 
> ﻿
> @bosr do you need any help with tests ?
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub, or mute the thread.

vfdev-5: @bosr no problems.
bosr: Hi, I've just rebased and included some support for the test.

Basically, my problem is that, if I re-establish the test, like for instance:

    with TensorboardLogger(log_dir=dirname) as tb_logger:
        assert(isinstance(tb_logger.writer, torch.utils.tensorboard.SummaryWriter), \
            "in the absence of tensorboardX, SummaryWriter should come from torch.utils.tensorboard"

then there is another `ImportError` about missing `tensorboard` module in `torch.utils`. I'm honestly surprised by this error. You can see it here: https://travis-ci.org/bosr/ignite/jobs/583263107

Do you have an idea for fixing this? Or do you prefer to cancel this and just write a warning?

Thanks for your support! 
vfdev-5: > there is another ImportError about missing tensorboard module in torch.utils. I'm honestly surprised by this error. 

This is because `tensorboard` is not a declared module : https://github.com/pytorch/pytorch/blob/master/torch/utils/__init__.py

Maybe you can do something like : 
```python

from torch.utils.tensorboard import SummaryWriter
with TensorboardLogger(log_dir=dirname) as tb_logger:
        assert isinstance(tb_logger.writer, SummaryWriter), type(tb_logger.writer)
```
bosr: Oops, I got confused with the import, thanks. I’ll update the PR. 
bosr: I've finally installed the test suite locally, so I'll keep iterating and come back here. Thanks!
bosr: Thanks a lot for the fixes! The code is nicer now, and one more case covered. This incentivized me to push it a little bit further and reduce to:

```python
def test_no_tensorboardX_package(dirname):
    from torch.utils.tensorboard import SummaryWriter
    with patch.dict('sys.modules', {'tensorboardX': None}):
        tb_logger = TensorboardLogger(log_dir=dirname)
        assert isinstance(tb_logger.writer, SummaryWriter), type(tb_logger.writer)

def test_no_torch_utils_tensorboard_package(dirname):
    from tensorboardX import SummaryWriter
    with patch.dict('sys.modules', {'torch.utils.tensorboard': None}):
        tb_logger = TensorboardLogger(log_dir=dirname)
        assert isinstance(tb_logger.writer, SummaryWriter), type(tb_logger.writer)


def test_no_tensorboardX_nor_torch_utils_tensorboard():
    with patch.dict('sys.modules', {'tensorboardX': None, 'torch.utils.tensorboard': None}):
        with pytest.raises(RuntimeError, match=r'This contrib module requires either tensorboardX or torch'):
            TensorboardLogger(log_dir=None)
```
replacing all related fixtures. Locally it passes on both 2.7 and 3.6+. Let's see if CI agrees ;)

I kept the previous code as comments for discussion. Tell me what you think about it.
diff --git a/.travis.yml b/.travis.yml
index 5b4ac4e5..69c7d420 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,7 +29,7 @@ before_install: &before_install
   - source activate test-environment
   - if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then pip install enum34; fi
   # Test contrib dependencies
-  - pip install tqdm scikit-learn tensorboardX visdom polyaxon-client mlflow
+  - pip install tqdm scikit-learn tensorboardX visdom polyaxon-client mlflow tensorboard
   - if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then pip install pynvml; fi
   # Futures should be already installed via visdom -> tornado -> futures
   # Let's reinstall it anyway to be sure
diff --git a/ignite/contrib/handlers/tensorboard_logger.py b/ignite/contrib/handlers/tensorboard_logger.py
index b1cb76f0..1a0c0759 100644
--- a/ignite/contrib/handlers/tensorboard_logger.py
+++ b/ignite/contrib/handlers/tensorboard_logger.py
@@ -322,12 +322,13 @@ class TensorboardLogger(BaseLogger):
     """
     TensorBoard handler to log metrics, model/optimizer parameters, gradients during the training and validation.
 
-    This class requires `tensorboardX <https://github.com/lanpa/tensorboardX>`_ package to be installed:
+    By default, this class favors `tensorboardX <https://github.com/lanpa/tensorboardX>`_ package if installed:
 
     .. code-block:: bash
 
         pip install tensorboardX
 
+    otherwise, it falls back to using PyTorch's SummaryWriter (>=v1.2.0).
 
     Args:
         *args: Positional arguments accepted from :class:`~tensorboardx.SummaryWriter`.
@@ -413,8 +414,12 @@ class TensorboardLogger(BaseLogger):
         try:
             from tensorboardX import SummaryWriter
         except ImportError:
-            raise RuntimeError("This contrib module requires tensorboardX to be installed. "
-                               "Please install it with command: \n pip install tensorboardX")
+            try:
+                from torch.utils.tensorboard import SummaryWriter
+            except ImportError:
+                raise RuntimeError("This contrib module requires either tensorboardX or torch >= 1.2.0. "
+                                   "You may install tensorboardX with command: \n pip install tensorboardX \n"
+                                   "or upgrade PyTorch using your package manager of choice (pip or conda).")
 
         self.writer = SummaryWriter(*args, **kwargs)
 

support for torch.utils.tensorboard when using `tensorboard_logger`
With PyTorch 1.1.0, TensorBoard is now [natively supported](https://pytorch.org/docs/stable/tensorboard.html) in PyTorch. 

Can we add a new option to switch `torch.utils.tensorboard` or `tensorboardX`?

I found that `tensorboard_logger` only need `SummaryWriter` to implement `add_histogram` and `add_scalar`. It seems that we can just import `torch.utils.tensorboard` when import tensorboardX failed.

```python
try:
    from tensorboardX import SummaryWriter
except ImportError:
    from torch.utils.tensorboard import SummaryWriter
```

For now, tensorboardX:
> Support scalar, image, figure, histogram, audio, text, graph, onnx_graph, embedding, pr_curve, mesh and video summaries.

`torch.utils.tensorboard`:
> Scalars, images, histograms, graphs, and embedding visualizations are all supported for PyTorch models and tensors as well as Caffe2 nets and blobs.


diff --git a/tests/ignite/contrib/handlers/test_tensorboard_logger.py b/tests/ignite/contrib/handlers/test_tensorboard_logger.py
index 70e2ba77..0ec40c5c 100644
--- a/tests/ignite/contrib/handlers/test_tensorboard_logger.py
+++ b/tests/ignite/contrib/handlers/test_tensorboard_logger.py
@@ -3,7 +3,7 @@ import math
 
 import pytest
 
-from mock import MagicMock, call, ANY, Mock
+from mock import MagicMock, call, ANY, Mock, patch
 
 import torch
 
@@ -560,44 +560,88 @@ def test_integration_as_context_manager(dirname):
     assert len(written_files) > 0
 
 
-@pytest.fixture
-def no_site_packages():
-    import sys
-    tensorboardX_module = sys.modules['tensorboardX']
-    del sys.modules['tensorboardX']
-    prev_path = list(sys.path)
-    sys.path = [p for p in sys.path if "site-packages" not in p]
-    yield "no_site_packages"
-    sys.path = prev_path
-    sys.modules['tensorboardX'] = tensorboardX_module
+# @pytest.fixture
+# def no_tensorboardX_package():
+#     import sys
+#     import tensorboardX
+#     from torch.utils import tensorboard
+#     # remove tensorboardX
+#     tensorboardX_module = sys.modules['tensorboardX']
+#     del sys.modules['tensorboardX']
+#     # save and replace sys.path
+#     prev_path = list(sys.path)
+#     sys.path = [p for p in sys.path if "site-packages" not in p]
+#     yield "no_site_packages"
+#     # put everything back in place
+#     sys.path = prev_path
+#     sys.modules['tensorboardX'] = tensorboardX_module
 
 
-def test_no_tensorboardX(dirname, no_site_packages):
+# def test_no_tensorboardX(dirname, no_tensorboardX_package):
 
-    with pytest.raises(RuntimeError, match=r"This contrib module requires tensorboardX to be installed"):
-        TensorboardLogger(log_dir=dirname)
+#     from torch.utils.tensorboard import SummaryWriter
+#     with TensorboardLogger(log_dir=dirname) as tb_logger:
+#         assert isinstance(tb_logger.writer, SummaryWriter), type(tb_logger.writer)
 
 
-@pytest.fixture
-def mock_tb_module():
-    import sys
-    import types
+# @pytest.fixture
+# def mock_tb_module():
+#     import sys
+#     import types
 
-    module_name = 'tensorboardX'
-    tb_module = types.ModuleType(module_name)
-    prev_tb_module = sys.modules[module_name]
-    sys.modules[module_name] = tb_module
+#     module_name = 'tensorboardX'
+#     tb_module = types.ModuleType(module_name)
+#     prev_tb_module = sys.modules[module_name]
+#     sys.modules[module_name] = tb_module
 
-    yield tb_module
-    sys.modules[module_name] = prev_tb_module
+#     yield tb_module
+#     sys.modules[module_name] = prev_tb_module
 
 
-def test_init_typeerror_exception(mock_tb_module):
+# def test_init_typeerror_exception(mock_tb_module):
 
-    def side_effect(*args, **kwargs):
-        raise TypeError("a problem")
+#     def side_effect(*args, **kwargs):
+#         raise TypeError("a problem")
 
-    mock_tb_module.SummaryWriter = Mock(name='tensorboardX.SummaryWriter', side_effect=side_effect)
+#     mock_tb_module.SummaryWriter = Mock(name='tensorboardX.SummaryWriter', side_effect=side_effect)
 
-    with pytest.raises(TypeError, match=r'a problem'):
-        TensorboardLogger(log_dir=None)
+#     with pytest.raises(TypeError, match=r'a problem'):
+#         TensorboardLogger(log_dir=None)
+
+
+# @pytest.fixture
+# def mock_no_torch_utils_tensorboard():
+#     import sys
+#     from torch.utils import tensorboard
+#     orig_module = sys.modules['torch.utils.tensorboard']
+#     mock_module = Mock(spec=tensorboard)
+#     del mock_module.SummaryWriter
+#     sys.modules['torch.utils.tensorboard'] = mock_module
+#     yield mock_module
+#     sys.modules['torch.utils.tensorboard'] = orig_module
+
+
+# def test_no_torch_utils_tensorboard(no_tensorboardX_package, mock_no_torch_utils_tensorboard):
+
+#     with pytest.raises(RuntimeError, match=r'This contrib module requires either tensorboardX or torch'):
+#         TensorboardLogger(log_dir=None)
+
+
+def test_no_tensorboardX_package(dirname):
+    from torch.utils.tensorboard import SummaryWriter
+    with patch.dict('sys.modules', {'tensorboardX': None}):
+        tb_logger = TensorboardLogger(log_dir=dirname)
+        assert isinstance(tb_logger.writer, SummaryWriter), type(tb_logger.writer)
+
+
+def test_no_torch_utils_tensorboard_package(dirname):
+    from tensorboardX import SummaryWriter
+    with patch.dict('sys.modules', {'torch.utils.tensorboard': None}):
+        tb_logger = TensorboardLogger(log_dir=dirname)
+        assert isinstance(tb_logger.writer, SummaryWriter), type(tb_logger.writer)
+
+
+def test_no_tensorboardX_nor_torch_utils_tensorboard():
+    with patch.dict('sys.modules', {'tensorboardX': None, 'torch.utils.tensorboard': None}):
+        with pytest.raises(RuntimeError, match=r'This contrib module requires either tensorboardX or torch'):
+            TensorboardLogger(log_dir=None)

pip install -e .
parse_log_pytest
pytest
numpy mock pytest codecov pytest-cov matplotlib pandas gym tqdm scikit-learn tensorboardX visdom polyaxon-client mlflow
apt-get update apt-get install -y gcc
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alembic==1.7.7
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
charset-normalizer==2.0.12
click==7.1.2
cloudpickle==2.2.1
codecov==2.1.13
coverage==6.2
cycler==0.11.0
databricks-cli==0.17.8
dataclasses==0.8
decorator==4.4.2
docker==5.0.3
entrypoints==0.4
Flask==1.1.4
gitdb==4.0.9
GitPython==3.1.18
greenlet==2.0.2
gunicorn==21.2.0
gym==0.26.2
gym-notices==0.0.8
hestia==0.6.0
idna==3.10
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
importlib-resources==5.4.0
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
itsdangerous==1.1.0
Jinja2==2.10.3
joblib==1.1.1
jsonpatch==1.32
jsonpointer==2.3
kiwisolver==1.3.1
Mako==1.1.6
MarkupSafe==2.0.1
marshmallow==3.0.0rc5
matplotlib==3.3.4
mlflow==1.23.1
mock==5.2.0
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
networkx==2.5.1
numpy==1.19.5
oauthlib==3.2.2
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pandas==1.1.5
Pillow==8.4.0
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
polyaxon-client==0.6.1
polyaxon-schemas==0.6.1
polystores==0.2.5
prometheus-client==0.17.1
prometheus_flask_exporter==0.23.2
protobuf==4.21.0
psutil==7.0.0
py @ file:///opt/conda/conda-bld/py_1644396412707/work
PyJWT==2.4.0
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
pytest-cov==4.0.0
python-dateutil==2.9.0.post0
-e git+https://github.com/pytorch/ignite.git@8ffcf8d3b6f0e63eea1f275631703133913d03de#egg=pytorch_ignite
pytz==2025.2
PyYAML==6.0.1
querystring-parser==1.2.4
requests==2.27.1
requests-toolbelt==1.0.0
rhea==0.5.5
scikit-learn==0.24.2
scipy==1.5.4
six==1.17.0
smmap==5.0.0
SQLAlchemy==1.4.54
sqlparse==0.4.4
tabulate==0.8.10
tensorboardX==2.6.2.2
threadpoolctl==3.1.0
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
tomli==1.2.3
torch==1.10.2
tornado==6.1
tqdm==4.64.1
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
urllib3==1.26.20
visdom==0.2.4
websocket-client==1.3.1
Werkzeug==1.0.1
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: ignite
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alembic==1.7.7
      - charset-normalizer==2.0.12
      - click==7.1.2
      - cloudpickle==2.2.1
      - codecov==2.1.13
      - coverage==6.2
      - cycler==0.11.0
      - databricks-cli==0.17.8
      - dataclasses==0.8
      - decorator==4.4.2
      - docker==5.0.3
      - entrypoints==0.4
      - flask==1.1.4
      - gitdb==4.0.9
      - gitpython==3.1.18
      - greenlet==2.0.2
      - gunicorn==21.2.0
      - gym==0.26.2
      - gym-notices==0.0.8
      - hestia==0.6.0
      - idna==3.10
      - importlib-resources==5.4.0
      - itsdangerous==1.1.0
      - jinja2==2.10.3
      - joblib==1.1.1
      - jsonpatch==1.32
      - jsonpointer==2.3
      - kiwisolver==1.3.1
      - mako==1.1.6
      - markupsafe==2.0.1
      - marshmallow==3.0.0rc5
      - matplotlib==3.3.4
      - mlflow==1.23.1
      - mock==5.2.0
      - networkx==2.5.1
      - numpy==1.19.5
      - oauthlib==3.2.2
      - pandas==1.1.5
      - pillow==8.4.0
      - polyaxon-client==0.6.1
      - polyaxon-schemas==0.6.1
      - polystores==0.2.5
      - prometheus-client==0.17.1
      - prometheus-flask-exporter==0.23.2
      - protobuf==4.21.0
      - psutil==7.0.0
      - pyjwt==2.4.0
      - pytest-cov==4.0.0
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyyaml==6.0.1
      - querystring-parser==1.2.4
      - requests==2.27.1
      - requests-toolbelt==1.0.0
      - rhea==0.5.5
      - scikit-learn==0.24.2
      - scipy==1.5.4
      - six==1.17.0
      - smmap==5.0.0
      - sqlalchemy==1.4.54
      - sqlparse==0.4.4
      - tabulate==0.8.10
      - tensorboardx==2.6.2.2
      - threadpoolctl==3.1.0
      - tomli==1.2.3
      - torch==1.10.2
      - tornado==6.1
      - tqdm==4.64.1
      - urllib3==1.26.20
      - visdom==0.2.4
      - websocket-client==1.3.1
      - werkzeug==1.0.1
prefix: /opt/conda/envs/ignite

tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_no_tensorboardX_nor_torch_utils_tensorboard
tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_no_tensorboardX_package
tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_optimizer_params_handler_wrong_setup tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_optimizer_params tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_output_handler_with_wrong_logger_type tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_output_handler_output_transform tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_output_handler_metric_names tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_output_handler_both tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_output_handler_with_wrong_global_step_transform_output tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_output_handler_with_global_step_transform tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_weights_scalar_handler_wrong_setup tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_weights_scalar_handler tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_weights_scalar_handler_frozen_layers tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_weights_hist_handler_wrong_setup tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_weights_hist_handler tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_weights_hist_handler_frozen_layers tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_grads_scalar_handler_wrong_setup tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_grads_scalar_handler tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_grads_scalar_handler_frozen_layers tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_grads_hist_handler_wrong_setup tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_grads_hist_handler tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_grads_hist_frozen_layers tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_integration tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_integration_as_context_manager tests/ignite/contrib/handlers/test_tensorboard_logger.py::test_no_torch_utils_tensorboard_package
ignite/contrib/handlers/tensorboard_logger.py .travis.yml
ignite/contrib/handlers/tensorboard_logger.py .travis.yml