Skip to content

Commit

Permalink
support report libname and libver to Redis
Browse files Browse the repository at this point in the history
  • Loading branch information
ztxiuyuan committed Apr 13, 2023
1 parent e1017fd commit 1fe8055
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 3 deletions.
17 changes: 17 additions & 0 deletions redis/asyncio/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import copy
import inspect
import re
import sys
import warnings
from typing import (
TYPE_CHECKING,
Expand Down Expand Up @@ -59,6 +60,11 @@
from redis.typing import ChannelT, EncodableT, KeyT
from redis.utils import safe_str, str_if_bytes

if sys.version_info >= (3, 8):
from importlib import metadata
else:
import importlib_metadata as metadata

PubSubHandler = Callable[[Dict[str, str]], Awaitable[None]]
_KeyT = TypeVar("_KeyT", bound=KeyT)
_ArgT = TypeVar("_ArgT", KeyT, EncodableT)
Expand All @@ -67,6 +73,13 @@
if TYPE_CHECKING:
from redis.commands.core import Script

# default libname and libver
try:
LIBVER = metadata.version("redis")
except metadata.PackageNotFoundError:
LIBVER = "99.99.99"
LIBNAME = "redis-py"


class ResponseCallbackProtocol(Protocol):
def __call__(self, response: Any, **kwargs):
Expand Down Expand Up @@ -171,6 +184,8 @@ def __init__(
single_connection_client: bool = False,
health_check_interval: int = 0,
client_name: Optional[str] = None,
lib_name: str = LIBNAME,
lib_ver: str = LIBVER,
username: Optional[str] = None,
retry: Optional[Retry] = None,
auto_close_connection_pool: bool = True,
Expand Down Expand Up @@ -212,6 +227,8 @@ def __init__(
"max_connections": max_connections,
"health_check_interval": health_check_interval,
"client_name": client_name,
"lib_name": lib_name,
"lib_ver": lib_ver,
"redis_connect_func": redis_connect_func,
}
# based on input, setup appropriate connection args
Expand Down
19 changes: 18 additions & 1 deletion redis/asyncio/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ class Connection:
"db",
"username",
"client_name",
"lib_name",
"lib_ver",
"credential_provider",
"password",
"socket_timeout",
Expand Down Expand Up @@ -503,6 +505,8 @@ def __init__(
socket_read_size: int = 65536,
health_check_interval: float = 0,
client_name: Optional[str] = None,
lib_name: Optional[str] = None,
lib_ver: Optional[str] = None,
username: Optional[str] = None,
retry: Optional[Retry] = None,
redis_connect_func: Optional[ConnectCallbackT] = None,
Expand All @@ -521,6 +525,8 @@ def __init__(
self.port = int(port)
self.db = db
self.client_name = client_name
self.lib_name = lib_name
self.lib_ver = lib_ver
self.credential_provider = credential_provider
self.password = password
self.username = username
Expand Down Expand Up @@ -717,7 +723,18 @@ async def on_connect(self) -> None:
await self.send_command("CLIENT", "SETNAME", self.client_name)
if str_if_bytes(await self.read_response()) != "OK":
raise ConnectionError("Error setting client name")

if self.lib_name:
await self.send_command("CLIENT", "SETINFO", "LIB-NAME", self.lib_name)
try:
await self.read_response()
except:
pass
if self.lib_ver:
await self.send_command("CLIENT", "SETINFO", "LIB-VER", self.lib_ver)
try:
await self.read_response()
except:
pass
# if a database is specified, switch to it
if self.db:
await self.send_command("SELECT", self.db)
Expand Down
18 changes: 18 additions & 0 deletions redis/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import copy
import datetime
import re
import sys
import threading
import time
import warnings
Expand Down Expand Up @@ -29,12 +30,24 @@
from redis.retry import Retry
from redis.utils import safe_str, str_if_bytes

if sys.version_info >= (3, 8):
from importlib import metadata
else:
import importlib_metadata as metadata

SYM_EMPTY = b""
EMPTY_RESPONSE = "EMPTY_RESPONSE"

# some responses (ie. dump) are binary, and just meant to never be decoded
NEVER_DECODE = "NEVER_DECODE"

# default libname and libver
try:
LIBVER = metadata.version("redis")
except metadata.PackageNotFoundError:
LIBVER = "99.99.99"
LIBNAME = "redis-py"


def timestamp_to_datetime(response):
"Converts a unix timestamp to a Python datetime object"
Expand Down Expand Up @@ -745,6 +758,7 @@ class AbstractRedis:
"CLIENT LIST": parse_client_list,
"CLIENT INFO": parse_client_info,
"CLIENT SETNAME": bool_ok,
"CLIENT SETINFO": bool_ok,
"CLIENT UNBLOCK": lambda r: r and int(r) == 1 or False,
"CLIENT PAUSE": bool_ok,
"CLIENT GETREDIR": int,
Expand Down Expand Up @@ -938,6 +952,8 @@ def __init__(
single_connection_client=False,
health_check_interval=0,
client_name=None,
lib_name=LIBNAME,
lib_ver=LIBVER,
username=None,
retry=None,
redis_connect_func=None,
Expand Down Expand Up @@ -988,6 +1004,8 @@ def __init__(
"max_connections": max_connections,
"health_check_interval": health_check_interval,
"client_name": client_name,
"lib_name": lib_name,
"lib_ver": lib_ver,
"redis_connect_func": redis_connect_func,
"credential_provider": credential_provider,
}
Expand Down
1 change: 1 addition & 0 deletions redis/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class AbstractRedisCluster:
"AUTH",
"CLIENT LIST",
"CLIENT SETNAME",
"CLIENT SETINFO",
"CLIENT GETNAME",
"CONFIG SET",
"CONFIG REWRITE",
Expand Down
8 changes: 8 additions & 0 deletions redis/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,14 @@ def client_setname(self, name: str, **kwargs) -> ResponseT:
"""
return self.execute_command("CLIENT SETNAME", name, **kwargs)

def client_setinfo(self, attr: str, value: str, **kwargs) -> ResponseT:
"""
Sets the current connection libname
For mor information see https://redis.io/commands/client-setinfo
"""
return self.execute_command("CLIENT SETINFO", attr, value)

def client_unblock(
self, client_id: int, error: bool = False, **kwargs
) -> ResponseT:
Expand Down
17 changes: 16 additions & 1 deletion redis/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,8 @@ def __init__(
socket_read_size=65536,
health_check_interval=0,
client_name=None,
lib_name=None,
lib_ver=None,
username=None,
retry=None,
redis_connect_func=None,
Expand All @@ -623,6 +625,8 @@ def __init__(
self.pid = os.getpid()
self.db = db
self.client_name = client_name
self.lib_name = lib_name
self.lib_ver = lib_ver
self.credential_provider = credential_provider
self.password = password
self.username = username
Expand Down Expand Up @@ -768,7 +772,18 @@ def on_connect(self):
self.send_command("CLIENT", "SETNAME", self.client_name)
if str_if_bytes(self.read_response()) != "OK":
raise ConnectionError("Error setting client name")

if self.lib_name:
self.send_command("CLIENT", "SETINFO", "LIB-NAME", self.lib_name)
try:
self.read_response()
except:
pass
if self.lib_ver:
self.send_command("CLIENT", "SETINFO", "LIB-VERSION", self.lib_ver)
try:
self.read_response()
except:
pass
# if a database is specified, switch to it
if self.db:
self.send_command("SELECT", self.db)
Expand Down
8 changes: 8 additions & 0 deletions tests/test_asyncio/test_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,14 @@ async def test_client_setname(self, r: RedisCluster) -> None:
client_name = await r.client_getname(target_nodes=node)
assert client_name == "redis_py_test"

async def test_client_setinfo(self, r: RedisCluster) -> None:
node = r.get_random_node()
await r.client_setinfo("lib-name", "redis-py", target_nodes=node)
await r.client_setinfo("lib-ver", "4.33", target_nodes=node)
info = await r.client_info(target_nodes=node)
assert "lib-name" in info
assert "lib-ver" in info

async def test_exists(self, r: RedisCluster) -> None:
d = {"a": b"1", "b": b"2", "c": b"3", "d": b"4"}
await r.mset_nonatomic(d)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_asyncio/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,15 @@ async def test_client_setname(self, r: redis.Redis):
assert await r.client_setname("redis_py_test")
assert await r.client_getname() == "redis_py_test"

@skip_if_server_version_lt("7.2.0")
@pytest.mark.onlynoncluster
async def test_client_setinfo(self, r:redis.Redis):
assert await r.client_setinfo("lib-name", "redis-py")
assert await r.client_setinfo("lib-ver", "4.33")
info = await r.client_info()
assert "lib-name" in info
assert "lib-ver" in info

@skip_if_server_version_lt("2.6.9")
@pytest.mark.onlynoncluster
async def test_client_kill(self, r: redis.Redis, r2):
Expand Down Expand Up @@ -438,6 +447,14 @@ async def test_client_list_after_client_setname(self, r: redis.Redis):
# we don't know which client ours will be
assert "redis_py_test" in [c["name"] for c in clients]

@skip_if_server_version_lt("7.2.0")
async def test_client_list_after_client_setinfo(self, r: redis.Redis):
await r.client_setinfo("lib-name", "redis-py")
await r.client_setinfo("lib-ver", "4.33")
clients = await r.client_list()
assert "redis-py" in [c["lib-name"] for c in clients]
assert "4.33" in [c["lib-ver"] for c in clients]

@skip_if_server_version_lt("2.9.50")
@pytest.mark.onlynoncluster
async def test_client_pause(self, r: redis.Redis):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -2147,7 +2147,7 @@ def teardown():
user_client.hset("{cache}:0", "hkey", "hval")

assert isinstance(r.acl_log(target_nodes=node), list)
assert len(r.acl_log(target_nodes=node)) == 2
assert len(r.acl_log(target_nodes=node)) == 3
assert len(r.acl_log(count=1, target_nodes=node)) == 1
assert isinstance(r.acl_log(target_nodes=node)[0], dict)
assert "client-info" in r.acl_log(count=1, target_nodes=node)[0]
Expand Down
17 changes: 17 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,15 @@ def test_client_setname(self, r):
assert r.client_setname("redis_py_test")
assert r.client_getname() == "redis_py_test"

@pytest.mark.onlynoncluster
@skip_if_server_version_lt("7.2.0")
def test_client_setinfo(self, r):
assert r.client_setinfo("lib-name", "redis-py")
assert r.client_setinfo("lib-ver", "4.33")
info = r.client_info()
assert "lib-name" in info
assert "lib-ver" in info

@pytest.mark.onlynoncluster
@skip_if_server_version_lt("2.6.9")
def test_client_kill(self, r, r2):
Expand Down Expand Up @@ -628,6 +637,14 @@ def test_client_list_after_client_setname(self, r):
# we don't know which client ours will be
assert "redis_py_test" in [c["name"] for c in clients]

@skip_if_server_version_lt("7.2.0")
def test_client_list_after_client_setinfo(self, r):
r.client_setinfo("lib-name", "redis-py")
r.client_setinfo("lib-ver", "4.33")
clients = r.client_list()
assert "redis-py" in [c["lib-name"] for c in clients]
assert "4.33" in [c["lib-ver"] for c in clients]

@skip_if_server_version_lt("6.2.0")
def test_client_kill_filter_by_laddr(self, r, r2):
r.client_setname("redis-py-c1")
Expand Down

0 comments on commit 1fe8055

Please sign in to comment.