Skip to content

[BUG]: Rails ActiveSupport Cache instrumentation key duplication #5402

Description

@ggambetti

Tracer Version(s)

v2.22.0

Ruby Version(s)

3.4.8

Relevent Library and Version(s)

Rails 8.0

Bug Report

Rails ActiveSupport Cache tracing integration appears to duplicate keys when #fetch is called as a result of PreserveOriginalKey unconditionally appending key to the key list.

When a #fetch call occurs, the arguments are processed both by #fetch and again by #write. This causes PreserveOriginalKey to be invoked a second time on an already processed options hash, appending to the :dd_original_keys member. The stack trace is:

I believe normalize_key is more correctly implemented as:

              def normalize_key(key, options)
                options[:dd_original_keys] = options[:dd_original_keys] || [key]

                super
              end

edit: The above code block is incorrect for calls with multiple keys, ie: multi_fetch, multi_write, and multi_read. I think an inclusion check needs to be performed.

              def normalize_key(key, options)
                orig_keys = options[:dd_original_keys] || []
                # Deal with fetch passing keys through normalization twice.
                orig_keys << key unless orig_keys.include?(key)
                options[:dd_original_keys] = orig_keys

                super
              end

Reproduction Code

Adding this test to spec/datadog/tracing/contrib/rails/cache_spec.rb #fetch should break:

    context 'with value' do                                                                                                                                             
      it do                                                                                                                                                             
        expect { fetch }.to eq('default')                                                                                                                               
                                                                                                                                                                        
        expect(span.get_tag('rails.cache.key')).to eq(key)                                                                                                              
      end                                                                                                                                                               
    end

What I've observed in production is that the rails.cache.key tag has the value key + "/" + key.

Configuration Block

No response

Error Logs

No response

Operating System

hub.docker.com ruby:3.4.8-alpine3.23

How does Datadog help you?

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugInvolves a bugcommunityWas opened by a community memberintegrationsInvolves tracing integrations

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions