From 345897283509259646848bf71e3f38a8f63e4abf Mon Sep 17 00:00:00 2001 From: AhmadMasry Date: Sat, 18 Jan 2025 01:20:30 +0200 Subject: [PATCH 1/6] feat: Add Valkey instrumentation support Add support for Valkey instrumentation --- .github/COMMIT_TEMPLATE.txt | 2 +- .riot/requirements/b96b665.txt | 21 + ddtrace/_monkey.py | 1 + ddtrace/_trace/trace_handlers.py | 8 + ddtrace/_trace/utils_valkey.py | 96 +++ .../contrib/internal/valkey/asyncio_patch.py | 36 + ddtrace/contrib/internal/valkey/patch.py | 155 +++++ ddtrace/contrib/trace_utils_valkey.py | 18 + ddtrace/contrib/valkey/__init__.py | 84 +++ ddtrace/contrib/valkey/asyncio_patch.py | 14 + ddtrace/contrib/valkey/patch.py | 14 + ddtrace/contrib/valkey_utils.py | 84 +++ ddtrace/ext/__init__.py | 2 + ddtrace/ext/valkey.py | 14 + docker-compose.yml | 30 + docs/index.rst | 2 + docs/integrations.rst | 7 + docs/spelling_wordlist.txt | 1 + min_compatible_versions.csv | 1 + riotfile.py | 10 + supported_versions_output.json | 6 + supported_versions_table.csv | 1 + tests/contrib/config.py | 10 + tests/contrib/suitespec.yml | 22 + tests/contrib/valkey/__init__.py | 0 tests/contrib/valkey/test_valkey.py | 617 ++++++++++++++++++ tests/contrib/valkey/test_valkey_asyncio.py | 221 +++++++ tests/contrib/valkey/test_valkey_cluster.py | 209 ++++++ .../valkey/test_valkey_cluster_asyncio.py | 457 +++++++++++++ tests/contrib/valkey/test_valkey_patch.py | 31 + ....test_valkey.test_analytics_with_rate.json | 38 ++ ...st_valkey.test_analytics_without_rate.json | 38 ++ ...ontrib.valkey.test_valkey.test_basics.json | 37 ++ ...ey.test_valkey.test_custom_cmd_length.json | 37 ++ ...est_valkey.test_custom_cmd_length_env.json | 37 ++ ...est_env_user_specified_valkey_service.json | 74 +++ ....test_full_command_in_resource_config.json | 71 ++ ...key.test_full_command_in_resource_env.json | 71 ++ ....valkey.test_valkey.test_long_command.json | 37 ++ ...valkey.test_valkey.test_meta_override.json | 38 ++ ...b.valkey.test_valkey.test_opentracing.json | 56 ++ ...y.test_valkey.test_pipeline_immediate.json | 72 ++ ...lkey.test_valkey.test_pipeline_traced.json | 36 + ...y.test_valkey.test_service_precedence.json | 37 ++ ...ntrib.valkey.test_valkey.test_unicode.json | 37 ++ ...st_valkey.test_user_specified_service.json | 37 ++ ...est_valkey_asyncio.test_basic_request.json | 37 ++ ....test_valkey_asyncio.test_client_name.json | 57 ++ ..._valkey_asyncio.test_connection_error.json | 40 ++ ...y_asyncio.test_decoding_non_utf8_args.json | 73 +++ ....test_decoding_non_utf8_pipeline_args.json | 36 + ...test_valkey_asyncio.test_long_command.json | 37 ++ ...ey_asyncio.test_override_service_name.json | 110 ++++ ...ey.test_valkey_asyncio.test_parenting.json | 85 +++ ...b.valkey.test_valkey_asyncio.test_pin.json | 37 ++ ...t_valkey_asyncio.test_pipeline_traced.json | 36 + ...ne_traced_context_manager_transaction.json | 36 + ...key_asyncio.test_two_traced_pipelines.json | 84 +++ ...t_valkey_asyncio.test_unicode_request.json | 37 ++ 59 files changed, 3631 insertions(+), 1 deletion(-) create mode 100644 .riot/requirements/b96b665.txt create mode 100644 ddtrace/_trace/utils_valkey.py create mode 100644 ddtrace/contrib/internal/valkey/asyncio_patch.py create mode 100644 ddtrace/contrib/internal/valkey/patch.py create mode 100644 ddtrace/contrib/trace_utils_valkey.py create mode 100644 ddtrace/contrib/valkey/__init__.py create mode 100644 ddtrace/contrib/valkey/asyncio_patch.py create mode 100644 ddtrace/contrib/valkey/patch.py create mode 100644 ddtrace/contrib/valkey_utils.py create mode 100644 ddtrace/ext/valkey.py create mode 100644 tests/contrib/valkey/__init__.py create mode 100644 tests/contrib/valkey/test_valkey.py create mode 100644 tests/contrib/valkey/test_valkey_asyncio.py create mode 100644 tests/contrib/valkey/test_valkey_cluster.py create mode 100644 tests/contrib/valkey/test_valkey_cluster_asyncio.py create mode 100644 tests/contrib/valkey/test_valkey_patch.py create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json create mode 100644 tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json diff --git a/.github/COMMIT_TEMPLATE.txt b/.github/COMMIT_TEMPLATE.txt index f6e418cc2e8..55dc46d5378 100644 --- a/.github/COMMIT_TEMPLATE.txt +++ b/.github/COMMIT_TEMPLATE.txt @@ -29,5 +29,5 @@ feat/fix/docs/refactor/ci(xxx): commit title here # mysqlpython, openai, opentelemetry, opentracer, profile, psycopg, pylibmc, pymemcache, # pymongo, pymysql, pynamodb, pyodbc, pyramid, pytest, redis, rediscluster, requests, rq, # sanic, snowflake, sourcecode, sqlalchemy, starlette, stdlib, structlog, subprocess, -# telemetry, test_logging, tornado, tracer, unittest, urllib3, vendor, vertica, wsgi, +# telemetry, test_logging, tornado, tracer, unittest, urllib3, valkey, vendor, vertica, wsgi, # yaaredis diff --git a/.riot/requirements/b96b665.txt b/.riot/requirements/b96b665.txt new file mode 100644 index 00000000000..8b14d5cb8ec --- /dev/null +++ b/.riot/requirements/b96b665.txt @@ -0,0 +1,21 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/b96b665.in +# +attrs==24.3.0 +coverage[toml]==7.6.10 +hypothesis==6.45.0 +iniconfig==2.0.0 +mock==5.1.0 +opentracing==2.4.0 +packaging==24.2 +pluggy==1.5.0 +pytest==8.3.4 +pytest-asyncio==0.23.7 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +sortedcontainers==2.4.0 +valkey==6.0.2 diff --git a/ddtrace/_monkey.py b/ddtrace/_monkey.py index b93b0cb1fc4..38f2e6cadf9 100644 --- a/ddtrace/_monkey.py +++ b/ddtrace/_monkey.py @@ -105,6 +105,7 @@ "unittest": True, "coverage": False, "selenium": True, + "valkey": True, } diff --git a/ddtrace/_trace/trace_handlers.py b/ddtrace/_trace/trace_handlers.py index 7c2ba02d6b4..093d4286741 100644 --- a/ddtrace/_trace/trace_handlers.py +++ b/ddtrace/_trace/trace_handlers.py @@ -649,6 +649,11 @@ def _on_redis_command_post(ctx: core.ExecutionContext, rowcount): ctx.span.set_metric(db.ROWCOUNT, rowcount) +def _on_valkey_command_post(ctx: core.ExecutionContext, rowcount): + if rowcount is not None: + ctx.span.set_metric(db.ROWCOUNT, rowcount) + + def _on_test_visibility_enable(config) -> None: from ddtrace.internal.ci_visibility import CIVisibility @@ -758,6 +763,8 @@ def listen(): core.on("botocore.kinesis.GetRecords.post", _on_botocore_kinesis_getrecords_post) core.on("redis.async_command.post", _on_redis_command_post) core.on("redis.command.post", _on_redis_command_post) + core.on("valkey.async_command.post", _on_valkey_command_post) + core.on("valkey.command.post", _on_valkey_command_post) core.on("azure.functions.request_call_modifier", _on_azure_functions_request_span_modifier) core.on("azure.functions.start_response", _on_azure_functions_start_response) @@ -786,6 +793,7 @@ def listen(): "botocore.patched_stepfunctions_api_call", "botocore.patched_bedrock_api_call", "redis.command", + "valkey.command", "rq.queue.enqueue_job", "rq.traced_queue_fetch_job", "rq.worker.perform_job", diff --git a/ddtrace/_trace/utils_valkey.py b/ddtrace/_trace/utils_valkey.py new file mode 100644 index 00000000000..ac90070ca9d --- /dev/null +++ b/ddtrace/_trace/utils_valkey.py @@ -0,0 +1,96 @@ +""" +Some utils used by the dogtrace valkey integration +""" + +from contextlib import contextmanager +from typing import List +from typing import Optional + +from ddtrace.constants import _ANALYTICS_SAMPLE_RATE_KEY +from ddtrace.constants import SPAN_KIND +from ddtrace.constants import SPAN_MEASURED_KEY +from ddtrace.contrib import trace_utils +from ddtrace.contrib.valkey_utils import _extract_conn_tags +from ddtrace.ext import SpanKind +from ddtrace.ext import SpanTypes +from ddtrace.ext import db +from ddtrace.ext import valkey as valkeyx +from ddtrace.internal import core +from ddtrace.internal.constants import COMPONENT +from ddtrace.internal.schema import schematize_cache_operation +from ddtrace.internal.utils.formats import stringify_cache_args + + +format_command_args = stringify_cache_args + + +def _set_span_tags( + span, pin, config_integration, args: Optional[List], instance, query: Optional[List], is_cluster: bool = False +): + span.set_tag_str(SPAN_KIND, SpanKind.CLIENT) + span.set_tag_str(COMPONENT, config_integration.integration_name) + span.set_tag_str(db.SYSTEM, valkeyx.APP) + span.set_tag(SPAN_MEASURED_KEY) + if query is not None: + span_name = schematize_cache_operation(valkeyx.RAWCMD, cache_provider=valkeyx.APP) # type: ignore[operator] + span.set_tag_str(span_name, query) + if pin.tags: + span.set_tags(pin.tags) + # some valkey clients do not have a connection_pool attribute (ex. aiovalkey v1.3) + if not is_cluster and hasattr(instance, "connection_pool"): + span.set_tags(_extract_conn_tags(instance.connection_pool.connection_kwargs)) + if args is not None: + span.set_metric(valkeyx.ARGS_LEN, len(args)) + else: + for attr in ("command_stack", "_command_stack"): + if hasattr(instance, attr): + span.set_metric(valkeyx.PIPELINE_LEN, len(getattr(instance, attr))) + # set analytics sample rate if enabled + span.set_tag(_ANALYTICS_SAMPLE_RATE_KEY, config_integration.get_analytics_sample_rate()) + + +@contextmanager +def _instrument_valkey_cmd(pin, config_integration, instance, args): + query = stringify_cache_args(args, cmd_max_len=config_integration.cmd_max_length) + with core.context_with_data( + "valkey.command", + span_name=schematize_cache_operation(valkeyx.CMD, cache_provider=valkeyx.APP), + pin=pin, + service=trace_utils.ext_service(pin, config_integration), + span_type=SpanTypes.VALKEY, + resource=query.split(" ")[0] if config_integration.resource_only_command else query, + ) as ctx, ctx.span as span: + _set_span_tags(span, pin, config_integration, args, instance, query) + yield ctx + + +@contextmanager +def _instrument_valkey_execute_pipeline(pin, config_integration, cmds, instance, is_cluster=False): + cmd_string = resource = "\n".join(cmds) + if config_integration.resource_only_command: + resource = "\n".join([cmd.split(" ")[0] for cmd in cmds]) + + with pin.tracer.trace( + schematize_cache_operation(valkeyx.CMD, cache_provider=valkeyx.APP), + resource=resource, + service=trace_utils.ext_service(pin, config_integration), + span_type=SpanTypes.VALKEY, + ) as span: + _set_span_tags(span, pin, config_integration, None, instance, cmd_string) + yield span + + +@contextmanager +def _instrument_valkey_execute_async_cluster_pipeline(pin, config_integration, cmds, instance): + cmd_string = resource = "\n".join(cmds) + if config_integration.resource_only_command: + resource = "\n".join([cmd.split(" ")[0] for cmd in cmds]) + + with pin.tracer.trace( + schematize_cache_operation(valkeyx.CMD, cache_provider=valkeyx.APP), + resource=resource, + service=trace_utils.ext_service(pin, config_integration), + span_type=SpanTypes.VALKEY, + ) as span: + _set_span_tags(span, pin, config_integration, None, instance, cmd_string) + yield span diff --git a/ddtrace/contrib/internal/valkey/asyncio_patch.py b/ddtrace/contrib/internal/valkey/asyncio_patch.py new file mode 100644 index 00000000000..ef36fdd2bf4 --- /dev/null +++ b/ddtrace/contrib/internal/valkey/asyncio_patch.py @@ -0,0 +1,36 @@ +from ddtrace import config +from ddtrace._trace.utils_valkey import _instrument_valkey_cmd +from ddtrace._trace.utils_valkey import _instrument_valkey_execute_async_cluster_pipeline +from ddtrace._trace.utils_valkey import _instrument_valkey_execute_pipeline +from ddtrace.contrib.valkey_utils import _run_valkey_command_async +from ddtrace.internal.utils.formats import stringify_cache_args +from ddtrace.trace import Pin + + +async def instrumented_async_execute_command(func, instance, args, kwargs): + pin = Pin.get_from(instance) + if not pin or not pin.enabled(): + return await func(*args, **kwargs) + + with _instrument_valkey_cmd(pin, config.valkey, instance, args) as ctx: + return await _run_valkey_command_async(ctx=ctx, func=func, args=args, kwargs=kwargs) + + +async def instrumented_async_execute_pipeline(func, instance, args, kwargs): + pin = Pin.get_from(instance) + if not pin or not pin.enabled(): + return await func(*args, **kwargs) + + cmds = [stringify_cache_args(c, cmd_max_len=config.valkey.cmd_max_length) for c, _ in instance.command_stack] + with _instrument_valkey_execute_pipeline(pin, config.valkey, cmds, instance): + return await func(*args, **kwargs) + + +async def instrumented_async_execute_cluster_pipeline(func, instance, args, kwargs): + pin = Pin.get_from(instance) + if not pin or not pin.enabled(): + return await func(*args, **kwargs) + + cmds = [stringify_cache_args(c.args, cmd_max_len=config.valkey.cmd_max_length) for c in instance._command_stack] + with _instrument_valkey_execute_async_cluster_pipeline(pin, config.valkey, cmds, instance): + return await func(*args, **kwargs) diff --git a/ddtrace/contrib/internal/valkey/patch.py b/ddtrace/contrib/internal/valkey/patch.py new file mode 100644 index 00000000000..4e077376149 --- /dev/null +++ b/ddtrace/contrib/internal/valkey/patch.py @@ -0,0 +1,155 @@ +import os + +import valkey +import wrapt + +from ddtrace import config +from ddtrace._trace.utils_valkey import _instrument_valkey_cmd +from ddtrace._trace.utils_valkey import _instrument_valkey_execute_pipeline +from ddtrace.contrib.trace_utils import unwrap +from ddtrace.contrib.valkey_utils import ROW_RETURNING_COMMANDS +from ddtrace.contrib.valkey_utils import determine_row_count +from ddtrace.internal import core +from ddtrace.internal.schema import schematize_service_name +from ddtrace.internal.utils.formats import CMD_MAX_LEN +from ddtrace.internal.utils.formats import asbool +from ddtrace.internal.utils.formats import stringify_cache_args +from ddtrace.trace import Pin + + +config._add( + "valkey", + { + "_default_service": schematize_service_name("valkey"), + "cmd_max_length": int(os.getenv("DD_VALKEY_CMD_MAX_LENGTH", CMD_MAX_LEN)), + "resource_only_command": asbool(os.getenv("DD_VALKEY_RESOURCE_ONLY_COMMAND", True)), + }, +) + + +def get_version(): + # type: () -> str + return getattr(valkey, "__version__", "") + + +def patch(): + """Patch the instrumented methods + + This duplicated doesn't look nice. The nicer alternative is to use an ObjectProxy on top + of Valkey and StrictValkey. However, it means that any "import valkey.Valkey" won't be instrumented. + """ + if getattr(valkey, "_datadog_patch", False): + return + valkey._datadog_patch = True + + _w = wrapt.wrap_function_wrapper + + from .asyncio_patch import instrumented_async_execute_cluster_pipeline + from .asyncio_patch import instrumented_async_execute_command + from .asyncio_patch import instrumented_async_execute_pipeline + + _w("valkey", "Valkey.execute_command", instrumented_execute_command(config.valkey)) + _w("valkey", "Valkey.pipeline", instrumented_pipeline) + _w("valkey.client", "Pipeline.execute", instrumented_execute_pipeline(config.valkey, False)) + _w("valkey.client", "Pipeline.immediate_execute_command", instrumented_execute_command(config.valkey)) + _w("valkey.cluster", "ValkeyCluster.execute_command", instrumented_execute_command(config.valkey)) + _w("valkey.cluster", "ValkeyCluster.pipeline", instrumented_pipeline) + _w("valkey.cluster", "ClusterPipeline.execute", instrumented_execute_pipeline(config.valkey, True)) + Pin(service=None).onto(valkey.cluster.ValkeyCluster) + + _w("valkey.asyncio.client", "Valkey.execute_command", instrumented_async_execute_command) + _w("valkey.asyncio.client", "Valkey.pipeline", instrumented_pipeline) + _w("valkey.asyncio.client", "Pipeline.execute", instrumented_async_execute_pipeline) + _w("valkey.asyncio.client", "Pipeline.immediate_execute_command", instrumented_async_execute_command) + Pin(service=None).onto(valkey.asyncio.Valkey) + + _w("valkey.asyncio.cluster", "ValkeyCluster.execute_command", instrumented_async_execute_command) + _w("valkey.asyncio.cluster", "ValkeyCluster.pipeline", instrumented_pipeline) + _w("valkey.asyncio.cluster", "ClusterPipeline.execute", instrumented_async_execute_cluster_pipeline) + Pin(service=None).onto(valkey.asyncio.ValkeyCluster) + + Pin(service=None).onto(valkey.StrictValkey) + + +def unpatch(): + if getattr(valkey, "_datadog_patch", False): + valkey._datadog_patch = False + + unwrap(valkey.Valkey, "execute_command") + unwrap(valkey.Valkey, "pipeline") + unwrap(valkey.client.Pipeline, "execute") + unwrap(valkey.client.Pipeline, "immediate_execute_command") + unwrap(valkey.cluster.ValkeyCluster, "execute_command") + unwrap(valkey.cluster.ValkeyCluster, "pipeline") + unwrap(valkey.cluster.ClusterPipeline, "execute") + unwrap(valkey.asyncio.client.Valkey, "execute_command") + unwrap(valkey.asyncio.client.Valkey, "pipeline") + unwrap(valkey.asyncio.client.Pipeline, "execute") + unwrap(valkey.asyncio.client.Pipeline, "immediate_execute_command") + unwrap(valkey.asyncio.cluster.ValkeyCluster, "execute_command") + unwrap(valkey.asyncio.cluster.ValkeyCluster, "pipeline") + unwrap(valkey.asyncio.cluster.ClusterPipeline, "execute") + + +def _run_valkey_command(ctx: core.ExecutionContext, func, args, kwargs): + parsed_command = stringify_cache_args(args) + valkey_command = parsed_command.split(" ")[0] + rowcount = None + result = None + try: + result = func(*args, **kwargs) + return result + except Exception: + rowcount = 0 + raise + finally: + if rowcount is None: + rowcount = determine_row_count(valkey_command=valkey_command, result=result) + if valkey_command not in ROW_RETURNING_COMMANDS: + rowcount = None + core.dispatch("valkey.command.post", [ctx, rowcount]) + + +# +# tracing functions +# +def instrumented_execute_command(integration_config): + def _instrumented_execute_command(func, instance, args, kwargs): + pin = Pin.get_from(instance) + if not pin or not pin.enabled(): + return func(*args, **kwargs) + + with _instrument_valkey_cmd(pin, integration_config, instance, args) as ctx: + return _run_valkey_command(ctx=ctx, func=func, args=args, kwargs=kwargs) + + return _instrumented_execute_command + + +def instrumented_pipeline(func, instance, args, kwargs): + pipeline = func(*args, **kwargs) + pin = Pin.get_from(instance) + if pin: + pin.onto(pipeline) + return pipeline + + +def instrumented_execute_pipeline(integration_config, is_cluster=False): + def _instrumented_execute_pipeline(func, instance, args, kwargs): + pin = Pin.get_from(instance) + if not pin or not pin.enabled(): + return func(*args, **kwargs) + + if is_cluster: + cmds = [ + stringify_cache_args(c.args, cmd_max_len=integration_config.cmd_max_length) + for c in instance.command_stack + ] + else: + cmds = [ + stringify_cache_args(c, cmd_max_len=integration_config.cmd_max_length) + for c, _ in instance.command_stack + ] + with _instrument_valkey_execute_pipeline(pin, integration_config, cmds, instance, is_cluster): + return func(*args, **kwargs) + + return _instrumented_execute_pipeline diff --git a/ddtrace/contrib/trace_utils_valkey.py b/ddtrace/contrib/trace_utils_valkey.py new file mode 100644 index 00000000000..b84ee7b955d --- /dev/null +++ b/ddtrace/contrib/trace_utils_valkey.py @@ -0,0 +1,18 @@ +from ddtrace.contrib.valkey_utils import determine_row_count +from ddtrace.contrib.valkey_utils import stringify_cache_args +from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning +from ddtrace.vendor.debtcollector import deprecate + + +deprecate( + "The ddtrace.contrib.trace_utils_valkey module is deprecated and will be removed.", + message="A new interface will be provided by the ddtrace.contrib.valkey_utils module", + category=DDTraceDeprecationWarning, +) + + +format_command_args = stringify_cache_args + + +def determine_row_count(valkey_command, span, result): # noqa: F811 + determine_row_count(valkey_command=valkey_command, result=result) diff --git a/ddtrace/contrib/valkey/__init__.py b/ddtrace/contrib/valkey/__init__.py new file mode 100644 index 00000000000..eb369ae02cf --- /dev/null +++ b/ddtrace/contrib/valkey/__init__.py @@ -0,0 +1,84 @@ +""" +The valkey integration traces valkey requests. + + +Enabling +~~~~~~~~ + +The valkey integration is enabled automatically when using +:ref:`ddtrace-run` or :ref:`import ddtrace.auto`. + +Or use :func:`patch()` to manually enable the integration:: + + from ddtrace import patch + patch(valkey=True) + + +Global Configuration +~~~~~~~~~~~~~~~~~~~~ + +.. py:data:: ddtrace.config.valkey["service"] + + The service name reported by default for valkey traces. + + This option can also be set with the ``DD_VALKEY_SERVICE`` environment + variable. + + Default: ``"valkey"`` + + +.. py:data:: ddtrace.config.valkey["cmd_max_length"] + + Max allowable size for the valkey command span tag. + Anything beyond the max length will be replaced with ``"..."``. + + This option can also be set with the ``DD_VALKEY_CMD_MAX_LENGTH`` environment + variable. + + Default: ``1000`` + + +.. py:data:: ddtrace.config.valkey["resource_only_command"] + + The span resource will only include the command executed. To include all + arguments in the span resource, set this value to ``False``. + + This option can also be set with the ``DD_VALKEY_RESOURCE_ONLY_COMMAND`` environment + variable. + + Default: ``True`` + + +Instance Configuration +~~~~~~~~~~~~~~~~~~~~~~ + +To configure particular valkey instances use the :class:`Pin ` API:: + + import valkey + from ddtrace.trace import Pin + + client = valkey.StrictValkey(host="localhost", port=6379) + + # Override service name for this instance + Pin.override(client, service="my-custom-queue") + + # Traces reported for this client will now have "my-custom-queue" + # as the service name. + client.get("my-key") +""" + + +# Required to allow users to import from `ddtrace.contrib.redis.patch` directly +import warnings as _w + + +with _w.catch_warnings(): + _w.simplefilter("ignore", DeprecationWarning) + from . import patch as _ # noqa: F401, I001 + +# Expose public methods +from ddtrace.contrib.internal.valkey.patch import get_version +from ddtrace.contrib.internal.valkey.patch import patch + + +__all__ = ["patch", "get_version"] diff --git a/ddtrace/contrib/valkey/asyncio_patch.py b/ddtrace/contrib/valkey/asyncio_patch.py new file mode 100644 index 00000000000..9ad800f1382 --- /dev/null +++ b/ddtrace/contrib/valkey/asyncio_patch.py @@ -0,0 +1,14 @@ +from ddtrace.contrib.internal.valkey.asyncio_patch import * # noqa: F403 +from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning +from ddtrace.vendor.debtcollector import deprecate + + +def __getattr__(name): + deprecate( + ("%s.%s is deprecated" % (__name__, name)), + category=DDTraceDeprecationWarning, + ) + + if name in globals(): + return globals()[name] + raise AttributeError("%s has no attribute %s", __name__, name) diff --git a/ddtrace/contrib/valkey/patch.py b/ddtrace/contrib/valkey/patch.py new file mode 100644 index 00000000000..242d5edcd23 --- /dev/null +++ b/ddtrace/contrib/valkey/patch.py @@ -0,0 +1,14 @@ +from ddtrace.contrib.internal.valkey.patch import * # noqa: F403 +from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning +from ddtrace.vendor.debtcollector import deprecate + + +def __getattr__(name): + deprecate( + ("%s.%s is deprecated" % (__name__, name)), + category=DDTraceDeprecationWarning, + ) + + if name in globals(): + return globals()[name] + raise AttributeError("%s has no attribute %s", __name__, name) diff --git a/ddtrace/contrib/valkey_utils.py b/ddtrace/contrib/valkey_utils.py new file mode 100644 index 00000000000..8518dbe648a --- /dev/null +++ b/ddtrace/contrib/valkey_utils.py @@ -0,0 +1,84 @@ +from typing import Dict +from typing import List +from typing import Optional +from typing import Union + +from ddtrace.ext import net +from ddtrace.ext import valkey as valkeyx +from ddtrace.internal import core +from ddtrace.internal.utils.formats import stringify_cache_args + + +SINGLE_KEY_COMMANDS = [ + "GET", + "GETDEL", + "GETEX", + "GETRANGE", + "GETSET", + "LINDEX", + "LRANGE", + "RPOP", + "LPOP", + "HGET", + "HGETALL", + "HKEYS", + "HMGET", + "HRANDFIELD", + "HVALS", +] +MULTI_KEY_COMMANDS = ["MGET"] +ROW_RETURNING_COMMANDS = SINGLE_KEY_COMMANDS + MULTI_KEY_COMMANDS + + +def _extract_conn_tags(conn_kwargs): + """Transform valkey conn info into dogtrace metas""" + try: + conn_tags = { + net.TARGET_HOST: conn_kwargs["host"], + net.TARGET_PORT: conn_kwargs["port"], + net.SERVER_ADDRESS: conn_kwargs["host"], + valkeyx.DB: conn_kwargs.get("db") or 0, + } + client_name = conn_kwargs.get("client_name") + if client_name: + conn_tags[valkeyx.CLIENT_NAME] = client_name + return conn_tags + except Exception: + return {} + + +def determine_row_count(valkey_command: str, result: Optional[Union[List, Dict, str]]) -> int: + empty_results = [b"", [], {}, None] + # result can be an empty list / dict / string + if result not in empty_results: + if valkey_command == "MGET": + # only include valid key results within count + result = [x for x in result if x not in empty_results] + return len(result) + elif valkey_command == "HMGET": + # only include valid key results within count + result = [x for x in result if x not in empty_results] + return 1 if len(result) > 0 else 0 + else: + return 1 + else: + return 0 + + +async def _run_valkey_command_async(ctx: core.ExecutionContext, func, args, kwargs): + parsed_command = stringify_cache_args(args) + valkey_command = parsed_command.split(" ")[0] + rowcount = None + result = None + try: + result = await func(*args, **kwargs) + return result + except BaseException: + rowcount = 0 + raise + finally: + if rowcount is None: + rowcount = determine_row_count(valkey_command=valkey_command, result=result) + if valkey_command not in ROW_RETURNING_COMMANDS: + rowcount = None + core.dispatch("valkey.async_command.post", [ctx, rowcount]) diff --git a/ddtrace/ext/__init__.py b/ddtrace/ext/__init__.py index 965dd04f43f..98cc5226100 100644 --- a/ddtrace/ext/__init__.py +++ b/ddtrace/ext/__init__.py @@ -16,6 +16,7 @@ class SpanTypes(object): AUTH = "auth" SYSTEM = "system" LLM = "llm" + VALKEY = "valkey" class SpanKind(object): @@ -35,5 +36,6 @@ class SpanKind(object): SpanTypes.REDIS, SpanTypes.SQL, SpanTypes.WORKER, + SpanTypes.VALKEY, } ) diff --git a/ddtrace/ext/valkey.py b/ddtrace/ext/valkey.py new file mode 100644 index 00000000000..3246af841f6 --- /dev/null +++ b/ddtrace/ext/valkey.py @@ -0,0 +1,14 @@ +# defaults +APP = "valkey" +DEFAULT_SERVICE = "valkey" + +# net extension +DB = "out.valkey_db" + +# standard tags +RAWCMD = "valkey.raw_command" +CMD = "valkey.command" +ARGS_LEN = "valkey.args_length" +PIPELINE_LEN = "valkey.pipeline_length" +PIPELINE_AGE = "valkey.pipeline_age" +CLIENT_NAME = "valkey.client_name" diff --git a/docker-compose.yml b/docker-compose.yml index 118ad8cc5db..30cc08d0ae7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -207,5 +207,35 @@ services: - DD_TRACE_AGENT_URL=http://testagent:8126 - _DD_APPSEC_DEDUPLICATION_ENABLED=false + valkey: + image: valkey/valkey:8.0-alpine + ports: + - "127.0.0.1:6379:6379" + + valkeycluster: + image: valkey/valkey:8.0-alpine + ports: + - "127.0.0.1:7000:7000" + - "127.0.0.1:7001:7001" + - "127.0.0.1:7002:7002" + - "127.0.0.1:7003:7003" + - "127.0.0.1:7004:7004" + - "127.0.0.1:7005:7005" + entrypoint: + - /bin/sh + - -c + - | + PORTS='7000 7001 7002 7003 7004 7005' + for PORT in $${PORTS} + do + mkdir $${PORT} + cd $${PORT} + valkey-server --port $${PORT} --cluster-enabled yes --cluster-node-timeout 5000 --appendonly yes & + cd .. + done + sleep 2 + valkey-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-yes --cluster-replicas 1 + sleep infinity + volumes: ddagent: diff --git a/docs/index.rst b/docs/index.rst index 23c0cd48a06..2b2f61d91c4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -174,6 +174,8 @@ contacting support. +--------------------------------------------------+---------------+----------------+ | :ref:`urllib3` | >= 1.25.8 | No | +--------------------------------------------------+---------------+----------------+ +| :ref:`valkey` | >= 6.0.0 | Yes | ++--------------------------------------------------+---------------+----------------+ | :ref:`vertexai` | >= 1.71.1 | Yes | +--------------------------------------------------+---------------+----------------+ | :ref:`vertica` | >= 0.6 | Yes | diff --git a/docs/integrations.rst b/docs/integrations.rst index 62e096aa668..06739389406 100644 --- a/docs/integrations.rst +++ b/docs/integrations.rst @@ -485,6 +485,13 @@ urllib3 .. automodule:: ddtrace.contrib.urllib3 +.. _valkey: + +valkey +^^^^^^ +.. automodule:: ddtrace.contrib.valkey + + .. _vertexai: vertexai diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index ff2cfc09c6d..913ad7f8319 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -301,6 +301,7 @@ urls username uvicorn uWSGI +valkey vendored versioned vertexai diff --git a/min_compatible_versions.csv b/min_compatible_versions.csv index 4537863f24c..c128cd85ffc 100644 --- a/min_compatible_versions.csv +++ b/min_compatible_versions.csv @@ -182,6 +182,7 @@ typing-extensions,0 typing_extensions,0 urllib3,~=1.0 uwsgi,0 +valkey,~=6.0.0 vcrpy,==4.2.1 vertexai,0 vertica-python,>=0.6.0 diff --git a/riotfile.py b/riotfile.py index b52fa77cbe1..bab57242ab3 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2947,6 +2947,16 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT Venv(pys=select_pys(min_version="3.8"), pkgs={"ragas": "==0.1.21", "langchain": latest}), ], ), + Venv( + name="valkey", + command="pytest {cmdargs} tests/contrib/valkey", + pkgs={ + "valkey": latest, + "pytest-randomly": latest, + "pytest-asyncio": "==0.23.7", + }, + pys=select_pys(min_version="3.8"), + ), Venv( name="profile", # NB riot commands that use this Venv must include --pass-env to work properly diff --git a/supported_versions_output.json b/supported_versions_output.json index a51bb17bb9a..06eff37be25 100644 --- a/supported_versions_output.json +++ b/supported_versions_output.json @@ -294,6 +294,12 @@ "max_tracer_supported": "2.2.3", "auto-instrumented": false }, + { + "integration": "valkey", + "minimum_tracer_supported": "6.0.0", + "max_tracer_supported": "6.0.2", + "auto-instrumented": true + }, { "integration": "vertexai", "minimum_tracer_supported": "1.71.1", diff --git a/supported_versions_table.csv b/supported_versions_table.csv index 3f7384a0cdd..edbe73503cd 100644 --- a/supported_versions_table.csv +++ b/supported_versions_table.csv @@ -47,5 +47,6 @@ starlette,0.13.6,0.41.3,True structlog,20.2.0,24.4.0,False tornado *,4.5.3,6.4,False urllib3,1.24.3,2.2.3,False +valkey,6.0.0,6.0.2,True vertexai,1.71.1,1.71.1,True yaaredis,2.0.4,3.0.0,True diff --git a/tests/contrib/config.py b/tests/contrib/config.py index 6ed086109a2..0b5f3d2bfbb 100644 --- a/tests/contrib/config.py +++ b/tests/contrib/config.py @@ -97,3 +97,13 @@ "host": os.getenv("TEST_KAFKA_HOST", "127.0.0.1"), "port": int(os.getenv("TEST_KAFKA_PORT", 29092)), } + +VALKEY_CONFIG = { + "host": os.getenv("TEST_VALKEY_HOST", "localhost"), + "port": int(os.getenv("TEST_VALKEY_PORT", 6379)), +} + +VALKEY_CLUSTER_CONFIG = { + "host": "127.0.0.1", + "ports": os.getenv("TEST_VALKEYCLUSTER_PORTS", "7000,7001,7002,7003,7004,7005"), +} diff --git a/tests/contrib/suitespec.yml b/tests/contrib/suitespec.yml index 8c5fbc72da2..185d2b7560e 100644 --- a/tests/contrib/suitespec.yml +++ b/tests/contrib/suitespec.yml @@ -240,6 +240,13 @@ components: urllib3: - ddtrace/contrib/urllib3/* - ddtrace/contrib/internal/urllib3/* + valkey: + - ddtrace/contrib/valkey/* + - ddtrace/contrib/internal/valkey/* + - ddtrace/_trace/utils_valkey.py + - ddtrace/contrib/valkey_utils.py + - ddtrace/contrib/trace_utils_valkey.py + - ddtrace/ext/valkey.py vertica: - ddtrace/contrib/vertica/* - ddtrace/contrib/internal/vertica/* @@ -1177,3 +1184,18 @@ suites: services: - redis snapshot: true + valkey: + parallelism: 5 + paths: + - '@bootstrap' + - '@core' + - '@contrib' + - '@tracing' + - '@valkey' + - tests/contrib/valkey/* + - tests/snapshots/tests.contrib.valkey.* + pattern: ^valkey$ + runner: riot + services: + - valkey + snapshot: true diff --git a/tests/contrib/valkey/__init__.py b/tests/contrib/valkey/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/contrib/valkey/test_valkey.py b/tests/contrib/valkey/test_valkey.py new file mode 100644 index 00000000000..1f78e744a7a --- /dev/null +++ b/tests/contrib/valkey/test_valkey.py @@ -0,0 +1,617 @@ +# -*- coding: utf-8 -*- +from unittest import mock + +import pytest +import valkey + +import ddtrace +from ddtrace.contrib.internal.valkey.patch import patch +from ddtrace.contrib.internal.valkey.patch import unpatch +from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME +from ddtrace.trace import Pin +from tests.opentracer.utils import init_tracer +from tests.utils import DummyTracer +from tests.utils import TracerTestCase +from tests.utils import snapshot + +from ..config import VALKEY_CONFIG + + +class TestValkeyPatch(TracerTestCase): + TEST_PORT = VALKEY_CONFIG["port"] + + def setUp(self): + super(TestValkeyPatch, self).setUp() + patch() + r = valkey.Valkey(port=self.TEST_PORT) + r.flushall() + Pin.override(r, tracer=self.tracer) + self.r = r + + def tearDown(self): + unpatch() + super(TestValkeyPatch, self).tearDown() + + def command_test_rowcount(self, raw_command, row_count, expect_result=True, **kwargs): + command_args_as_list = raw_command.split(" ") + + command_name = command_args_as_list[0].lower() + + if hasattr(self.r, command_name): + func = getattr(self.r, command_name) + + try: + # try to run function with kwargs, may fail due to valkey version + result = yield func(*command_args_as_list[1:], **kwargs) + for k in kwargs.keys(): + raw_command += " " + str(kwargs[k]) + except Exception: + # try without keyword arguments + result = func(*command_args_as_list[1:]) + + if expect_result: + assert result is not None + else: + empty_result = [None, [], {}, b""] + if isinstance(result, list): + result = [x for x in result if x] + assert result in empty_result + + command_span = self.get_spans()[-1] + + assert command_span.name == "valkey.command" + assert command_span.get_tag("valkey.raw_command") == raw_command + assert command_span.get_metric("db.row_count") == row_count + + def test_long_command(self): + self.r.mget(*range(1000)) + + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + + self.assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.span_type == "valkey" + assert span.error == 0 + meta = { + "out.host": "localhost", + } + metrics = { + "network.destination.port": self.TEST_PORT, + "out.valkey_db": 0, + } + for k, v in meta.items(): + assert span.get_tag(k) == v + for k, v in metrics.items(): + assert span.get_metric(k) == v + + assert span.get_tag("valkey.raw_command").startswith("MGET 0 1 2 3") + assert span.get_tag("valkey.raw_command").endswith("...") + assert span.get_tag("component") == "valkey" + assert span.get_tag("span.kind") == "client" + assert span.get_tag("db.system") == "valkey" + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) + def test_service_name_v1(self): + us = self.r.get("cheese") + assert us is None + spans = self.get_spans() + span = spans[0] + assert span.service == DEFAULT_SPAN_SERVICE_NAME + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0")) + def test_operation_name_v0_schema(self): + us = self.r.get("cheese") + assert us is None + spans = self.get_spans() + span = spans[0] + assert span.name == "valkey.command" + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) + def test_operation_name_v1_schema(self): + us = self.r.get("cheese") + assert us is None + spans = self.get_spans() + span = spans[0] + assert span.name == "valkey.command" + + def test_basics(self): + us = self.r.get("cheese") + assert us is None + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + self.assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_metric("out.valkey_db") == 0 + assert span.get_tag("out.host") == "localhost" + assert span.get_tag("valkey.raw_command") == "GET cheese" + assert span.get_tag("component") == "valkey" + assert span.get_tag("span.kind") == "client" + assert span.get_tag("db.system") == "valkey" + assert span.get_metric("valkey.args_length") == 2 + assert span.resource == "GET" + + def test_connection_error(self): + with mock.patch.object( + valkey.connection.ConnectionPool, + "get_connection", + side_effect=valkey.exceptions.ConnectionError("whatever"), + ): + with pytest.raises(valkey.exceptions.ConnectionError): + self.r.get("foo") + + def test_pipeline_traced(self): + with self.r.pipeline(transaction=False) as p: + p.set("blah", 32) + p.rpush("foo", "éé") + p.hgetall("xxx") + p.execute() + + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + self.assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.resource == "SET\nRPUSH\nHGETALL" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_metric("out.valkey_db") == 0 + assert span.get_tag("out.host") == "localhost" + assert span.get_tag("valkey.raw_command") == "SET blah 32\nRPUSH foo éé\nHGETALL xxx" + assert span.get_tag("component") == "valkey" + assert span.get_tag("span.kind") == "client" + assert span.get_metric("valkey.pipeline_length") == 3 + assert span.get_metric("valkey.pipeline_length") == 3 + + def test_pipeline_immediate(self): + with self.r.pipeline() as p: + p.set("a", 1) + p.immediate_execute_command("SET", "a", 1) + p.execute() + + spans = self.get_spans() + assert len(spans) == 2 + span = spans[0] + self.assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.resource == "SET" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_metric("out.valkey_db") == 0 + assert span.get_tag("out.host") == "localhost" + assert span.get_tag("component") == "valkey" + assert span.get_tag("span.kind") == "client" + + def test_meta_override(self): + r = self.r + pin = Pin.get_from(r) + if pin: + pin.clone(tags={"cheese": "camembert"}).onto(r) + + r.get("cheese") + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + assert span.service == "valkey" + assert "cheese" in span.get_tags() and span.get_tag("cheese") == "camembert" + + def test_patch_unpatch(self): + tracer = DummyTracer() + + # Test patch idempotence + patch() + patch() + + r = valkey.Valkey(port=VALKEY_CONFIG["port"]) + Pin.get_from(r).clone(tracer=tracer).onto(r) + r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + + # Test unpatch + unpatch() + + r = valkey.Valkey(port=VALKEY_CONFIG["port"]) + r.get("key") + + spans = tracer.pop() + assert not spans, spans + + # Test patch again + patch() + + r = valkey.Valkey(port=VALKEY_CONFIG["port"]) + Pin.get_from(r).clone(tracer=tracer).onto(r) + r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + + def test_opentracing(self): + """Ensure OpenTracing works with valkey.""" + ot_tracer = init_tracer("valkey_svc", self.tracer) + + with ot_tracer.start_active_span("valkey_get"): + us = self.r.get("cheese") + assert us is None + + spans = self.get_spans() + assert len(spans) == 2 + ot_span, dd_span = spans + + # confirm the parenting + assert ot_span.parent_id is None + assert dd_span.parent_id == ot_span.span_id + + assert ot_span.name == "valkey_get" + assert ot_span.service == "valkey_svc" + + self.assert_is_measured(dd_span) + assert dd_span.service == "valkey" + assert dd_span.name == "valkey.command" + assert dd_span.span_type == "valkey" + assert dd_span.error == 0 + assert dd_span.get_metric("out.valkey_db") == 0 + assert dd_span.get_tag("out.host") == "localhost" + assert dd_span.get_tag("valkey.raw_command") == "GET cheese" + assert dd_span.get_tag("component") == "valkey" + assert dd_span.get_tag("span.kind") == "client" + assert dd_span.get_tag("db.system") == "valkey" + assert dd_span.get_metric("valkey.args_length") == 2 + assert dd_span.resource == "GET" + + def test_valkey_rowcount_all_keys_valid(self): + self.r.set("key1", "value1") + + get1 = self.r.get("key1") + + assert get1 == b"value1" + + spans = self.get_spans() + get_valid_key_span = spans[1] + + assert get_valid_key_span.name == "valkey.command" + assert get_valid_key_span.get_tag("valkey.raw_command") == "GET key1" + assert get_valid_key_span.get_metric("db.row_count") == 1 + + get_commands = ["GET key", "GETEX key", "GETRANGE key 0 2"] + list_get_commands = ["LINDEX lkey 0", "LRANGE lkey 0 3", "RPOP lkey", "LPOP lkey"] + hashing_get_commands = [ + "HGET hkey field1", + "HGETALL hkey", + "HKEYS hkey", + "HMGET hkey field1 field2", + "HRANDFIELD hkey", + "HVALS hkey", + ] + multi_key_get_commands = ["MGET key key2", "MGET key key2 key3", "MGET key key2 key3 key4"] + + for command in get_commands: + self.r.set("key", "value") + self.command_test_rowcount(command, 1) + for command in list_get_commands: + self.r.lpush("lkey", "1", "2", "3", "4", "5") + self.command_test_rowcount(command, 1) + if command == "RPOP lkey": # lets get multiple values from the set and ensure rowcount is still 1 + self.command_test_rowcount(command, 1, count=2) + for command in hashing_get_commands: + self.r.hset("hkey", "field1", "value1") + self.r.hset("hkey", "field2", "value2") + self.command_test_rowcount(command, 1) + for command in multi_key_get_commands: + self.r.mset({"key": "value", "key2": "value2", "key3": "value3", "key4": "value4"}) + self.command_test_rowcount(command, len(command.split(" ")) - 1) + + def test_valkey_rowcount_some_keys_valid(self): + self.r.mset({"key": "value", "key2": "value2"}) + + get_both_valid = self.r.mget("key", "key2") + get_one_missing = self.r.mget("key", "missing_key") + + assert get_both_valid == [b"value", b"value2"] + assert get_one_missing == [b"value", None] + + spans = self.get_spans() + get_both_valid_span = spans[1] + get_one_missing_span = spans[2] + + assert get_both_valid_span.name == "valkey.command" + assert get_both_valid_span.get_tag("valkey.raw_command") == "MGET key key2" + assert get_both_valid_span.get_metric("db.row_count") == 2 + + assert get_one_missing_span.name == "valkey.command" + assert get_one_missing_span.get_tag("valkey.raw_command") == "MGET key missing_key" + assert get_one_missing_span.get_metric("db.row_count") == 1 + + multi_key_get_commands = [ + "MGET key key2", + "MGET key missing_key", + "MGET key key2 missing_key", + "MGET key missing_key missing_key2 key2", + ] + + for command in multi_key_get_commands: + command_keys = command.split(" ")[1:] + self.command_test_rowcount(command, len([key for key in command_keys if "missing_key" not in key])) + + def test_valkey_rowcount_no_keys_valid(self): + get_missing = self.r.get("missing_key") + + assert get_missing is None + + spans = self.get_spans() + get_missing_key_span = spans[0] + + assert get_missing_key_span.name == "valkey.command" + assert get_missing_key_span.get_tag("valkey.raw_command") == "GET missing_key" + assert get_missing_key_span.get_metric("db.row_count") == 0 + + get_commands = ["GET key", "GETDEL key", "GETEX key", "GETRANGE key 0 2"] + list_get_commands = ["LINDEX lkey 0", "LRANGE lkey 0 3", "RPOP lkey", "LPOP lkey"] + hashing_get_commands = [ + "HGET hkey field1", + "HGETALL hkey", + "HKEYS hkey", + "HMGET hkey field1 field2", + "HRANDFIELD hkey", + "HVALS hkey", + ] + multi_key_get_commands = ["MGET key key2", "MGET key key2 key3", "MGET key key2 key3 key4"] + + for command in get_commands: + self.command_test_rowcount(command, 0, expect_result=False) + for command in list_get_commands: + self.command_test_rowcount(command, 0, expect_result=False) + if command == "RPOP lkey": # lets get multiple values from the set and ensure rowcount is still 1 + self.command_test_rowcount(command, 0, expect_result=False, count=2) + for command in hashing_get_commands: + self.command_test_rowcount(command, 0, expect_result=False) + for command in multi_key_get_commands: + self.command_test_rowcount(command, 0, expect_result=False) + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc")) + def test_user_specified_service_default(self): + from ddtrace import config + + assert config.service == "mysvc" + + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "valkey" + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0")) + def test_user_specified_service_v0(self): + from ddtrace import config + + assert config.service == "mysvc" + + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "valkey" + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) + def test_user_specified_service_v1(self): + from ddtrace import config + + assert config.service == "mysvc" + + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "mysvc" + + @TracerTestCase.run_in_subprocess( + env_overrides=dict(DD_VALKEY_SERVICE="myvalkey", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0") + ) + def test_env_user_specified_valkey_service_v0(self): + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "myvalkey", span.service + + self.reset() + + # Global config + with self.override_config("valkey", dict(service="cfg-valkey")): + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "cfg-valkey", span.service + + self.reset() + + # Manual override + Pin.override(self.r, service="mysvc", tracer=self.tracer) + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "mysvc", span.service + + @TracerTestCase.run_in_subprocess( + env_overrides=dict( + DD_SERVICE="app-svc", DD_VALKEY_SERVICE="env-specified-valkey-svc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0" + ) + ) + def test_service_precedence_v0(self): + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "env-specified-valkey-svc", span.service + + self.reset() + + # Do a manual override + Pin.override(self.r, service="override-valkey", tracer=self.tracer) + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "override-valkey", span.service + + +class TestValkeyPatchSnapshot(TracerTestCase): + TEST_PORT = VALKEY_CONFIG["port"] + + def setUp(self): + super(TestValkeyPatchSnapshot, self).setUp() + patch() + r = valkey.Valkey(port=self.TEST_PORT) + self.r = r + + def tearDown(self): + unpatch() + super(TestValkeyPatchSnapshot, self).tearDown() + self.r.flushall() + + @snapshot() + def test_long_command(self): + self.r.mget(*range(1000)) + + @snapshot() + def test_basics(self): + us = self.r.get("cheese") + assert us is None + + @snapshot() + def test_unicode(self): + us = self.r.get("😐") + assert us is None + + @snapshot() + def test_pipeline_traced(self): + with self.r.pipeline(transaction=False) as p: + p.set("blah", 32) + p.rpush("foo", "éé") + p.hgetall("xxx") + p.execute() + + @snapshot() + def test_pipeline_immediate(self): + with self.r.pipeline() as p: + p.set("a", 1) + p.immediate_execute_command("SET", "a", 1) + p.execute() + + @snapshot() + def test_meta_override(self): + r = self.r + pin = Pin.get_from(r) + if pin: + pin.clone(tags={"cheese": "camembert"}).onto(r) + + r.get("cheese") + + def test_patch_unpatch(self): + tracer = DummyTracer() + + # Test patch idempotence + patch() + patch() + + r = valkey.Valkey(port=VALKEY_CONFIG["port"]) + Pin.get_from(r).clone(tracer=tracer).onto(r) + r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + + # Test unpatch + unpatch() + + r = valkey.Valkey(port=VALKEY_CONFIG["port"]) + r.get("key") + + spans = tracer.pop() + assert not spans, spans + + # Test patch again + patch() + + r = valkey.Valkey(port=VALKEY_CONFIG["port"]) + Pin.get_from(r).clone(tracer=tracer).onto(r) + r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + + @snapshot() + def test_opentracing(self): + """Ensure OpenTracing works with valkey.""" + writer = ddtrace.tracer._writer + ot_tracer = init_tracer("valkey_svc", ddtrace.tracer) + ddtrace.tracer.configure(writer=writer) + + with ot_tracer.start_active_span("valkey_get"): + us = self.r.get("cheese") + assert us is None + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc")) + @snapshot() + def test_user_specified_service(self): + from ddtrace import config + + assert config.service == "mysvc" + + self.r.get("cheese") + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_VALKEY_SERVICE="myvalkey")) + @snapshot() + def test_env_user_specified_valkey_service(self): + self.r.get("cheese") + + self.reset() + + # Global config + with self.override_config("valkey", dict(service="cfg-valkey")): + self.r.get("cheese") + + self.reset() + + # Manual override + Pin.override(self.r, service="mysvc", tracer=self.tracer) + self.r.get("cheese") + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="app-svc", DD_VALKEY_SERVICE="env-valkey")) + @snapshot() + def test_service_precedence(self): + self.r.get("cheese") + + self.reset() + + # Do a manual override + Pin.override(self.r, service="override-valkey", tracer=self.tracer) + self.r.get("cheese") + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_VALKEY_CMD_MAX_LENGTH="10")) + @snapshot() + def test_custom_cmd_length_env(self): + self.r.get("here-is-a-long-key-name") + + @snapshot() + def test_custom_cmd_length(self): + with self.override_config("valkey", dict(cmd_max_length=7)): + self.r.get("here-is-a-long-key-name") + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_VALKEY_RESOURCE_ONLY_COMMAND="false")) + @snapshot() + def test_full_command_in_resource_env(self): + self.r.get("put_key_in_resource") + p = self.r.pipeline(transaction=False) + p.set("pipeline-cmd1", 1) + p.set("pipeline-cmd2", 2) + p.execute() + + @snapshot() + def test_full_command_in_resource_config(self): + with self.override_config("valkey", dict(resource_only_command=False)): + self.r.get("put_key_in_resource") + p = self.r.pipeline(transaction=False) + p.set("pipeline-cmd1", 1) + p.set("pipeline-cmd2", 2) + p.execute() diff --git a/tests/contrib/valkey/test_valkey_asyncio.py b/tests/contrib/valkey/test_valkey_asyncio.py new file mode 100644 index 00000000000..64743a7770b --- /dev/null +++ b/tests/contrib/valkey/test_valkey_asyncio.py @@ -0,0 +1,221 @@ +import asyncio +import typing +from unittest import mock + +import pytest +import valkey +import valkey.asyncio +from wrapt import ObjectProxy + +from ddtrace import tracer +from ddtrace.contrib.internal.valkey.patch import patch +from ddtrace.contrib.internal.valkey.patch import unpatch +from ddtrace.trace import Pin +from tests.utils import override_config + +from ..config import VALKEY_CONFIG + + +def get_valkey_instance(max_connections: int, client_name: typing.Optional[str] = None): + return valkey.asyncio.from_url( + "valkey://127.0.0.1:%s" % VALKEY_CONFIG["port"], max_connections=max_connections, client_name=client_name + ) + + +@pytest.fixture +def valkey_client(): + r = get_valkey_instance(max_connections=10) # default values + yield r + + +@pytest.fixture +def single_pool_valkey_client(): + r = get_valkey_instance(max_connections=1) + yield r + + +@pytest.fixture(autouse=True) +async def traced_valkey(valkey_client): + await valkey_client.flushall() + + patch() + try: + yield + finally: + unpatch() + await valkey_client.flushall() + + +def test_patching(): + """ + When patching valkey library + We wrap the correct methods + When unpatching valkey library + We unwrap the correct methods + """ + assert isinstance(valkey.asyncio.client.Valkey.execute_command, ObjectProxy) + assert isinstance(valkey.asyncio.client.Valkey.pipeline, ObjectProxy) + assert isinstance(valkey.asyncio.client.Pipeline.pipeline, ObjectProxy) + unpatch() + assert not isinstance(valkey.asyncio.client.Valkey.execute_command, ObjectProxy) + assert not isinstance(valkey.asyncio.client.Valkey.pipeline, ObjectProxy) + assert not isinstance(valkey.asyncio.client.Pipeline.pipeline, ObjectProxy) + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_basic_request(valkey_client): + val = await valkey_client.get("cheese") + assert val is None + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_unicode_request(valkey_client): + val = await valkey_client.get("😐") + assert val is None + + +@pytest.mark.snapshot(wait_for_num_traces=1, ignores=["meta.error.stack"]) +async def test_connection_error(valkey_client): + with mock.patch.object( + valkey.asyncio.connection.ConnectionPool, + "get_connection", + side_effect=valkey.exceptions.ConnectionError("whatever"), + ): + with pytest.raises(valkey.exceptions.ConnectionError): + await valkey_client.get("foo") + + +@pytest.mark.snapshot(wait_for_num_traces=2) +async def test_decoding_non_utf8_args(valkey_client): + await valkey_client.set(b"\x80foo", b"\x80abc") + val = await valkey_client.get(b"\x80foo") + assert val == b"\x80abc" + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_decoding_non_utf8_pipeline_args(valkey_client): + p = valkey_client.pipeline() + p.set(b"\x80blah", "boo") + p.set("foo", b"\x80abc") + p.get(b"\x80blah") + p.get("foo") + + response_list = await p.execute() + assert response_list[0] is True # response from valkey.set is OK if successfully pushed + assert response_list[1] is True + assert response_list[2].decode() == "boo" + assert response_list[3] == b"\x80abc" + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_long_command(valkey_client): + length = 1000 + val_list = await valkey_client.mget(*range(length)) + assert len(val_list) == length + for val in val_list: + assert val is None + + +@pytest.mark.snapshot(wait_for_num_traces=3) +async def test_override_service_name(valkey_client): + with override_config("valkey", dict(service_name="myvalkey")): + val = await valkey_client.get("cheese") + assert val is None + await valkey_client.set("cheese", "my-cheese") + val = await valkey_client.get("cheese") + if isinstance(val, bytes): + val = val.decode() + assert val == "my-cheese" + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_pin(valkey_client): + Pin.override(valkey_client, service="my-valkey") + val = await valkey_client.get("cheese") + assert val is None + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_pipeline_traced(valkey_client): + p = valkey_client.pipeline(transaction=False) + p.set("blah", "boo") + p.set("foo", "bar") + p.get("blah") + p.get("foo") + + response_list = await p.execute() + assert response_list[0] is True # response from valkey.set is OK if successfully pushed + assert response_list[1] is True + assert ( + response_list[2].decode() == "boo" + ) # response from hset is 'Integer reply: The number of fields that were added.' + assert response_list[3].decode() == "bar" + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_pipeline_traced_context_manager_transaction(valkey_client): + """ + Regression test for: https://github.com/DataDog/dd-trace-py/issues/3106 + + Example:: + + async def main(): + valkey = await valkey.from_url("valkey://localhost") + async with valkey.pipeline(transaction=True) as pipe: + ok1, ok2 = await (pipe.set("key1", "value1").set("key2", "value2").execute()) + assert ok1 + assert ok2 + """ + + async with valkey_client.pipeline(transaction=True) as p: + set_1, set_2, get_1, get_2 = await p.set("blah", "boo").set("foo", "bar").get("blah").get("foo").execute() + + # response from valkey.set is OK if successfully pushed + assert set_1 is True + assert set_2 is True + assert get_1.decode() == "boo" + assert get_2.decode() == "bar" + + +@pytest.mark.snapshot(wait_for_num_traces=1) +async def test_two_traced_pipelines(valkey_client): + with tracer.trace("web-request", service="test"): + p1 = await valkey_client.pipeline(transaction=False) + p2 = await valkey_client.pipeline(transaction=False) + await p1.set("blah", "boo") + await p2.set("foo", "bar") + await p1.get("blah") + await p2.get("foo") + + response_list1 = await p1.execute() + response_list2 = await p2.execute() + + assert response_list1[0] is True # response from valkey.set is OK if successfully pushed + assert response_list2[0] is True + assert ( + response_list1[1].decode() == "boo" + ) # response from hset is 'Integer reply: The number of fields that were added.' + assert response_list2[1].decode() == "bar" + + +async def test_parenting(valkey_client, snapshot_context): + with snapshot_context(wait_for_num_traces=1): + with tracer.trace("web-request", service="test"): + await valkey_client.set("blah", "boo") + await valkey_client.get("blah") + + +async def test_client_name(snapshot_context): + with snapshot_context(wait_for_num_traces=1): + with tracer.trace("web-request", service="test"): + valkey_client = get_valkey_instance(10, client_name="testing-client-name") + await valkey_client.get("blah") + + +@pytest.mark.asyncio +async def test_asyncio_task_cancelled(valkey_client): + with mock.patch.object( + valkey.asyncio.connection.ConnectionPool, "get_connection", side_effect=asyncio.CancelledError + ): + with pytest.raises(asyncio.CancelledError): + await valkey_client.get("foo") diff --git a/tests/contrib/valkey/test_valkey_cluster.py b/tests/contrib/valkey/test_valkey_cluster.py new file mode 100644 index 00000000000..3876426d25d --- /dev/null +++ b/tests/contrib/valkey/test_valkey_cluster.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +import valkey + +from ddtrace.contrib.internal.valkey.patch import patch +from ddtrace.contrib.internal.valkey.patch import unpatch +from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME +from ddtrace.trace import Pin +from tests.contrib.config import VALKEY_CLUSTER_CONFIG +from tests.utils import DummyTracer +from tests.utils import TracerTestCase +from tests.utils import assert_is_measured + + +class TestValkeyClusterPatch(TracerTestCase): + TEST_HOST = VALKEY_CLUSTER_CONFIG["host"] + TEST_PORTS = VALKEY_CLUSTER_CONFIG["ports"] + + def _get_test_client(self): + startup_nodes = [valkey.cluster.ClusterNode(self.TEST_HOST, int(port)) for port in self.TEST_PORTS.split(",")] + return valkey.cluster.ValkeyCluster(startup_nodes=startup_nodes) + + def setUp(self): + super(TestValkeyClusterPatch, self).setUp() + patch() + r = self._get_test_client() + r.flushall() + Pin.override(r, tracer=self.tracer) + self.r = r + + def tearDown(self): + unpatch() + super(TestValkeyClusterPatch, self).tearDown() + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) + def test_span_service_name_v1(self): + us = self.r.get("cheese") + assert us is None + spans = self.get_spans() + span = spans[0] + assert span.service == DEFAULT_SPAN_SERVICE_NAME + + def test_basics(self): + us = self.r.get("cheese") + assert us is None + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_tag("valkey.raw_command") == "GET cheese" + assert span.get_tag("component") == "valkey" + assert span.get_tag("db.system") == "valkey" + assert span.get_metric("valkey.args_length") == 2 + assert span.resource == "GET" + + def test_unicode(self): + us = self.r.get("😐") + assert us is None + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_tag("valkey.raw_command") == "GET 😐" + assert span.get_tag("component") == "valkey" + assert span.get_tag("db.system") == "valkey" + assert span.get_metric("valkey.args_length") == 2 + assert span.resource == "GET" + + def test_pipeline(self): + with self.r.pipeline(transaction=False) as p: + p.set("blah", 32) + p.rpush("foo", "éé") + p.hgetall("xxx") + p.execute() + + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.resource == "SET\nRPUSH\nHGETALL" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_tag("valkey.raw_command") == "SET blah 32\nRPUSH foo éé\nHGETALL xxx" + assert span.get_tag("component") == "valkey" + assert span.get_metric("valkey.pipeline_length") == 3 + + def test_patch_unpatch(self): + tracer = DummyTracer() + + # Test patch idempotence + patch() + patch() + + r = self._get_test_client() + Pin.get_from(r).clone(tracer=tracer).onto(r) + r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + + # Test unpatch + unpatch() + + r = self._get_test_client() + r.get("key") + + spans = tracer.pop() + assert not spans, spans + + # Test patch again + patch() + + r = self._get_test_client() + Pin.get_from(r).clone(tracer=tracer).onto(r) + r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0")) + def test_user_specified_service_v0(self): + """ + When a user specifies a service for the app + The valkeycluster integration should not use it. + """ + # Ensure that the service name was configured + from ddtrace import config + + assert config.service == "mysvc" + + r = self._get_test_client() + Pin.get_from(r).clone(tracer=self.tracer).onto(r) + r.get("key") + + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + assert span.service != "mysvc" + + @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) + def test_user_specified_service_v1(self): + """ + When a user specifies a service for the app + The valkeycluster integration should use it. + """ + # Ensure that the service name was configured + from ddtrace import config + + assert config.service == "mysvc" + + r = self._get_test_client() + Pin.get_from(r).clone(tracer=self.tracer).onto(r) + r.get("key") + + spans = self.get_spans() + assert len(spans) == 1 + span = spans[0] + assert span.service == "mysvc" + + @TracerTestCase.run_in_subprocess( + env_overrides=dict(DD_VALKEY_SERVICE="myvalkeycluster", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0") + ) + def test_env_user_specified_valkeycluster_service_v0(self): + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "myvalkeycluster", span.service + + @TracerTestCase.run_in_subprocess( + env_overrides=dict(DD_VALKEY_SERVICE="myvalkeycluster", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1") + ) + def test_env_user_specified_valkeycluster_service_v1(self): + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "myvalkeycluster", span.service + + @TracerTestCase.run_in_subprocess( + env_overrides=dict( + DD_SERVICE="app-svc", DD_VALKEY_SERVICE="myvalkeycluster", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0" + ) + ) + def test_service_precedence_v0(self): + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "myvalkeycluster" + + self.reset() + + @TracerTestCase.run_in_subprocess( + env_overrides=dict( + DD_SERVICE="app-svc", DD_VALKEY_SERVICE="myvalkeycluster", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1" + ) + ) + def test_service_precedence_v1(self): + self.r.get("cheese") + span = self.get_spans()[0] + assert span.service == "myvalkeycluster" + + self.reset() diff --git a/tests/contrib/valkey/test_valkey_cluster_asyncio.py b/tests/contrib/valkey/test_valkey_cluster_asyncio.py new file mode 100644 index 00000000000..8f63aa9d542 --- /dev/null +++ b/tests/contrib/valkey/test_valkey_cluster_asyncio.py @@ -0,0 +1,457 @@ +# -*- coding: utf-8 -*- +import pytest +import valkey + +from ddtrace.contrib.internal.valkey.patch import patch +from ddtrace.contrib.internal.valkey.patch import unpatch +from ddtrace.trace import Pin +from tests.contrib.config import VALKEY_CLUSTER_CONFIG +from tests.utils import DummyTracer +from tests.utils import assert_is_measured + + +TEST_HOST = VALKEY_CLUSTER_CONFIG["host"] +TEST_PORTS = VALKEY_CLUSTER_CONFIG["ports"] + + +@pytest.mark.asyncio +@pytest.fixture +async def valkey_cluster(): + startup_nodes = [valkey.asyncio.cluster.ClusterNode(TEST_HOST, int(port)) for port in TEST_PORTS.split(",")] + yield valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + + +@pytest.mark.asyncio +@pytest.fixture +async def traced_valkey_cluster(tracer, test_spans): + patch() + startup_nodes = [valkey.asyncio.cluster.ClusterNode(TEST_HOST, int(port)) for port in TEST_PORTS.split(",")] + valkey_cluster = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + await valkey_cluster.flushall() + Pin.override(valkey_cluster, tracer=tracer) + try: + yield valkey_cluster, test_spans + finally: + unpatch() + await valkey_cluster.flushall() + + +@pytest.mark.asyncio +async def test_basics(traced_valkey_cluster): + cluster, test_spans = traced_valkey_cluster + us = await cluster.get("cheese") + assert us is None + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + + span = spans[0] + assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_tag("valkey.raw_command") == "GET cheese" + assert span.get_tag("component") == "valkey" + assert span.get_tag("db.system") == "valkey" + assert span.get_metric("valkey.args_length") == 2 + assert span.resource == "GET" + + +@pytest.mark.asyncio +async def test_unicode(traced_valkey_cluster): + cluster, test_spans = traced_valkey_cluster + us = await cluster.get("😐") + assert us is None + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + + span = spans[0] + assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_tag("valkey.raw_command") == "GET 😐" + assert span.get_tag("component") == "valkey" + assert span.get_tag("db.system") == "valkey" + assert span.get_metric("valkey.args_length") == 2 + assert span.resource == "GET" + + +@pytest.mark.asyncio +async def test_pipeline(traced_valkey_cluster): + cluster, test_spans = traced_valkey_cluster + async with cluster.pipeline(transaction=False) as p: + p.set("blah", 32) + p.rpush("foo", "éé") + p.hgetall("xxx") + await p.execute() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + + span = spans[0] + assert_is_measured(span) + assert span.service == "valkey" + assert span.name == "valkey.command" + assert span.resource == "SET\nRPUSH\nHGETALL" + assert span.span_type == "valkey" + assert span.error == 0 + assert span.get_tag("valkey.raw_command") == "SET blah 32\nRPUSH foo éé\nHGETALL xxx" + assert span.get_tag("component") == "valkey" + assert span.get_metric("valkey.pipeline_length") == 3 + + +@pytest.mark.asyncio +async def test_patch_unpatch(valkey_cluster): + tracer = DummyTracer() + + # Test patch idempotence + patch() + patch() + + r = valkey_cluster + Pin.override(r, tracer=tracer) + await r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + + # Test unpatch + unpatch() + + r = valkey_cluster + await r.get("key") + + spans = tracer.pop() + assert not spans, spans + + # Test patch again + patch() + + r = valkey_cluster + Pin.override(r, tracer=tracer) + await r.get("key") + + spans = tracer.pop() + assert spans, spans + assert len(spans) == 1 + unpatch() + + +@pytest.mark.subprocess( + env=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1"), + err=None, # avoid checking stderr because of an expected deprecation warning +) +def test_default_service_name_v1(): + import asyncio + + import valkey + + from ddtrace.contrib.internal.valkey.patch import patch + from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME + from ddtrace.trace import Pin + from tests.contrib.config import VALKEY_CLUSTER_CONFIG + from tests.utils import DummyTracer + from tests.utils import TracerSpanContainer + + patch() + + async def test(): + startup_nodes = [ + valkey.asyncio.cluster.ClusterNode(VALKEY_CLUSTER_CONFIG["host"], int(port)) + for port in VALKEY_CLUSTER_CONFIG["ports"].split(",") + ] + r = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + tracer = DummyTracer() + test_spans = TracerSpanContainer(tracer) + + Pin.get_from(r).clone(tracer=tracer).onto(r) + await r.get("key") + await r.close() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + span = spans[0] + assert span.service == DEFAULT_SPAN_SERVICE_NAME + + asyncio.run(test()) + + +@pytest.mark.subprocess( + env=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0"), + err=None, # avoid checking stderr because of an expected deprecation warning +) +def test_user_specified_service_v0(): + """ + When a user specifies a service for the app + The valkeycluster integration should not use it. + """ + import asyncio + + import valkey + + from ddtrace import config + from ddtrace.contrib.internal.valkey.patch import patch + from ddtrace.trace import Pin + from tests.contrib.config import VALKEY_CLUSTER_CONFIG + from tests.utils import DummyTracer + from tests.utils import TracerSpanContainer + + patch() + + async def test(): + # # Ensure that the service name was configured + assert config.service == "mysvc" + + startup_nodes = [ + valkey.asyncio.cluster.ClusterNode(VALKEY_CLUSTER_CONFIG["host"], int(port)) + for port in VALKEY_CLUSTER_CONFIG["ports"].split(",") + ] + r = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + tracer = DummyTracer() + test_spans = TracerSpanContainer(tracer) + + Pin.get_from(r).clone(tracer=tracer).onto(r) + await r.get("key") + await r.close() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + span = spans[0] + assert span.service != "mysvc" + + asyncio.run(test()) + + +@pytest.mark.subprocess( + env=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1"), + err=None, # avoid checking stderr because of an expected deprecation warning +) +def test_user_specified_service_v1(): + """ + When a user specifies a service for the app + The valkeycluster integration should use it. + """ + import asyncio + + import valkey + + from ddtrace import config + from ddtrace.contrib.internal.valkey.patch import patch + from ddtrace.trace import Pin + from tests.contrib.config import VALKEY_CLUSTER_CONFIG + from tests.utils import DummyTracer + from tests.utils import TracerSpanContainer + + patch() + + async def test(): + # # Ensure that the service name was configured + assert config.service == "mysvc" + + startup_nodes = [ + valkey.asyncio.cluster.ClusterNode(VALKEY_CLUSTER_CONFIG["host"], int(port)) + for port in VALKEY_CLUSTER_CONFIG["ports"].split(",") + ] + r = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + tracer = DummyTracer() + test_spans = TracerSpanContainer(tracer) + + Pin.get_from(r).clone(tracer=tracer).onto(r) + await r.get("key") + await r.close() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + span = spans[0] + assert span.service == "mysvc" + + asyncio.run(test()) + + +@pytest.mark.subprocess( + env=dict(DD_VALKEY_SERVICE="myvalkeycluster", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0"), + err=None, # avoid checking stderr because of an expected deprecation warning +) +def test_env_user_specified_valkeycluster_service_v0(): + import asyncio + + import valkey + + from ddtrace.contrib.internal.valkey.patch import patch + from ddtrace.trace import Pin + from tests.contrib.config import VALKEY_CLUSTER_CONFIG + from tests.utils import DummyTracer + from tests.utils import TracerSpanContainer + + patch() + + async def test(): + startup_nodes = [ + valkey.asyncio.cluster.ClusterNode(VALKEY_CLUSTER_CONFIG["host"], int(port)) + for port in VALKEY_CLUSTER_CONFIG["ports"].split(",") + ] + r = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + tracer = DummyTracer() + test_spans = TracerSpanContainer(tracer) + + Pin.get_from(r).clone(tracer=tracer).onto(r) + await r.get("key") + await r.close() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + span = spans[0] + assert span.service == "myvalkeycluster" + + asyncio.run(test()) + + +@pytest.mark.subprocess( + env=dict(DD_VALKEY_SERVICE="myvalkeycluster", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1"), + err=None, # avoid checking stderr because of an expected deprecation warning +) +def test_env_user_specified_valkeycluster_service_v1(): + import asyncio + + import valkey + + from ddtrace.contrib.internal.valkey.patch import patch + from ddtrace.trace import Pin + from tests.contrib.config import VALKEY_CLUSTER_CONFIG + from tests.utils import DummyTracer + from tests.utils import TracerSpanContainer + + patch() + + async def test(): + startup_nodes = [ + valkey.asyncio.cluster.ClusterNode(VALKEY_CLUSTER_CONFIG["host"], int(port)) + for port in VALKEY_CLUSTER_CONFIG["ports"].split(",") + ] + r = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + tracer = DummyTracer() + test_spans = TracerSpanContainer(tracer) + + Pin.get_from(r).clone(tracer=tracer).onto(r) + await r.get("key") + await r.close() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + span = spans[0] + assert span.service == "myvalkeycluster" + + asyncio.run(test()) + + +@pytest.mark.subprocess( + env=dict( + DD_SERVICE="mysvc", + DD_VALKEY_SERVICE="myvalkeycluster", + DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0", + ), + err=None, # avoid checking stderr because of an expected deprecation warning +) +def test_service_precedence_v0(): + import asyncio + + import valkey + + from ddtrace import config + from ddtrace.contrib.internal.valkey.patch import patch + from ddtrace.trace import Pin + from tests.contrib.config import VALKEY_CLUSTER_CONFIG + from tests.utils import DummyTracer + from tests.utils import TracerSpanContainer + + patch() + + async def test(): + # # Ensure that the service name was configured + assert config.service == "mysvc" + + startup_nodes = [ + valkey.asyncio.cluster.ClusterNode(VALKEY_CLUSTER_CONFIG["host"], int(port)) + for port in VALKEY_CLUSTER_CONFIG["ports"].split(",") + ] + r = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + tracer = DummyTracer() + test_spans = TracerSpanContainer(tracer) + + Pin.get_from(r).clone(tracer=tracer).onto(r) + await r.get("key") + await r.close() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + span = spans[0] + assert span.service == "myvalkeycluster" + + asyncio.run(test()) + + +@pytest.mark.subprocess( + env=dict(DD_SERVICE="mysvc", DD_VALKEY_SERVICE="myvalkeycluster", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1"), + err=None, # avoid checking stderr because of an expected deprecation warning +) +def test_service_precedence_v1(): + import asyncio + + import valkey + + from ddtrace import config + from ddtrace.contrib.internal.valkey.patch import patch + from ddtrace.trace import Pin + from tests.contrib.config import VALKEY_CLUSTER_CONFIG + from tests.utils import DummyTracer + from tests.utils import TracerSpanContainer + + patch() + + async def test(): + # # Ensure that the service name was configured + assert config.service == "mysvc" + + startup_nodes = [ + valkey.asyncio.cluster.ClusterNode(VALKEY_CLUSTER_CONFIG["host"], int(port)) + for port in VALKEY_CLUSTER_CONFIG["ports"].split(",") + ] + r = valkey.asyncio.cluster.ValkeyCluster(startup_nodes=startup_nodes) + tracer = DummyTracer() + test_spans = TracerSpanContainer(tracer) + + Pin.get_from(r).clone(tracer=tracer).onto(r) + await r.get("key") + await r.close() + + traces = test_spans.pop_traces() + assert len(traces) == 1 + spans = traces[0] + assert len(spans) == 1 + span = spans[0] + assert span.service == "myvalkeycluster" + + asyncio.run(test()) diff --git a/tests/contrib/valkey/test_valkey_patch.py b/tests/contrib/valkey/test_valkey_patch.py new file mode 100644 index 00000000000..320d2b82b6a --- /dev/null +++ b/tests/contrib/valkey/test_valkey_patch.py @@ -0,0 +1,31 @@ +# This test script was automatically generated by the contrib-patch-tests.py +# script. If you want to make changes to it, you should make sure that you have +# removed the ``_generated`` suffix from the file name, to prevent the content +# from being overwritten by future re-generations. + +from ddtrace.contrib.internal.valkey.patch import get_version +from ddtrace.contrib.internal.valkey.patch import patch + + +try: + from ddtrace.contrib.internal.valkey.patch import unpatch +except ImportError: + unpatch = None +from tests.contrib.patch import PatchTestCase + + +class TestValkeyPatch(PatchTestCase.Base): + __integration_name__ = "valkey" + __module_name__ = "valkey" + __patch_func__ = patch + __unpatch_func__ = unpatch + __get_version__ = get_version + + def assert_module_patched(self, valkey): + pass + + def assert_not_module_patched(self, valkey): + pass + + def assert_not_module_double_patched(self, valkey): + pass diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json new file mode 100644 index 00000000000..0e980293801 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json @@ -0,0 +1,38 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_dd1.sr.eausr": 0.5, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 516916, + "start": 1692651820581556875 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json new file mode 100644 index 00000000000..5e3bf9dabb2 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json @@ -0,0 +1,38 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_dd1.sr.eausr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 340708, + "start": 1692651820591814875 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json new file mode 100644 index 00000000000..4175a987a06 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 335292, + "start": 1692651820600962708 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json new file mode 100644 index 00000000000..1acfd8989b4 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET here...", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 326167, + "start": 1692651820609597416 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json new file mode 100644 index 00000000000..8801294f1ab --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET here-is...", + "runtime-id": "ea409d0295db44adbf88dda3e4806547", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 20043, + "valkey.args_length": 2 + }, + "duration": 404084, + "start": 1692651821117540958 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json new file mode 100644 index 00000000000..ed75b8ef840 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json @@ -0,0 +1,74 @@ +[[ + { + "name": "valkey.command", + "service": "myvalkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "e263ff9ad1cd43099216a11ca5e19377", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 20046, + "valkey.args_length": 2 + }, + "duration": 501125, + "start": 1692651821692035875 + }], +[ + { + "name": "valkey.command", + "service": "cfg-valkey", + "resource": "GET", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "e263ff9ad1cd43099216a11ca5e19377", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 20046, + "valkey.args_length": 2 + }, + "duration": 329333, + "start": 1692651821722196292 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json new file mode 100644 index 00000000000..42f81d614af --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json @@ -0,0 +1,71 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET put_key_in_resource", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET put_key_in_resource", + "runtime-id": "3a1f7ba9b1ab42f4858e5effd03877ef", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 65639, + "valkey.args_length": 2 + }, + "duration": 2978000, + "start": 1698858795260743000 + }], +[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2", + "runtime-id": "3a1f7ba9b1ab42f4858e5effd03877ef", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 65639, + "valkey.pipeline_length": 2 + }, + "duration": 1408000, + "start": 1698858795278553000 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json new file mode 100644 index 00000000000..d53f49fbdc0 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json @@ -0,0 +1,71 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET put_key_in_resource", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.p.dm": "-0", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET put_key_in_resource", + "runtime-id": "451464ac55804a488cf355b1d96c7002", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 65646, + "valkey.args_length": 2 + }, + "duration": 3112000, + "start": 1698858796156355000 + }], +[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.p.dm": "-0", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2", + "runtime-id": "451464ac55804a488cf355b1d96c7002", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 65646, + "valkey.pipeline_length": 2 + }, + "duration": 1246000, + "start": 1698858796167913000 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json new file mode 100644 index 00000000000..b76ee2c3f9a --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "MGET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "MGET 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 36...", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 1001 + }, + "duration": 3428042, + "start": 1692651821775339875 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json new file mode 100644 index 00000000000..166c3f16942 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json @@ -0,0 +1,38 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "cheese": "camembert", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 474500, + "start": 1692651821790889125 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json new file mode 100644 index 00000000000..a1c4c7e690e --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json @@ -0,0 +1,56 @@ +[[ + { + "name": "valkey_get", + "service": "valkey_svc", + "resource": "valkey_get", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "language": "python", + "runtime-id": "3cf1df7fb079462ab81608355e026651" + }, + "metrics": { + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 19999 + }, + "duration": 534179, + "start": 1692651821803009280 + }, + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "valkey.args_length": 2 + }, + "duration": 358500, + "start": 1692651821803151542 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json new file mode 100644 index 00000000000..d3f2433934b --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json @@ -0,0 +1,72 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "SET a 1", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 3 + }, + "duration": 343500, + "start": 1692651821823333917 + }], +[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "SET a 1", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.pipeline_length": 1 + }, + "duration": 158750, + "start": 1692651821823756750 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json new file mode 100644 index 00000000000..4ed1ba0f8d8 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json @@ -0,0 +1,36 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET\nRPUSH\nHGETALL", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "SET blah 32\nRPUSH foo \u00e9\u00e9\nHGETALL xxx", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.pipeline_length": 3 + }, + "duration": 589917, + "start": 1692651821833429417 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json new file mode 100644 index 00000000000..832472e8c62 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "env-valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "app-svc", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "0f782133fa34462daf85cad95bb55fd2", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 20052, + "valkey.args_length": 2 + }, + "duration": 423750, + "start": 1692651822324419751 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json new file mode 100644 index 00000000000..4de19006a21 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET \ud83d\ude10", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 512083, + "start": 1692651822408832834 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json new file mode 100644 index 00000000000..68b95d4f134 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "mysvc", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "localhost", + "valkey.raw_command": "GET cheese", + "runtime-id": "9d4dd102c4394715976611e15b961233", + "server.address": "localhost", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 20056, + "valkey.args_length": 2 + }, + "duration": 439500, + "start": 1692651822941153668 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json new file mode 100644 index 00000000000..6c3b9225c83 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 595750, + "start": 1692651823036625793 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json new file mode 100644 index 00000000000..dd65f5e8be6 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json @@ -0,0 +1,57 @@ +[[ + { + "name": "web-request", + "service": "test", + "resource": "web-request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "language": "python", + "runtime-id": "3cf1df7fb079462ab81608355e026651" + }, + "metrics": { + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 19999 + }, + "duration": 828125, + "start": 1692651823188535376 + }, + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "out.host": "127.0.0.1", + "valkey.client_name": "testing-client-name", + "valkey.raw_command": "GET blah", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "valkey.args_length": 2 + }, + "duration": 541041, + "start": 1692651823188798168 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json new file mode 100644 index 00000000000..7c87d0b99be --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json @@ -0,0 +1,40 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 1, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "error.message": "whatever", + "error.stack": "Traceback (most recent call last):\n File \"/root/project/ddtrace/contrib/trace_utils_valkey.py\", line 117, in _trace_valkey_cmd\n yield span\n File \"/root/project/ddtrace/contrib/valkey/asyncio_patch.py\", line 22, in traced_async_execute_command\n return await _run_valkey_command_async(span=span, func=func, args=args, kwargs=kwargs)\n File \"/root/project/ddtrace/contrib/valkey/asyncio_patch.py\", line 41, in _run_valkey_command_async\n result = await func(*args, **kwargs)\n File \"/root/project/.riot/venv_py31011_mock_pytest_pytest-mock_coverage_pytest-cov_opentracing_hypothesis6451_pytest-asyncio_valkey~41/lib/python3.10/site-packages/valkey/asyncio/client.py\", line 509, in execute_command\n conn = self.connection or await pool.get_connection(command_name, **options)\n File \"/root/.pyenv/versions/3.10.11/lib/python3.10/unittest/mock.py\", line 2234, in _execute_mock_call\n raise effect\nvalkey.exceptions.ConnectionError: whatever\n", + "error.type": "valkey.exceptions.ConnectionError", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET foo", + "runtime-id": "dc59875580884b52bebd2f9c402238f8", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 2340, + "valkey.args_length": 2 + }, + "duration": 935417, + "start": 1695409673533997174 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json new file mode 100644 index 00000000000..27ad0f2f0cc --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json @@ -0,0 +1,73 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET \\x80foo \\x80abc", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 3 + }, + "duration": 512917, + "start": 1692651823066497751 + }], +[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET \\x80foo", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 330333, + "start": 1692651823067101001 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json new file mode 100644 index 00000000000..3ee539e27eb --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json @@ -0,0 +1,36 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET\nSET\nGET\nGET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET \\x80blah boo\nSET foo \\x80abc\nGET \\x80blah\nGET foo", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.pipeline_length": 4 + }, + "duration": 404709, + "start": 1692651823079707584 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json new file mode 100644 index 00000000000..86fa9c352ad --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "MGET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "MGET 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 36...", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 1001 + }, + "duration": 5689625, + "start": 1692651823091333793 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json new file mode 100644 index 00000000000..43ae49726d5 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json @@ -0,0 +1,110 @@ +[[ + { + "name": "valkey.command", + "service": "myvalkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 297666, + "start": 1692651823109161293 + }], +[ + { + "name": "valkey.command", + "service": "myvalkey", + "resource": "SET", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET cheese my-cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 3 + }, + "duration": 230084, + "start": 1692651823109550709 + }], +[ + { + "name": "valkey.command", + "service": "myvalkey", + "resource": "GET", + "trace_id": 2, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 160875, + "start": 1692651823109840043 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json new file mode 100644 index 00000000000..98c3fb8f5ae --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json @@ -0,0 +1,85 @@ +[[ + { + "name": "web-request", + "service": "test", + "resource": "web-request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "language": "python", + "runtime-id": "3cf1df7fb079462ab81608355e026651" + }, + "metrics": { + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 19999 + }, + "duration": 953000, + "start": 1692651823176740209 + }, + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET blah boo", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "valkey.args_length": 3 + }, + "duration": 270791, + "start": 1692651823176857918 + }, + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 3, + "parent_id": 1, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET blah", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "db.row_count": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "valkey.args_length": 2 + }, + "duration": 499000, + "start": 1692651823177170168 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json new file mode 100644 index 00000000000..ea6e0760ad5 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "my-valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET cheese", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 327417, + "start": 1692651823121474251 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json new file mode 100644 index 00000000000..8485f8418a0 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json @@ -0,0 +1,36 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET\nSET\nGET\nGET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET blah boo\nSET foo bar\nGET blah\nGET foo", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.pipeline_length": 4 + }, + "duration": 384125, + "start": 1692651823134602834 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json new file mode 100644 index 00000000000..12314de115e --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json @@ -0,0 +1,36 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET\nSET\nGET\nGET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET blah boo\nSET foo bar\nGET blah\nGET foo", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.pipeline_length": 4 + }, + "duration": 507125, + "start": 1692651823152247501 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json new file mode 100644 index 00000000000..f904b25d705 --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json @@ -0,0 +1,84 @@ +[[ + { + "name": "web-request", + "service": "test", + "resource": "web-request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "language": "python", + "runtime-id": "3cf1df7fb079462ab81608355e026651" + }, + "metrics": { + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 19999 + }, + "duration": 940000, + "start": 1692651823164019209 + }, + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET\nGET", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET blah boo\nGET blah", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "valkey.pipeline_length": 2 + }, + "duration": 352833, + "start": 1692651823164207293 + }, + { + "name": "valkey.command", + "service": "valkey", + "resource": "SET\nGET", + "trace_id": 0, + "span_id": 3, + "parent_id": 1, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "out.host": "127.0.0.1", + "valkey.raw_command": "SET foo bar\nGET foo", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "network.destination.port": 6379, + "out.valkey_db": 0, + "valkey.pipeline_length": 2 + }, + "duration": 310042, + "start": 1692651823164624126 + }]] diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json new file mode 100644 index 00000000000..f20464f381a --- /dev/null +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json @@ -0,0 +1,37 @@ +[[ + { + "name": "valkey.command", + "service": "valkey", + "resource": "GET", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "valkey", + "error": 0, + "meta": { + "_dd.base_service": "tests.contrib.valkey", + "_dd.p.dm": "-0", + "_dd.p.tid": "654a694400000000", + "component": "valkey", + "db.system": "valkey", + "language": "python", + "out.host": "127.0.0.1", + "valkey.raw_command": "GET \ud83d\ude10", + "runtime-id": "3cf1df7fb079462ab81608355e026651", + "server.address": "127.0.0.1", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "db.row_count": 0, + "network.destination.port": 6379, + "out.valkey_db": 0, + "process_id": 19999, + "valkey.args_length": 2 + }, + "duration": 300041, + "start": 1692651823049427543 + }]] From fcf1513bd1fa76bde4eddde52182c1a7342eb3f8 Mon Sep 17 00:00:00 2001 From: AhmadMasry Date: Sat, 18 Jan 2025 01:41:12 +0200 Subject: [PATCH 2/6] Add valkeycluster service --- tests/contrib/suitespec.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/contrib/suitespec.yml b/tests/contrib/suitespec.yml index 185d2b7560e..63d5f556e94 100644 --- a/tests/contrib/suitespec.yml +++ b/tests/contrib/suitespec.yml @@ -1197,5 +1197,6 @@ suites: pattern: ^valkey$ runner: riot services: + - valkeycluster - valkey snapshot: true From 8fe96e173244f4584120729f21af518c3bbd21a9 Mon Sep 17 00:00:00 2001 From: AhmadMasry Date: Sat, 18 Jan 2025 02:59:23 +0200 Subject: [PATCH 3/6] Add release notes --- .riot/requirements/11ac941.txt | 26 +++++++++++++++++ .riot/requirements/1e98e9b.txt | 26 +++++++++++++++++ .riot/requirements/4aa2a2a.txt | 22 ++++++++++++++ .riot/requirements/7219cf4.txt | 21 ++++++++++++++ .riot/requirements/dd68acc.txt | 24 +++++++++++++++ .../add-valkey-support-6cc9f41351dc0cd9.yaml | 29 +++++++++++++++++++ 6 files changed, 148 insertions(+) create mode 100644 .riot/requirements/11ac941.txt create mode 100644 .riot/requirements/1e98e9b.txt create mode 100644 .riot/requirements/4aa2a2a.txt create mode 100644 .riot/requirements/7219cf4.txt create mode 100644 .riot/requirements/dd68acc.txt create mode 100644 releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml diff --git a/.riot/requirements/11ac941.txt b/.riot/requirements/11ac941.txt new file mode 100644 index 00000000000..92df617ba6e --- /dev/null +++ b/.riot/requirements/11ac941.txt @@ -0,0 +1,26 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/11ac941.in +# +async-timeout==5.0.1 +attrs==24.3.0 +coverage[toml]==7.6.1 +exceptiongroup==1.2.2 +hypothesis==6.45.0 +importlib-metadata==8.5.0 +iniconfig==2.0.0 +mock==5.1.0 +opentracing==2.4.0 +packaging==24.2 +pluggy==1.5.0 +pytest==8.3.4 +pytest-asyncio==0.23.7 +pytest-cov==5.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.15.0 +sortedcontainers==2.4.0 +tomli==2.2.1 +valkey==6.0.2 +zipp==3.20.2 diff --git a/.riot/requirements/1e98e9b.txt b/.riot/requirements/1e98e9b.txt new file mode 100644 index 00000000000..6e2d11413c3 --- /dev/null +++ b/.riot/requirements/1e98e9b.txt @@ -0,0 +1,26 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/1e98e9b.in +# +async-timeout==5.0.1 +attrs==24.3.0 +coverage[toml]==7.6.10 +exceptiongroup==1.2.2 +hypothesis==6.45.0 +importlib-metadata==8.5.0 +iniconfig==2.0.0 +mock==5.1.0 +opentracing==2.4.0 +packaging==24.2 +pluggy==1.5.0 +pytest==8.3.4 +pytest-asyncio==0.23.7 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +sortedcontainers==2.4.0 +tomli==2.2.1 +valkey==6.0.2 +zipp==3.21.0 diff --git a/.riot/requirements/4aa2a2a.txt b/.riot/requirements/4aa2a2a.txt new file mode 100644 index 00000000000..6bc72515b3f --- /dev/null +++ b/.riot/requirements/4aa2a2a.txt @@ -0,0 +1,22 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/4aa2a2a.in +# +async-timeout==5.0.1 +attrs==24.3.0 +coverage[toml]==7.6.10 +hypothesis==6.45.0 +iniconfig==2.0.0 +mock==5.1.0 +opentracing==2.4.0 +packaging==24.2 +pluggy==1.5.0 +pytest==8.3.4 +pytest-asyncio==0.23.7 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +sortedcontainers==2.4.0 +valkey==6.0.2 diff --git a/.riot/requirements/7219cf4.txt b/.riot/requirements/7219cf4.txt new file mode 100644 index 00000000000..ffb631b7bcb --- /dev/null +++ b/.riot/requirements/7219cf4.txt @@ -0,0 +1,21 @@ +# +# This file is autogenerated by pip-compile with Python 3.13 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/7219cf4.in +# +attrs==24.3.0 +coverage[toml]==7.6.10 +hypothesis==6.45.0 +iniconfig==2.0.0 +mock==5.1.0 +opentracing==2.4.0 +packaging==24.2 +pluggy==1.5.0 +pytest==8.3.4 +pytest-asyncio==0.23.7 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +sortedcontainers==2.4.0 +valkey==6.0.2 diff --git a/.riot/requirements/dd68acc.txt b/.riot/requirements/dd68acc.txt new file mode 100644 index 00000000000..8eda9971324 --- /dev/null +++ b/.riot/requirements/dd68acc.txt @@ -0,0 +1,24 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/dd68acc.in +# +async-timeout==5.0.1 +attrs==24.3.0 +coverage[toml]==7.6.10 +exceptiongroup==1.2.2 +hypothesis==6.45.0 +iniconfig==2.0.0 +mock==5.1.0 +opentracing==2.4.0 +packaging==24.2 +pluggy==1.5.0 +pytest==8.3.4 +pytest-asyncio==0.23.7 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +sortedcontainers==2.4.0 +tomli==2.2.1 +valkey==6.0.2 diff --git a/releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml b/releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml new file mode 100644 index 00000000000..d2b71b0e20f --- /dev/null +++ b/releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml @@ -0,0 +1,29 @@ +--- +#instructions: +# The style guide below provides explanations, instructions, and templates to write your own release note. +# Once finished, all irrelevant sections (including this instruction section) should be removed, +# and the release note should be committed with the rest of the changes. +# +# The main goal of a release note is to provide a brief overview of a change and provide actionable steps to the user. +# The release note should clearly communicate what the change is, why the change was made, and how a user can migrate their code. +# +# The release note should also clearly distinguish between announcements and user instructions. Use: +# * Past tense for previous/existing behavior (ex: ``resulted, caused, failed``) +# * Third person present tense for the change itself (ex: ``adds, fixes, upgrades``) +# * Active present infinitive for user instructions (ex: ``set, use, add``) +# +# Release notes should: +# * Use plain language +# * Be concise +# * Include actionable steps with the necessary code changes +# * Include relevant links (bug issues, upstream issues or release notes, documentation pages) +# * Use full sentences with sentence-casing and punctuation. +# * Before using Datadog specific acronyms/terminology, a release note must first introduce them with a definition. +# +# Release notes should not: +# * Be vague. Example: ``fixes an issue in tracing``. +# * Use overly technical language +# * Use dynamic links (``stable/latest/1.x`` URLs). Instead, use static links (specific version, commit hash) whenever possible so that they don't break in the future. +features: + - | + Add support for Valkey instrumentation. \ No newline at end of file From cdc58275cdb7f58a2d242299f29169dc06175b79 Mon Sep 17 00:00:00 2001 From: AhmadMasry Date: Sat, 18 Jan 2025 11:09:50 +0200 Subject: [PATCH 4/6] Reformat snapshots --- ....valkey.test_valkey.test_analytics_with_rate.json | 4 ++-- ...lkey.test_valkey.test_analytics_without_rate.json | 4 ++-- ...tests.contrib.valkey.test_valkey.test_basics.json | 4 ++-- ...ib.valkey.test_valkey.test_custom_cmd_length.json | 4 ++-- ...alkey.test_valkey.test_custom_cmd_length_env.json | 4 ++-- ...alkey.test_env_user_specified_valkey_service.json | 8 ++++---- ..._valkey.test_full_command_in_resource_config.json | 8 ++++---- ...est_valkey.test_full_command_in_resource_env.json | 8 ++++---- ...contrib.valkey.test_valkey.test_long_command.json | 4 ++-- ...ontrib.valkey.test_valkey.test_meta_override.json | 4 ++-- ....contrib.valkey.test_valkey.test_opentracing.json | 4 ++-- ...b.valkey.test_valkey.test_pipeline_immediate.json | 8 ++++---- ...trib.valkey.test_valkey.test_pipeline_traced.json | 4 ++-- ...b.valkey.test_valkey.test_service_precedence.json | 4 ++-- ...ests.contrib.valkey.test_valkey.test_unicode.json | 4 ++-- ...lkey.test_valkey.test_user_specified_service.json | 4 ++-- ...alkey.test_valkey_asyncio.test_basic_request.json | 4 ++-- ....valkey.test_valkey_asyncio.test_client_name.json | 6 +++--- ...ey.test_valkey_asyncio.test_connection_error.json | 4 ++-- ...t_valkey_asyncio.test_decoding_non_utf8_args.json | 8 ++++---- ...asyncio.test_decoding_non_utf8_pipeline_args.json | 4 ++-- ...valkey.test_valkey_asyncio.test_long_command.json | 4 ++-- ...st_valkey_asyncio.test_override_service_name.json | 12 ++++++------ ...ib.valkey.test_valkey_asyncio.test_parenting.json | 8 ++++---- ....contrib.valkey.test_valkey_asyncio.test_pin.json | 4 ++-- ...key.test_valkey_asyncio.test_pipeline_traced.json | 4 ++-- ..._pipeline_traced_context_manager_transaction.json | 4 ++-- ...est_valkey_asyncio.test_two_traced_pipelines.json | 8 ++++---- ...key.test_valkey_asyncio.test_unicode_request.json | 4 ++-- 29 files changed, 77 insertions(+), 77 deletions(-) diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json index 0e980293801..cdc76343f08 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_with_rate.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json index 5e3bf9dabb2..9a2bb9f2e4f 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_analytics_without_rate.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json index 4175a987a06..e6da74211bb 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_basics.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json index 1acfd8989b4..5614e912961 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET here...", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET here..." }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json index 8801294f1ab..75f058f3700 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_custom_cmd_length_env.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET here-is...", "runtime-id": "ea409d0295db44adbf88dda3e4806547", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET here-is..." }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json index ed75b8ef840..f4b7d26f3a6 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_env_user_specified_valkey_service.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "e263ff9ad1cd43099216a11ca5e19377", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, @@ -53,10 +53,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "e263ff9ad1cd43099216a11ca5e19377", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json index 42f81d614af..c447412ee09 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_config.json @@ -15,10 +15,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET put_key_in_resource", "runtime-id": "3a1f7ba9b1ab42f4858e5effd03877ef", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET put_key_in_resource" }, "metrics": { "_dd.measured": 1, @@ -51,10 +51,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2", "runtime-id": "3a1f7ba9b1ab42f4858e5effd03877ef", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json index d53f49fbdc0..f7f89e8565a 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_full_command_in_resource_env.json @@ -15,10 +15,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET put_key_in_resource", "runtime-id": "451464ac55804a488cf355b1d96c7002", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET put_key_in_resource" }, "metrics": { "_dd.measured": 1, @@ -51,10 +51,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2", "runtime-id": "451464ac55804a488cf355b1d96c7002", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET pipeline-cmd1 1\nSET pipeline-cmd2 2" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json index b76ee2c3f9a..15378c706ba 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_long_command.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "MGET 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 36...", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "MGET 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 36..." }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json index 166c3f16942..5edc6b45665 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_meta_override.json @@ -17,10 +17,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json index a1c4c7e690e..749bd3d3307 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_opentracing.json @@ -39,9 +39,9 @@ "component": "valkey", "db.system": "valkey", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json index d3f2433934b..5559b6a5959 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_immediate.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "SET a 1", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET a 1" }, "metrics": { "_dd.measured": 1, @@ -52,10 +52,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "SET a 1", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET a 1" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json index 4ed1ba0f8d8..c5e90a181b3 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_pipeline_traced.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "SET blah 32\nRPUSH foo \u00e9\u00e9\nHGETALL xxx", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET blah 32\nRPUSH foo \u00e9\u00e9\nHGETALL xxx" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json index 832472e8c62..27979635427 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_service_precedence.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "0f782133fa34462daf85cad95bb55fd2", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json index 4de19006a21..09f6f46fd3d 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_unicode.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET \ud83d\ude10", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET \ud83d\ude10" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json b/tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json index 68b95d4f134..7a91612554e 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey.test_user_specified_service.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "localhost", - "valkey.raw_command": "GET cheese", "runtime-id": "9d4dd102c4394715976611e15b961233", "server.address": "localhost", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json index 6c3b9225c83..70b0e166d97 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_basic_request.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json index dd65f5e8be6..4f7b2688d76 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_client_name.json @@ -39,10 +39,10 @@ "component": "valkey", "db.system": "valkey", "out.host": "127.0.0.1", - "valkey.client_name": "testing-client-name", - "valkey.raw_command": "GET blah", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.client_name": "testing-client-name", + "valkey.raw_command": "GET blah" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json index 7c87d0b99be..64609dd8614 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_connection_error.json @@ -19,10 +19,10 @@ "error.type": "valkey.exceptions.ConnectionError", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "GET foo", "runtime-id": "dc59875580884b52bebd2f9c402238f8", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET foo" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json index 27ad0f2f0cc..649d89db933 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_args.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "SET \\x80foo \\x80abc", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET \\x80foo \\x80abc" }, "metrics": { "_dd.measured": 1, @@ -52,10 +52,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "GET \\x80foo", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET \\x80foo" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json index 3ee539e27eb..c22d2347b5e 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_decoding_non_utf8_pipeline_args.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "SET \\x80blah boo\nSET foo \\x80abc\nGET \\x80blah\nGET foo", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET \\x80blah boo\nSET foo \\x80abc\nGET \\x80blah\nGET foo" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json index 86fa9c352ad..9f4e40ffd1b 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_long_command.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "MGET 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 36...", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "MGET 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 36..." }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json index 43ae49726d5..f3d0bce583a 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_override_service_name.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, @@ -53,10 +53,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "SET cheese my-cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET cheese my-cheese" }, "metrics": { "_dd.measured": 1, @@ -89,10 +89,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json index 98c3fb8f5ae..c9a38d7fa31 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_parenting.json @@ -39,9 +39,9 @@ "component": "valkey", "db.system": "valkey", "out.host": "127.0.0.1", - "valkey.raw_command": "SET blah boo", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET blah boo" }, "metrics": { "_dd.measured": 1, @@ -68,9 +68,9 @@ "component": "valkey", "db.system": "valkey", "out.host": "127.0.0.1", - "valkey.raw_command": "GET blah", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET blah" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json index ea6e0760ad5..91c995cc259 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pin.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "GET cheese", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET cheese" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json index 8485f8418a0..e267216e24f 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "SET blah boo\nSET foo bar\nGET blah\nGET foo", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET blah boo\nSET foo bar\nGET blah\nGET foo" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json index 12314de115e..72633ef5e16 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_pipeline_traced_context_manager_transaction.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "SET blah boo\nSET foo bar\nGET blah\nGET foo", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET blah boo\nSET foo bar\nGET blah\nGET foo" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json index f904b25d705..60ff68c9b1b 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_two_traced_pipelines.json @@ -39,9 +39,9 @@ "component": "valkey", "db.system": "valkey", "out.host": "127.0.0.1", - "valkey.raw_command": "SET blah boo\nGET blah", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET blah boo\nGET blah" }, "metrics": { "_dd.measured": 1, @@ -68,9 +68,9 @@ "component": "valkey", "db.system": "valkey", "out.host": "127.0.0.1", - "valkey.raw_command": "SET foo bar\nGET foo", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "SET foo bar\nGET foo" }, "metrics": { "_dd.measured": 1, diff --git a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json index f20464f381a..c6db207fd51 100644 --- a/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json +++ b/tests/snapshots/tests.contrib.valkey.test_valkey_asyncio.test_unicode_request.json @@ -16,10 +16,10 @@ "db.system": "valkey", "language": "python", "out.host": "127.0.0.1", - "valkey.raw_command": "GET \ud83d\ude10", "runtime-id": "3cf1df7fb079462ab81608355e026651", "server.address": "127.0.0.1", - "span.kind": "client" + "span.kind": "client", + "valkey.raw_command": "GET \ud83d\ude10" }, "metrics": { "_dd.measured": 1, From 2a42d886f81bc3c445dea9d4fd89a8c6a2098576 Mon Sep 17 00:00:00 2001 From: Ahmad Al-Masry <33571825+AhmadMasry@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:27:15 +0200 Subject: [PATCH 5/6] Apply suggested changes --- ddtrace/contrib/valkey/__init__.py | 7 ----- .../add-valkey-support-6cc9f41351dc0cd9.yaml | 28 +------------------ 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/ddtrace/contrib/valkey/__init__.py b/ddtrace/contrib/valkey/__init__.py index eb369ae02cf..fd5e4474a1b 100644 --- a/ddtrace/contrib/valkey/__init__.py +++ b/ddtrace/contrib/valkey/__init__.py @@ -75,10 +75,3 @@ with _w.catch_warnings(): _w.simplefilter("ignore", DeprecationWarning) from . import patch as _ # noqa: F401, I001 - -# Expose public methods -from ddtrace.contrib.internal.valkey.patch import get_version -from ddtrace.contrib.internal.valkey.patch import patch - - -__all__ = ["patch", "get_version"] diff --git a/releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml b/releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml index d2b71b0e20f..6a8c47f01da 100644 --- a/releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml +++ b/releasenotes/notes/add-valkey-support-6cc9f41351dc0cd9.yaml @@ -1,29 +1,3 @@ ---- -#instructions: -# The style guide below provides explanations, instructions, and templates to write your own release note. -# Once finished, all irrelevant sections (including this instruction section) should be removed, -# and the release note should be committed with the rest of the changes. -# -# The main goal of a release note is to provide a brief overview of a change and provide actionable steps to the user. -# The release note should clearly communicate what the change is, why the change was made, and how a user can migrate their code. -# -# The release note should also clearly distinguish between announcements and user instructions. Use: -# * Past tense for previous/existing behavior (ex: ``resulted, caused, failed``) -# * Third person present tense for the change itself (ex: ``adds, fixes, upgrades``) -# * Active present infinitive for user instructions (ex: ``set, use, add``) -# -# Release notes should: -# * Use plain language -# * Be concise -# * Include actionable steps with the necessary code changes -# * Include relevant links (bug issues, upstream issues or release notes, documentation pages) -# * Use full sentences with sentence-casing and punctuation. -# * Before using Datadog specific acronyms/terminology, a release note must first introduce them with a definition. -# -# Release notes should not: -# * Be vague. Example: ``fixes an issue in tracing``. -# * Use overly technical language -# * Use dynamic links (``stable/latest/1.x`` URLs). Instead, use static links (specific version, commit hash) whenever possible so that they don't break in the future. features: - | - Add support for Valkey instrumentation. \ No newline at end of file + valkey: adds automatic instrumentation of the Valkey package \ No newline at end of file From e3d03f82a483c8d8db621890b2f1ded260baf84e Mon Sep 17 00:00:00 2001 From: Munir Abdinur Date: Thu, 23 Jan 2025 13:25:18 -0500 Subject: [PATCH 6/6] remove ddtrace/contrib/valkey --- ddtrace/contrib/internal/valkey/patch.py | 72 ++++++++++++++++- .../contrib/{ => internal}/valkey_utils.py | 0 ddtrace/contrib/trace_utils_valkey.py | 18 ----- ddtrace/contrib/valkey/__init__.py | 77 ------------------- ddtrace/contrib/valkey/asyncio_patch.py | 14 ---- ddtrace/contrib/valkey/patch.py | 14 ---- docs/integrations.rst | 2 +- tests/contrib/suitespec.yml | 2 - 8 files changed, 71 insertions(+), 128 deletions(-) rename ddtrace/contrib/{ => internal}/valkey_utils.py (100%) delete mode 100644 ddtrace/contrib/trace_utils_valkey.py delete mode 100644 ddtrace/contrib/valkey/__init__.py delete mode 100644 ddtrace/contrib/valkey/asyncio_patch.py delete mode 100644 ddtrace/contrib/valkey/patch.py diff --git a/ddtrace/contrib/internal/valkey/patch.py b/ddtrace/contrib/internal/valkey/patch.py index 4e077376149..7de63f947c1 100644 --- a/ddtrace/contrib/internal/valkey/patch.py +++ b/ddtrace/contrib/internal/valkey/patch.py @@ -1,3 +1,71 @@ +""" +The valkey integration traces valkey requests. + + +Enabling +~~~~~~~~ + +The valkey integration is enabled automatically when using +:ref:`ddtrace-run` or :ref:`import ddtrace.auto`. + +Or use :func:`patch()` to manually enable the integration:: + + from ddtrace import patch + patch(valkey=True) + + +Global Configuration +~~~~~~~~~~~~~~~~~~~~ + +.. py:data:: ddtrace.config.valkey["service"] + + The service name reported by default for valkey traces. + + This option can also be set with the ``DD_VALKEY_SERVICE`` environment + variable. + + Default: ``"valkey"`` + + +.. py:data:: ddtrace.config.valkey["cmd_max_length"] + + Max allowable size for the valkey command span tag. + Anything beyond the max length will be replaced with ``"..."``. + + This option can also be set with the ``DD_VALKEY_CMD_MAX_LENGTH`` environment + variable. + + Default: ``1000`` + + +.. py:data:: ddtrace.config.valkey["resource_only_command"] + + The span resource will only include the command executed. To include all + arguments in the span resource, set this value to ``False``. + + This option can also be set with the ``DD_VALKEY_RESOURCE_ONLY_COMMAND`` environment + variable. + + Default: ``True`` + + +Instance Configuration +~~~~~~~~~~~~~~~~~~~~~~ + +To configure particular valkey instances use the :class:`Pin ` API:: + + import valkey + from ddtrace.trace import Pin + + client = valkey.StrictValkey(host="localhost", port=6379) + + # Override service name for this instance + Pin.override(client, service="my-custom-queue") + + # Traces reported for this client will now have "my-custom-queue" + # as the service name. + client.get("my-key") +""" import os import valkey @@ -6,9 +74,9 @@ from ddtrace import config from ddtrace._trace.utils_valkey import _instrument_valkey_cmd from ddtrace._trace.utils_valkey import _instrument_valkey_execute_pipeline +from ddtrace.contrib.internal.valkey_utils import ROW_RETURNING_COMMANDS +from ddtrace.contrib.internal.valkey_utils import determine_row_count from ddtrace.contrib.trace_utils import unwrap -from ddtrace.contrib.valkey_utils import ROW_RETURNING_COMMANDS -from ddtrace.contrib.valkey_utils import determine_row_count from ddtrace.internal import core from ddtrace.internal.schema import schematize_service_name from ddtrace.internal.utils.formats import CMD_MAX_LEN diff --git a/ddtrace/contrib/valkey_utils.py b/ddtrace/contrib/internal/valkey_utils.py similarity index 100% rename from ddtrace/contrib/valkey_utils.py rename to ddtrace/contrib/internal/valkey_utils.py diff --git a/ddtrace/contrib/trace_utils_valkey.py b/ddtrace/contrib/trace_utils_valkey.py deleted file mode 100644 index b84ee7b955d..00000000000 --- a/ddtrace/contrib/trace_utils_valkey.py +++ /dev/null @@ -1,18 +0,0 @@ -from ddtrace.contrib.valkey_utils import determine_row_count -from ddtrace.contrib.valkey_utils import stringify_cache_args -from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning -from ddtrace.vendor.debtcollector import deprecate - - -deprecate( - "The ddtrace.contrib.trace_utils_valkey module is deprecated and will be removed.", - message="A new interface will be provided by the ddtrace.contrib.valkey_utils module", - category=DDTraceDeprecationWarning, -) - - -format_command_args = stringify_cache_args - - -def determine_row_count(valkey_command, span, result): # noqa: F811 - determine_row_count(valkey_command=valkey_command, result=result) diff --git a/ddtrace/contrib/valkey/__init__.py b/ddtrace/contrib/valkey/__init__.py deleted file mode 100644 index fd5e4474a1b..00000000000 --- a/ddtrace/contrib/valkey/__init__.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -The valkey integration traces valkey requests. - - -Enabling -~~~~~~~~ - -The valkey integration is enabled automatically when using -:ref:`ddtrace-run` or :ref:`import ddtrace.auto`. - -Or use :func:`patch()` to manually enable the integration:: - - from ddtrace import patch - patch(valkey=True) - - -Global Configuration -~~~~~~~~~~~~~~~~~~~~ - -.. py:data:: ddtrace.config.valkey["service"] - - The service name reported by default for valkey traces. - - This option can also be set with the ``DD_VALKEY_SERVICE`` environment - variable. - - Default: ``"valkey"`` - - -.. py:data:: ddtrace.config.valkey["cmd_max_length"] - - Max allowable size for the valkey command span tag. - Anything beyond the max length will be replaced with ``"..."``. - - This option can also be set with the ``DD_VALKEY_CMD_MAX_LENGTH`` environment - variable. - - Default: ``1000`` - - -.. py:data:: ddtrace.config.valkey["resource_only_command"] - - The span resource will only include the command executed. To include all - arguments in the span resource, set this value to ``False``. - - This option can also be set with the ``DD_VALKEY_RESOURCE_ONLY_COMMAND`` environment - variable. - - Default: ``True`` - - -Instance Configuration -~~~~~~~~~~~~~~~~~~~~~~ - -To configure particular valkey instances use the :class:`Pin ` API:: - - import valkey - from ddtrace.trace import Pin - - client = valkey.StrictValkey(host="localhost", port=6379) - - # Override service name for this instance - Pin.override(client, service="my-custom-queue") - - # Traces reported for this client will now have "my-custom-queue" - # as the service name. - client.get("my-key") -""" - - -# Required to allow users to import from `ddtrace.contrib.redis.patch` directly -import warnings as _w - - -with _w.catch_warnings(): - _w.simplefilter("ignore", DeprecationWarning) - from . import patch as _ # noqa: F401, I001 diff --git a/ddtrace/contrib/valkey/asyncio_patch.py b/ddtrace/contrib/valkey/asyncio_patch.py deleted file mode 100644 index 9ad800f1382..00000000000 --- a/ddtrace/contrib/valkey/asyncio_patch.py +++ /dev/null @@ -1,14 +0,0 @@ -from ddtrace.contrib.internal.valkey.asyncio_patch import * # noqa: F403 -from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning -from ddtrace.vendor.debtcollector import deprecate - - -def __getattr__(name): - deprecate( - ("%s.%s is deprecated" % (__name__, name)), - category=DDTraceDeprecationWarning, - ) - - if name in globals(): - return globals()[name] - raise AttributeError("%s has no attribute %s", __name__, name) diff --git a/ddtrace/contrib/valkey/patch.py b/ddtrace/contrib/valkey/patch.py deleted file mode 100644 index 242d5edcd23..00000000000 --- a/ddtrace/contrib/valkey/patch.py +++ /dev/null @@ -1,14 +0,0 @@ -from ddtrace.contrib.internal.valkey.patch import * # noqa: F403 -from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning -from ddtrace.vendor.debtcollector import deprecate - - -def __getattr__(name): - deprecate( - ("%s.%s is deprecated" % (__name__, name)), - category=DDTraceDeprecationWarning, - ) - - if name in globals(): - return globals()[name] - raise AttributeError("%s has no attribute %s", __name__, name) diff --git a/docs/integrations.rst b/docs/integrations.rst index 06739389406..541ad07322b 100644 --- a/docs/integrations.rst +++ b/docs/integrations.rst @@ -489,7 +489,7 @@ urllib3 valkey ^^^^^^ -.. automodule:: ddtrace.contrib.valkey +.. automodule:: ddtrace.contrib.valkey.patch .. _vertexai: diff --git a/tests/contrib/suitespec.yml b/tests/contrib/suitespec.yml index 63d5f556e94..6f852650892 100644 --- a/tests/contrib/suitespec.yml +++ b/tests/contrib/suitespec.yml @@ -244,8 +244,6 @@ components: - ddtrace/contrib/valkey/* - ddtrace/contrib/internal/valkey/* - ddtrace/_trace/utils_valkey.py - - ddtrace/contrib/valkey_utils.py - - ddtrace/contrib/trace_utils_valkey.py - ddtrace/ext/valkey.py vertica: - ddtrace/contrib/vertica/*