Repository: slackapi/python-slack-sdk
Pull request #1671 (2025-03-13 18:32:35)

feat: WebClient/AsyncWebClient expose logger property
## Summary

This PR exposes the logger of `WebClient` and `AsyncWebClient` as a property. 
This will be used in Bolt to resolve https://github.com/slackapi/bolt-python/issues/1255, it will allow the reuse of the logger [when copying](https://github.com/slackapi/bolt-python/blob/main/slack_bolt/app/app.py#L1367C1-L1385C10) the `WebClient`

### Testing

```
client = WebClient(token="my_token")

client.logger.info("hello world")
```

### Category <!-- place an `x` in each of the `[ ]`  -->

- [x] **slack_sdk.web.WebClient (sync/async)** (Web API client)
- [ ] **slack_sdk.webhook.WebhookClient (sync/async)** (Incoming Webhook, response_url sender)
- [ ] **slack_sdk.socket_mode** (Socket Mode client)
- [ ] **slack_sdk.signature** (Request Signature Verifier)
- [ ] **slack_sdk.oauth** (OAuth Flow Utilities)
- [ ] **slack_sdk.models** (UI component builders)
- [ ] **slack_sdk.scim** (SCIM API client)
- [ ] **slack_sdk.audit_logs** (Audit Logs API client)
- [ ] **slack_sdk.rtm_v2** (RTM client)
- [ ] `/docs` (Documents)
- [ ] `/tutorial` (PythOnBoardingBot tutorial)
- [ ] `tests`/`integration_tests` (Automated tests for this library)

## Requirements <!-- place an `x` in each `[ ]` -->

- [x] I've read and understood the [Contributing Guidelines](https://github.com/slackapi/python-slack-sdk/blob/main/.github/contributing.md) and have done my best effort to follow them.
- [x] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
- [x] I've run `python3 -m venv .venv && source .venv/bin/activate && ./scripts/run_validation.sh` after making the changes.


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1671?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 85.33%. Comparing base [(`897449a`)](https://app.codecov.io/gh/slackapi/python-slack-sdk/commit/897449acec0a810dd4a460008d22554ffcdcdd46?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) to head [(`206bfa2`)](https://app.codecov.io/gh/slackapi/python-slack-sdk/commit/206bfa20fb48b03faac7bc83999b5063d468b7f2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi).
> Report is 1 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1671      +/-   ##
==========================================
- Coverage   85.36%   85.33%   -0.03%     
==========================================
  Files         113      113              
  Lines       12802    12808       +6     
==========================================
+ Hits        10928    10930       +2     
- Misses       1874     1878       +4     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1671?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi).

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/slack_sdk/web/async_base_client.py b/slack_sdk/web/async_base_client.py
index 22f93f5..ebb0eb3 100644
--- a/slack_sdk/web/async_base_client.py
+++ b/slack_sdk/web/async_base_client.py
@@ -88,6 +88,17 @@ class AsyncBaseClient:
             if env_variable is not None:
                 self.proxy = env_variable
 
+    # -------------------------
+    # accessors
+
+    @property
+    def logger(self) -> logging.Logger:
+        """The logger this client uses."""
+        return self._logger
+
+    # -------------------------
+    # api call
+
     async def api_call(
         self,
         api_method: str,
diff --git a/slack_sdk/web/base_client.py b/slack_sdk/web/base_client.py
index f3c8f93..6c3714a 100644
--- a/slack_sdk/web/base_client.py
+++ b/slack_sdk/web/base_client.py
@@ -92,6 +92,17 @@ class BaseClient:
             if env_variable is not None:
                 self.proxy = env_variable
 
+    # -------------------------
+    # accessors
+
+    @property
+    def logger(self) -> logging.Logger:
+        """The logger this client uses."""
+        return self._logger
+
+    # -------------------------
+    # api call
+
     def api_call(
         self,
         api_method: str,


Test patch:
diff --git a/tests/slack_sdk/web/test_web_client_logger.py b/tests/slack_sdk/web/test_web_client_logger.py
new file mode 100644
index 0000000..3a6e033
--- /dev/null
+++ b/tests/slack_sdk/web/test_web_client_logger.py
@@ -0,0 +1,38 @@
+import logging
+import unittest
+
+from slack_sdk import WebClient
+from slack_sdk.web import base_client
+from tests.slack_sdk.web.mock_web_api_handler import MockHandler
+from tests.mock_web_api_server import setup_mock_web_api_server, cleanup_mock_web_api_server
+
+
+class TestWebClientLogger(unittest.TestCase):
+    test_logger: logging.Logger
+
+    def setUp(self):
+        self.test_logger = logging.Logger("test-logger")
+        setup_mock_web_api_server(self, MockHandler)
+
+    def tearDown(self):
+        cleanup_mock_web_api_server(self)
+
+    def test_logger_property_returns_default_logger(self):
+        client = WebClient(base_url="http://localhost:8888", token="xoxb-api_test")
+        self.assertEqual(client.logger.name, base_client.__name__)
+
+    def test_logger_property_returns_custom_logger(self):
+        client = WebClient(
+            base_url="http://localhost:8888",
+            token="xoxb-api_test",
+            logger=self.test_logger,
+        )
+        self.assertEqual(client.logger, self.test_logger)
+
+    def test_logger_property_has_no_setter(self):
+        client = WebClient(
+            base_url="http://localhost:8888",
+            token="xoxb-api_test",
+        )
+        with self.assertRaises(AttributeError):
+            client.logger = self.test_logger
diff --git a/tests/slack_sdk_async/web/test_async_web_client_logger.py b/tests/slack_sdk_async/web/test_async_web_client_logger.py
new file mode 100644
index 0000000..c1b7c06
--- /dev/null
+++ b/tests/slack_sdk_async/web/test_async_web_client_logger.py
@@ -0,0 +1,38 @@
+import logging
+import unittest
+
+from slack_sdk.web.async_client import AsyncWebClient
+from slack_sdk.web import async_base_client
+from tests.slack_sdk.web.mock_web_api_handler import MockHandler
+from tests.mock_web_api_server import setup_mock_web_api_server_async, cleanup_mock_web_api_server_async
+
+
+class TestAsyncWebClientLogger(unittest.TestCase):
+    test_logger: logging.Logger
+
+    def setUp(self):
+        self.test_logger = logging.Logger("test-logger")
+        setup_mock_web_api_server_async(self, MockHandler)
+
+    def tearDown(self):
+        cleanup_mock_web_api_server_async(self)
+
+    def test_logger_property_returns_default_logger(self):
+        client = AsyncWebClient(base_url="http://localhost:8888", token="xoxb-api_test")
+        self.assertEqual(client.logger.name, async_base_client.__name__)
+
+    def test_logger_property_returns_custom_logger(self):
+        client = AsyncWebClient(
+            base_url="http://localhost:8888",
+            token="xoxb-api_test",
+            logger=self.test_logger,
+        )
+        self.assertEqual(client.logger, self.test_logger)
+
+    def test_logger_property_has_no_setter(self):
+        client = AsyncWebClient(
+            base_url="http://localhost:8888",
+            token="xoxb-api_test",
+        )
+        with self.assertRaises(AttributeError):
+            client.logger = self.test_logger