We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Logging configuration in contrib/utils
# Question

`pyhf.contrib.utils` sets up logging:
https://github.com/scikit-hep/pyhf/blob/6b769fd6f5e1473deba2b4c55d49ebdb3db5b447/src/pyhf/contrib/utils.py#L9 

This interferes with custom logging users may want to set up. To achieve this now, they would have to do so before `from pyhf.contrib.utils import download`. To avoid this issue, the logging should not be configured in this part of the code (and only for the CLI).

# Relevant Issues and Pull Requests

#865

User-defined log formatting
# Description

`pyhf` uses `logging` for outputs, and calls `logging.basicConfig()` in a few places.
This has the effect of preventing the user to set their desired logging behavior after `pyhf` import.
While calling this a bug might be a bit of a stretch, I think it might be unintentional since `pyhf` does not apply any logging formatting as far as I can tell.

# Expected Behavior

I expect no calls to `logging.basicConfig()` within `pyhf` to leave the formatting fully up to the user, no matter whether they want to set it before or after importing `pyhf`.

# Actual Behavior

User-defined `logging` formatting only works before importing `pyhf`.

# Steps to Reproduce

importing `pyhf` before formatting:
```
import logging
import pyhf
print(pyhf.__version__)
logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)
log.info("message")
```
output:
```
0.4.1
```
and when applying formatting before input, the expected behavior:
```
import logging
logging.basicConfig(level=logging.INFO)
import pyhf
print(pyhf.__version__)
log = logging.getLogger(__name__)
log.info("message")
```
output:
```
0.4.1
INFO:__main__:message
``` 

# Checklist

- [ ] Run `git fetch` to get the most up to date version of `master`
  - no, but checked code on master to confirm that the relevant part is unchanged
- [X] Searched through existing Issues to confirm this is not a duplicate issue
- [X] Filled out the Description, Expected Behavior, Actual Behavior, and Steps to Reproduce sections above or have edited/removed them in a way that fully describes the issue


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/pyhf/contrib/utils.py`
Content:
```
1 """Helper utilities for common tasks."""
2 
3 from urllib.parse import urlparse
4 import tarfile
5 from io import BytesIO
6 import logging
7 from .. import exceptions
8 
9 logging.basicConfig()
10 log = logging.getLogger(__name__)
11 
12 __all__ = ["download"]
13 
14 
15 def __dir__():
16     return __all__
17 
18 
19 try:
20     import requests
21 
22     def download(archive_url, output_directory, force=False, compress=False):
23         """
24         Download the patchset archive from the remote URL and extract it in a
25         directory at the path given.
26 
27         Example:
28 
29             >>> from pyhf.contrib.utils import download
30             >>> download("https://doi.org/10.17182/hepdata.90607.v3/r3", "1Lbb-likelihoods")
31             >>> import os
32             >>> sorted(os.listdir("1Lbb-likelihoods"))
33             ['BkgOnly.json', 'README.md', 'patchset.json']
34             >>> download("https://doi.org/10.17182/hepdata.90607.v3/r3", "1Lbb-likelihoods.tar.gz", compress=True)
35             >>> import glob
36             >>> glob.glob("1Lbb-likelihoods.tar.gz")
37             ['1Lbb-likelihoods.tar.gz']
38 
39         Args:
40             archive_url (:obj:`str`): The URL of the :class:`~pyhf.patchset.PatchSet` archive to download.
41             output_directory (:obj:`str`): Name of the directory to unpack the archive into.
42             force (:obj:`bool`): Force download from non-approved host. Default is ``False``.
43             compress (:obj:`bool`): Keep the archive in a compressed ``tar.gz`` form. Default is ``False``.
44 
45         Raises:
46             :class:`~pyhf.exceptions.InvalidArchiveHost`: if the provided archive host name is not known to be valid
47         """
48         if not force:
49             valid_hosts = ["www.hepdata.net", "doi.org"]
50             netloc = urlparse(archive_url).netloc
51             if netloc not in valid_hosts:
52                 raise exceptions.InvalidArchiveHost(
53                     f"{netloc} is not an approved archive host: {', '.join(str(host) for host in valid_hosts)}\n"
54                     + "To download an archive from this host use the --force option."
55                 )
56 
57         with requests.get(archive_url) as response:
58             if compress:
59                 with open(output_directory, "wb") as archive:
60                     archive.write(response.content)
61             else:
62                 with tarfile.open(
63                     mode="r|gz", fileobj=BytesIO(response.content)
64                 ) as archive:
65                     archive.extractall(output_directory)
66 
67 
68 except ModuleNotFoundError:
69     log.error(
70         "\nInstallation of the contrib extra is required to use pyhf.contrib.utils.download"
71         + "\nPlease install with: python -m pip install pyhf[contrib]\n",
72         exc_info=True,
73     )
74
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/pyhf/contrib/utils.py b/src/pyhf/contrib/utils.py
--- a/src/pyhf/contrib/utils.py
+++ b/src/pyhf/contrib/utils.py
@@ -6,7 +6,6 @@
 import logging
 from .. import exceptions
 
-logging.basicConfig()
 log = logging.getLogger(__name__)
 
 __all__ = ["download"]

{"golden_diff": "diff --git a/src/pyhf/contrib/utils.py b/src/pyhf/contrib/utils.py\n--- a/src/pyhf/contrib/utils.py\n+++ b/src/pyhf/contrib/utils.py\n@@ -6,7 +6,6 @@\n import logging\n from .. import exceptions\n \n-logging.basicConfig()\n log = logging.getLogger(__name__)\n \n __all__ = [\"download\"]\n", "issue": "Logging configuration in contrib/utils\n# Question\r\n\r\n`pyhf.contrib.utils` sets up logging:\r\nhttps://github.com/scikit-hep/pyhf/blob/6b769fd6f5e1473deba2b4c55d49ebdb3db5b447/src/pyhf/contrib/utils.py#L9 \r\n\r\nThis interferes with custom logging users may want to set up. To achieve this now, they would have to do so before `from pyhf.contrib.utils import download`. To avoid this issue, the logging should not be configured in this part of the code (and only for the CLI).\r\n\r\n# Relevant Issues and Pull Requests\r\n\r\n#865\r\n\nUser-defined log formatting\n# Description\r\n\r\n`pyhf` uses `logging` for outputs, and calls `logging.basicConfig()` in a few places.\r\nThis has the effect of preventing the user to set their desired logging behavior after `pyhf` import.\r\nWhile calling this a bug might be a bit of a stretch, I think it might be unintentional since `pyhf` does not apply any logging formatting as far as I can tell.\r\n\r\n# Expected Behavior\r\n\r\nI expect no calls to `logging.basicConfig()` within `pyhf` to leave the formatting fully up to the user, no matter whether they want to set it before or after importing `pyhf`.\r\n\r\n# Actual Behavior\r\n\r\nUser-defined `logging` formatting only works before importing `pyhf`.\r\n\r\n# Steps to Reproduce\r\n\r\nimporting `pyhf` before formatting:\r\n```\r\nimport logging\r\nimport pyhf\r\nprint(pyhf.__version__)\r\nlogging.basicConfig(level=logging.INFO)\r\nlog = logging.getLogger(__name__)\r\nlog.info(\"message\")\r\n```\r\noutput:\r\n```\r\n0.4.1\r\n```\r\nand when applying formatting before input, the expected behavior:\r\n```\r\nimport logging\r\nlogging.basicConfig(level=logging.INFO)\r\nimport pyhf\r\nprint(pyhf.__version__)\r\nlog = logging.getLogger(__name__)\r\nlog.info(\"message\")\r\n```\r\noutput:\r\n```\r\n0.4.1\r\nINFO:__main__:message\r\n``` \r\n\r\n# Checklist\r\n\r\n- [ ] Run `git fetch` to get the most up to date version of `master`\r\n  - no, but checked code on master to confirm that the relevant part is unchanged\r\n- [X] Searched through existing Issues to confirm this is not a duplicate issue\r\n- [X] Filled out the Description, Expected Behavior, Actual Behavior, and Steps to Reproduce sections above or have edited/removed them in a way that fully describes the issue\r\n\n", "before_files": [{"content": "\"\"\"Helper utilities for common tasks.\"\"\"\n\nfrom urllib.parse import urlparse\nimport tarfile\nfrom io import BytesIO\nimport logging\nfrom .. import exceptions\n\nlogging.basicConfig()\nlog = logging.getLogger(__name__)\n\n__all__ = [\"download\"]\n\n\ndef __dir__():\n    return __all__\n\n\ntry:\n    import requests\n\n    def download(archive_url, output_directory, force=False, compress=False):\n        \"\"\"\n        Download the patchset archive from the remote URL and extract it in a\n        directory at the path given.\n\n        Example:\n\n            >>> from pyhf.contrib.utils import download\n            >>> download(\"https://doi.org/10.17182/hepdata.90607.v3/r3\", \"1Lbb-likelihoods\")\n            >>> import os\n            >>> sorted(os.listdir(\"1Lbb-likelihoods\"))\n            ['BkgOnly.json', 'README.md', 'patchset.json']\n            >>> download(\"https://doi.org/10.17182/hepdata.90607.v3/r3\", \"1Lbb-likelihoods.tar.gz\", compress=True)\n            >>> import glob\n            >>> glob.glob(\"1Lbb-likelihoods.tar.gz\")\n            ['1Lbb-likelihoods.tar.gz']\n\n        Args:\n            archive_url (:obj:`str`): The URL of the :class:`~pyhf.patchset.PatchSet` archive to download.\n            output_directory (:obj:`str`): Name of the directory to unpack the archive into.\n            force (:obj:`bool`): Force download from non-approved host. Default is ``False``.\n            compress (:obj:`bool`): Keep the archive in a compressed ``tar.gz`` form. Default is ``False``.\n\n        Raises:\n            :class:`~pyhf.exceptions.InvalidArchiveHost`: if the provided archive host name is not known to be valid\n        \"\"\"\n        if not force:\n            valid_hosts = [\"www.hepdata.net\", \"doi.org\"]\n            netloc = urlparse(archive_url).netloc\n            if netloc not in valid_hosts:\n                raise exceptions.InvalidArchiveHost(\n                    f\"{netloc} is not an approved archive host: {', '.join(str(host) for host in valid_hosts)}\\n\"\n                    + \"To download an archive from this host use the --force option.\"\n                )\n\n        with requests.get(archive_url) as response:\n            if compress:\n                with open(output_directory, \"wb\") as archive:\n                    archive.write(response.content)\n            else:\n                with tarfile.open(\n                    mode=\"r|gz\", fileobj=BytesIO(response.content)\n                ) as archive:\n                    archive.extractall(output_directory)\n\n\nexcept ModuleNotFoundError:\n    log.error(\n        \"\\nInstallation of the contrib extra is required to use pyhf.contrib.utils.download\"\n        + \"\\nPlease install with: python -m pip install pyhf[contrib]\\n\",\n        exc_info=True,\n    )\n", "path": "src/pyhf/contrib/utils.py"}], "after_files": [{"content": "\"\"\"Helper utilities for common tasks.\"\"\"\n\nfrom urllib.parse import urlparse\nimport tarfile\nfrom io import BytesIO\nimport logging\nfrom .. import exceptions\n\nlog = logging.getLogger(__name__)\n\n__all__ = [\"download\"]\n\n\ndef __dir__():\n    return __all__\n\n\ntry:\n    import requests\n\n    def download(archive_url, output_directory, force=False, compress=False):\n        \"\"\"\n        Download the patchset archive from the remote URL and extract it in a\n        directory at the path given.\n\n        Example:\n\n            >>> from pyhf.contrib.utils import download\n            >>> download(\"https://doi.org/10.17182/hepdata.90607.v3/r3\", \"1Lbb-likelihoods\")\n            >>> import os\n            >>> sorted(os.listdir(\"1Lbb-likelihoods\"))\n            ['BkgOnly.json', 'README.md', 'patchset.json']\n            >>> download(\"https://doi.org/10.17182/hepdata.90607.v3/r3\", \"1Lbb-likelihoods.tar.gz\", compress=True)\n            >>> import glob\n            >>> glob.glob(\"1Lbb-likelihoods.tar.gz\")\n            ['1Lbb-likelihoods.tar.gz']\n\n        Args:\n            archive_url (:obj:`str`): The URL of the :class:`~pyhf.patchset.PatchSet` archive to download.\n            output_directory (:obj:`str`): Name of the directory to unpack the archive into.\n            force (:obj:`bool`): Force download from non-approved host. Default is ``False``.\n            compress (:obj:`bool`): Keep the archive in a compressed ``tar.gz`` form. Default is ``False``.\n\n        Raises:\n            :class:`~pyhf.exceptions.InvalidArchiveHost`: if the provided archive host name is not known to be valid\n        \"\"\"\n        if not force:\n            valid_hosts = [\"www.hepdata.net\", \"doi.org\"]\n            netloc = urlparse(archive_url).netloc\n            if netloc not in valid_hosts:\n                raise exceptions.InvalidArchiveHost(\n                    f\"{netloc} is not an approved archive host: {', '.join(str(host) for host in valid_hosts)}\\n\"\n                    + \"To download an archive from this host use the --force option.\"\n                )\n\n        with requests.get(archive_url) as response:\n            if compress:\n                with open(output_directory, \"wb\") as archive:\n                    archive.write(response.content)\n            else:\n                with tarfile.open(\n                    mode=\"r|gz\", fileobj=BytesIO(response.content)\n                ) as archive:\n                    archive.extractall(output_directory)\n\n\nexcept ModuleNotFoundError:\n    log.error(\n        \"\\nInstallation of the contrib extra is required to use pyhf.contrib.utils.download\"\n        + \"\\nPlease install with: python -m pip install pyhf[contrib]\\n\",\n        exc_info=True,\n    )\n", "path": "src/pyhf/contrib/utils.py"}]}