Skip to content

Commit 18d88b8

Browse files
feat: add verbose mode (#1638)
* feat: add verbose mode * lint * fix test * fix tests --------- Co-authored-by: carlosmiei <[email protected]>
1 parent 0ac6d89 commit 18d88b8

File tree

11 files changed

+589
-11
lines changed

11 files changed

+589
-11
lines changed

binance/async_client.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,20 @@ def __init__(
3838
private_key_pass: Optional[str] = None,
3939
https_proxy: Optional[str] = None,
4040
time_unit: Optional[str] = None,
41+
verbose: bool = False,
4142
):
4243
self.https_proxy = https_proxy
4344
self.loop = loop or get_loop()
4445
self._session_params: Dict[str, Any] = session_params or {}
45-
46+
4647
# Convert https_proxy to requests_params format for BaseClient
4748
if https_proxy and requests_params is None:
4849
requests_params = {'proxies': {'http': https_proxy, 'https': https_proxy}}
4950
elif https_proxy and requests_params is not None:
5051
if 'proxies' not in requests_params:
5152
requests_params['proxies'] = {}
5253
requests_params['proxies'].update({'http': https_proxy, 'https': https_proxy})
53-
54+
5455
super().__init__(
5556
api_key,
5657
api_secret,
@@ -62,6 +63,7 @@ def __init__(
6263
private_key,
6364
private_key_pass,
6465
time_unit=time_unit,
66+
verbose=verbose,
6567
)
6668

6769
@classmethod
@@ -80,6 +82,7 @@ async def create(
8082
private_key_pass: Optional[str] = None,
8183
https_proxy: Optional[str] = None,
8284
time_unit: Optional[str] = None,
85+
verbose: bool = False,
8386
):
8487
self = cls(
8588
api_key,
@@ -94,7 +97,8 @@ async def create(
9497
private_key,
9598
private_key_pass,
9699
https_proxy,
97-
time_unit
100+
time_unit,
101+
verbose
98102
)
99103
self.https_proxy = https_proxy # move this to the constructor
100104

@@ -177,6 +181,20 @@ async def _request(
177181
**kwargs,
178182
) as response:
179183
self.response = response
184+
185+
if self.verbose:
186+
response_text = await response.text()
187+
self.logger.debug(
188+
"\nRequest: %s %s\nRequestHeaders: %s\nRequestBody: %s\nResponse: %s\nResponseHeaders: %s\nResponseBody: %s",
189+
method.upper(),
190+
uri,
191+
headers,
192+
data,
193+
response.status,
194+
dict(response.headers),
195+
response_text[:1000] if response_text else None
196+
)
197+
180198
return await self._handle_response(response)
181199

182200
async def _handle_response(self, response: aiohttp.ClientResponse):

binance/base_client.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import asyncio
77
import hashlib
88
import hmac
9+
import logging
910
import time
1011
from Crypto.PublicKey import RSA, ECC
1112
from Crypto.Hash import SHA256
@@ -167,6 +168,7 @@ def __init__(
167168
private_key_pass: Optional[str] = None,
168169
loop: Optional[asyncio.AbstractEventLoop] = None,
169170
time_unit: Optional[str] = None,
171+
verbose: bool = False,
170172
):
171173
"""Binance API Client constructor
172174
@@ -184,10 +186,19 @@ def __init__(
184186
:type private_key_pass: optional - str
185187
:param time_unit: Time unit to use for requests. Supported values: "MILLISECOND", "MICROSECOND"
186188
:type time_unit: optional - str
189+
:param verbose: Enable verbose logging for debugging
190+
:type verbose: bool
187191
188192
"""
189193

190194
self.tld = tld
195+
self.verbose = verbose
196+
self.logger = logging.getLogger(__name__)
197+
198+
# Set logger level based on verbose flag
199+
# Users can override this by configuring logging externally
200+
if verbose:
201+
self.logger.setLevel(logging.DEBUG)
191202
self.API_URL = self.API_URL.format(base_endpoint, tld)
192203
self.MARGIN_API_URL = self.MARGIN_API_URL.format(base_endpoint, tld)
193204
self.WEBSITE_URL = self.WEBSITE_URL.format(tld)

binance/client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(
3434
private_key_pass: Optional[str] = None,
3535
ping: Optional[bool] = True,
3636
time_unit: Optional[str] = None,
37+
verbose: bool = False,
3738
):
3839
super().__init__(
3940
api_key,
@@ -46,6 +47,7 @@ def __init__(
4647
private_key,
4748
private_key_pass,
4849
time_unit=time_unit,
50+
verbose=verbose,
4951
)
5052

5153
# init DNS and SSL cert
@@ -88,6 +90,19 @@ def _request(
8890
data = f"{url_encoded_data}&signature={signature}"
8991

9092
self.response = getattr(self.session, method)(uri, headers=headers, data=data, **kwargs)
93+
94+
if self.verbose:
95+
self.logger.debug(
96+
"\nRequest: %s %s\nRequestHeaders: %s\nRequestBody: %s\nResponse: %s\nResponseHeaders: %s\nResponseBody: %s",
97+
method.upper(),
98+
uri,
99+
headers,
100+
data,
101+
self.response.status_code,
102+
dict(self.response.headers),
103+
self.response.text[:1000] if self.response.text else None
104+
)
105+
91106
return self._handle_response(self.response)
92107

93108
@staticmethod

binance/ws/streams.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import time
33
from enum import Enum
44
from typing import Optional, List, Dict, Callable, Any
5+
import logging
56

67
from binance.ws.constants import KEEPALIVE_TIMEOUT
78
from binance.ws.keepalive_websocket import KeepAliveWebsocket
@@ -40,10 +41,11 @@ class BinanceSocketManager:
4041
WEBSOCKET_DEPTH_20 = "20"
4142

4243
def __init__(
43-
self,
44-
client: AsyncClient,
44+
self,
45+
client: AsyncClient,
4546
user_timeout=KEEPALIVE_TIMEOUT,
4647
max_queue_size: int = 100,
48+
verbose: bool = False,
4749
):
4850
"""Initialise the BinanceSocketManager
4951
@@ -52,6 +54,8 @@ def __init__(
5254
:param user_timeout: Timeout for user socket in seconds
5355
:param max_queue_size: Max size of the websocket queue, defaults to 100
5456
:type max_queue_size: int
57+
:param verbose: Enable verbose logging for WebSocket connections
58+
:type verbose: bool
5559
"""
5660
self.STREAM_URL = self.STREAM_URL.format(client.tld)
5761
self.FSTREAM_URL = self.FSTREAM_URL.format(client.tld)
@@ -65,8 +69,12 @@ def __init__(
6569
self.testnet = self._client.testnet
6670
self.demo = self._client.demo
6771
self._max_queue_size = max_queue_size
72+
self.verbose = verbose
6873
self.ws_kwargs = {}
6974

75+
if verbose:
76+
logging.getLogger('binance.ws').setLevel(logging.DEBUG)
77+
7078
def _get_stream_url(self, stream_url: Optional[str] = None):
7179
if stream_url:
7280
return stream_url
@@ -872,7 +880,7 @@ def multiplex_socket(self, streams: List[str]):
872880

873881
def options_multiplex_socket(self, streams: List[str]):
874882
"""Start a multiplexed socket using a list of socket names.
875-
883+
876884
https://developers.binance.com/docs/derivatives/option/websocket-market-streams
877885
878886
"""
@@ -967,7 +975,6 @@ def margin_socket(self):
967975
stream_url = self.STREAM_DEMO_URL
968976
return self._get_account_socket("margin", stream_url=stream_url)
969977

970-
971978
def futures_socket(self):
972979
"""Start a websocket for futures data
973980
@@ -1041,7 +1048,7 @@ def options_ticker_socket(self, symbol: str):
10411048
10421049
API Reference: https://developers.binance.com/docs/derivatives/option/websocket-market-streams/24-hour-TICKER
10431050
1044-
Stream provides real-time 24hr ticker information for all symbols. Only symbols whose ticker info
1051+
Stream provides real-time 24hr ticker information for all symbols. Only symbols whose ticker info
10451052
changed will be sent. Updates every 1000ms.
10461053
10471054
:param symbol: The option symbol to subscribe to (e.g. "BTC-220930-18000-C")
@@ -1066,7 +1073,7 @@ def options_ticker_by_expiration_socket(self, symbol: str, expiration_date: str)
10661073

10671074
def options_recent_trades_socket(self, symbol: str):
10681075
"""Subscribe to a real-time trade information stream.
1069-
1076+
10701077
API Reference: https://developers.binance.com/docs/derivatives/option/websocket-market-streams/Trade-Streams
10711078
10721079
Stream pushes raw trade information for a specific symbol or underlying asset.
@@ -1081,7 +1088,7 @@ def options_kline_socket(
10811088
self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE
10821089
):
10831090
"""Subscribe to a Kline/Candlestick data stream.
1084-
1091+
10851092
API Reference: https://developers.binance.com/docs/derivatives/option/websocket-market-streams/Kline-Candlestick-Streams
10861093
10871094
Stream pushes updates to the current klines/candlestick every 1000ms (if existing).

binance/ws/threaded_stream.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,28 @@ def __init__(
1818
session_params: Optional[Dict[str, Any]] = None,
1919
https_proxy: Optional[str] = None,
2020
_loop: Optional[asyncio.AbstractEventLoop] = None,
21+
verbose: bool = False,
2122
):
22-
"""Initialise the BinanceSocketManager"""
23+
"""Initialise the ThreadedApiManager
24+
25+
:param api_key: Binance API key
26+
:param api_secret: Binance API secret
27+
:param requests_params: optional - Dictionary of requests params
28+
:param tld: optional - Top level domain, default is 'com'
29+
:param testnet: optional - Use testnet endpoint
30+
:param session_params: optional - Session params for aiohttp
31+
:param https_proxy: optional - Proxy URL
32+
:param _loop: optional - Event loop
33+
:param verbose: Enable verbose logging for WebSocket connections
34+
:type verbose: bool
35+
"""
2336
super().__init__()
2437
self._loop: asyncio.AbstractEventLoop = get_loop() if _loop is None else _loop
2538
self._client: Optional[AsyncClient] = None
2639
self._running: bool = True
2740
self._socket_running: Dict[str, bool] = {}
2841
self._log = logging.getLogger(__name__)
42+
self.verbose = verbose
2943
self._client_params = {
3044
"api_key": api_key,
3145
"api_secret": api_secret,
@@ -34,8 +48,12 @@ def __init__(
3448
"testnet": testnet,
3549
"session_params": session_params,
3650
"https_proxy": https_proxy,
51+
"verbose": verbose,
3752
}
3853

54+
if verbose:
55+
logging.getLogger('binance.ws').setLevel(logging.DEBUG)
56+
3957
async def _before_socket_listener_start(self): ...
4058

4159
async def socket_listener(self):

docs/faqs.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,15 @@ Check recvWindow is an integer and not a string.
2020
*A2*: You may need to regenerate your API Key and Secret
2121

2222
*A3*: You may be attempting to access the API from a Chinese IP address, these are now restricted by Binance.
23+
24+
*Q: How can I debug API issues?*
25+
26+
*A*: Enable verbose mode to see detailed request and response information:
27+
28+
.. code:: python
29+
30+
client = Client(api_key, api_secret, verbose=True)
31+
32+
This will log all HTTP requests and responses, including headers, body, and status codes. This is particularly helpful for debugging authentication issues, understanding API behavior, and troubleshooting network problems.
33+
34+
See the Logging section in the `Getting Started guide <overview.html#verbose-mode>`_ for more details.

0 commit comments

Comments
 (0)