Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
208 commits
Select commit Hold shift + click to select a range
c65ec1b
[SECTION START: Core Data Models] Implement Scope, Symbol, ServiceVer…
Mar 9, 2026
7386c12
[Symbol Extraction] Add FileHash module for Git commit inference
Mar 9, 2026
929b9d7
[Symbol Extraction] Add Extractor for Ruby introspection
Mar 9, 2026
476c139
Fix linting for Symbol Extraction section
Mar 9, 2026
c872a6a
[SECTION END: Symbol Extraction] Complete implementation and testing
Mar 9, 2026
7318eb0
[SECTION START: Aggregation and Batching] Implement ScopeContext with…
Mar 9, 2026
1cd800d
[SECTION END: Aggregation and Batching] Complete with 99 tests passing
Mar 9, 2026
9b64e18
Move symbol_database out of di/ to top-level (peer relationship)
Mar 9, 2026
6ec3fd5
Remove temporary files from namespace migration
Mar 9, 2026
c0488ee
[SECTION START: Upload Mechanism] Implement Uploader with HTTP multipart
Mar 9, 2026
dc5ca23
[SECTION END: Upload Mechanism] Complete with 117 tests passing
Mar 9, 2026
abc214c
[Remote Config] Add Remote module and Component coordinator
Mar 9, 2026
93b0415
[SECTION END: Remote Config Integration] Complete remote config support
Mar 9, 2026
21c6037
[SECTION START: Configuration System] Add Settings with 3 env vars
Mar 9, 2026
6813dc5
[SECTION END: Configuration System] Complete
Mar 9, 2026
e7d485f
[SECTION START: Lifecycle Management] Wire symbol_database into tracer
Mar 9, 2026
3d9723d
[SECTION END: Lifecycle Management] Complete tracer integration
Mar 9, 2026
b120bde
Register symbol_database with remote config capabilities
Mar 9, 2026
0ba75e9
[SECTION START & END: Instrumentation and Logging] Verify logging exists
Mar 9, 2026
0d0c1c7
Add end-to-end integration test for MVP
Mar 9, 2026
4a0153b
Fix indentation in components.rb initialization
Mar 9, 2026
16d704c
Add symbol_database to attr_reader and shutdown
Mar 9, 2026
ee741bb
Add symbol_database to Components attr_reader list
Mar 9, 2026
9782542
Address PR feedback: error logging pattern, time provider, constants
Mar 9, 2026
51a2069
Add ERROR_HANDLING.md per PR feedback
Mar 9, 2026
e28476e
Register DD_SYMBOL_DATABASE_* env vars in supported-configurations.json
Mar 9, 2026
38657ba
Fix linting: Add symbol database env vars to supported configurations
Mar 9, 2026
9fe328b
Fix thread leaks in ScopeContext timer handling
Mar 9, 2026
9ee6ea1
Add RBS type signatures for Symbol Database
Mar 9, 2026
08c8d9c
Fix missing require for SymbolDatabase::Component
Mar 9, 2026
c1219a3
Fix component initialization issues
Mar 9, 2026
ad1c011
Add SymbolDatabase settings interface to Settings RBS
Mar 9, 2026
ce26061
Fix RBS stale file error by creating module definition files
Mar 9, 2026
8c50bbe
Fix semgrep SHA-1 false positive in file_hash.rb
Mar 9, 2026
97a7588
Fix CI test failures
Mar 9, 2026
c60aae3
Add missing RBS signature for configuration.rb
Mar 10, 2026
7b1b7cc
Add metrics and telemetry to match Java tracer observability
Mar 10, 2026
e48f51e
Add Steep ignore for symbol_database.rb module-level delegation
Mar 10, 2026
5b07553
Add comprehensive class-level documentation explaining purpose and in…
Mar 10, 2026
2f91e95
Add explicit Steepfile ignore for symbol_database.rb
Mar 10, 2026
350d918
Fix SymbolDatabase module initialization order
Mar 10, 2026
4f3188f
Add YARD documentation: @param, @return, @api private markers
Mar 10, 2026
81c541f
Fix nosemgrep comment placement for SHA-1 usage
Mar 10, 2026
f8f1917
Add defensive parameter extraction and detailed logging
Mar 10, 2026
957d7fa
Add stderr diagnostic logging for parameter extraction
Mar 10, 2026
aabbbdb
Remove debug stderr.puts statements from extractor
Mar 10, 2026
694e8ac
Add stderr diagnostic logging using warn() for parameter extraction
Mar 10, 2026
45adb3a
Fix linting: use begin/rescue instead of rescue modifier
Mar 10, 2026
9fa2064
Fix Ruby 2.5/2.6 compatibility in symbol database extractor
Mar 11, 2026
6e0a9e1
Rename UPLOAD_COOLDOWN to UPLOAD_COOLDOWN_INTERVAL
Mar 11, 2026
966350c
Add explanatory comments for MAX constants
Mar 11, 2026
9f39f57
Add justification for 0.1s timer join timeout
Mar 11, 2026
75e09b3
Rename pending? to scopes_pending?
Mar 11, 2026
4b32dce
Remove DI dependency requirement
Mar 11, 2026
3a35dfe
Remove global component variable, use components tree
Mar 11, 2026
c9ccdff
Move require 'json' to top of files
Mar 11, 2026
0d6b0f9
[WIP] Add comprehensive remote config integration test
Mar 11, 2026
3562990
Use WEBrick for RC integration tests like DI does
Mar 11, 2026
f0f3f2d
[REFACTOR] Migrate symbol database to use Core::Transport::HTTP infra…
Mar 11, 2026
1f13b94
[TEST] Update uploader tests to use transport mocks
Mar 11, 2026
7a72a67
[REFACTOR] Update component and tests to pass agent_settings to uploader
Mar 11, 2026
cb01fbf
Add Datadog namespace exclusion to prevent circular extraction
Mar 11, 2026
7d10ffd
Update integration tests to use /tmp for test classes
Mar 11, 2026
0ae1b0e
Merge branch 'refactor-transport-layer' into symbol-database-upload
Mar 11, 2026
068114d
Fix thread leak in concurrent scope additions
Mar 11, 2026
21276eb
Enable Steep type checking for symbol_database
Mar 11, 2026
4a5d7ef
[FIX] Parse remote config JSON string to Hash (was causing integratio…
Mar 11, 2026
3c3c7e3
Remove 'requires DI' comments from components.rb
Mar 11, 2026
0ac04af
Add telemetry to rescue blocks
Mar 11, 2026
84ebcdf
Remove debug output from code
Mar 11, 2026
0537310
Fix remote config integration by parsing JSON content
Mar 11, 2026
a437c40
Fix remaining integration test issues
Mar 11, 2026
92df698
Fix uploader retry tests, improve timer tests
Mar 11, 2026
c50dce9
[FIX] Fix remaining integration test failures and clean up tests
Mar 11, 2026
3d8c3a4
Replace magic numbers with named constants
Mar 11, 2026
d6a2882
[CLEANUP] Remove debug logging from component extraction
Mar 11, 2026
41e2956
Merge branch 'debug-integration-tests' into symbol-database-upload
Mar 11, 2026
e316232
Replace hardcoded /tmp paths with Dir.mktmpdir
Mar 11, 2026
5030007
Skip WIP comprehensive RC integration test
Mar 11, 2026
0c925ff
Replace sleep with deterministic checks in timer tests
Mar 11, 2026
fcb5b89
[REVIEW] Use UPLOAD_COOLDOWN_INTERVAL constant in comments
Mar 11, 2026
e6adddc
[REVIEW] Add explanatory comments for MAX_SCOPES and MAX_FILES
Mar 11, 2026
347748b
[REVIEW] Justify 0.1s timeout values in shutdown and reset
Mar 11, 2026
851a9be
[REVIEW] Remove dependency requirement debug message
Mar 11, 2026
906c840
[REVIEW] Add mutex protection to start_upload for thread safety
Mar 11, 2026
6a2ca90
[REVIEW] Add in-flight upload tracking to shutdown
Mar 11, 2026
37e9213
[TEST] Fix timer tests to use deterministic checks and remove debug file
Mar 11, 2026
23bd98f
Make timer testable with timer_enabled flag
Mar 11, 2026
3e9e155
[FIX] Update RBS signatures and ignore transport files in Steepfile
Mar 12, 2026
391460e
Remove final sleep calls from scope_context tests
Mar 12, 2026
791121b
Remove debugging diagnostics from extractor
Mar 12, 2026
720192e
Remove final hardcoded /tmp paths from tests
Mar 12, 2026
0775f32
Add RBS signatures for transport classes and enable type checking
Mar 12, 2026
e97057b
Fix Steep type checking errors
Mar 12, 2026
5b27d34
Remove timeout from Thread.join calls
Mar 12, 2026
eb757ff
Trigger CI re-run for zizmor
Mar 12, 2026
7a41912
Rename backoff constants and document retry exceptions
Mar 12, 2026
f743076
Add documentation and extract EXCLUDED_COMMON_MODULES constant
Mar 12, 2026
e36417e
Remove redundant @api private marker
Mar 12, 2026
f293fdd
Merge branch 'master' into symbol-database-upload
p-datadog Mar 12, 2026
172a65e
[FIX] Update test to use renamed constant MAX_BACKOFF_INTERVAL
Mar 12, 2026
8d10fa1
Add missing RBS declarations
Mar 12, 2026
a369728
Fix to_json parameter for Steep compatibility
Mar 12, 2026
9325436
Fix symbol.rb to_json parameter
Mar 12, 2026
f99db86
Fix Steep type checking errors
Mar 13, 2026
883c5ca
Fix remaining Steep type checking errors
Mar 13, 2026
f797fa2
Merge branch 'master' into symbol-database-upload
p-datadog Mar 13, 2026
a21bc05
Fix telemetry API, use verifying doubles, temp Java identifiers
Mar 17, 2026
cbc3e0d
Fix find_source_file to prefer user code over gem paths
Mar 17, 2026
5a2b800
Fix extractor crashing on classes that override Module#name with requ…
Mar 17, 2026
87837c8
Add deferred upload for Rails and shutdown guard to Component
Mar 17, 2026
a46dadb
Fix: wrap top-level CLASS scopes in MODULE for backend compatibility
Mar 17, 2026
dba3bcc
Fix: extract all user classes including namespaced ones, fix namespac…
Mar 17, 2026
0bf86a4
Use PACKAGE instead of MODULE wrapper for Ruby classes (interim fix)
Mar 17, 2026
2704ff9
Rename superclass → super_classes, emit as array
Mar 18, 2026
de0c19f
Emit self as first ARG in instance method scopes
Mar 18, 2026
b8204ad
Add edge case tests; accept class method gating from linter
Mar 18, 2026
db2a561
Add remaining edge case tests: class vars, value constants, file_hash…
Mar 18, 2026
ffbe158
Add internal setting for class method upload, fix method naming
Mar 18, 2026
91aeb04
Merge worktree-symdb-edge-cases: edge case tests
Mar 18, 2026
008666b
Remove noisy empty-params debug logs — zero-arg methods are normal
Mar 18, 2026
153762d
Port 38 Java symdb tests, update class methods design doc
Mar 18, 2026
3d8274e
Sync RBS signatures, register env var, fix filter_map in spec
Mar 18, 2026
1f79122
Port 24 Python symdb tests: remote config and configuration
Mar 18, 2026
710804f
Fix CI test failures: config map, unused variable, remove internal en…
Mar 18, 2026
6b582ce
Fix JRuby CI failures in extractor tests
Mar 18, 2026
1657e3e
Add unit tests for cases 7, 12, 13 from SYMBOL_EXTRACTION_CASES.md
Mar 18, 2026
db29022
Extract attr_* methods on JRuby despite nil source_location
Mar 18, 2026
857fbdd
Skip attr_accessor tests on JRuby; revert JRuby-specific production code
Mar 18, 2026
853a077
Skip stdlib filtering test on JRuby
Mar 18, 2026
6f56750
Fix StandardRB style violations in symbol_database
Mar 18, 2026
cf7f091
Add symbol_database files to Steep ignore list
Mar 18, 2026
9727d61
Add platform guards: symdb requires MRI Ruby 2.6+
Mar 18, 2026
f3de5cf
Skip all symdb specs on JRuby via global spec_helper hook
Mar 18, 2026
51ae4d3
Change root wrapper scope_type from PACKAGE to MODULE for system-test…
Mar 20, 2026
cd7b961
Use PACKAGE root scope with file-based naming for class wrappers
Mar 20, 2026
58f54cc
Use MODULE with file-based naming for class wrapper root scopes
Mar 20, 2026
0f170a0
Add unit tests for C-internal exclusion and Kernel filtering (E8, E9-…
p-ddsign Mar 22, 2026
cdb2016
Replace MODULE wrapper with FILE root scope and add extract_all
p-ddsign Mar 22, 2026
7b0b09b
Remove extract_nested_classes from extract path
p-ddsign Mar 22, 2026
901ee81
Fix user_code_path? to reject non-absolute paths
p-ddsign Mar 22, 2026
470da62
Add Ruby metaprogramming edge case tests
p-ddsign Mar 22, 2026
41ddd85
Fix StandardRB violations
p-ddsign Mar 22, 2026
7fbf94f
Fix macOS path mismatch in extract_all tests
p-ddsign Mar 22, 2026
68c2e13
Remove DD_SYMBOL_DATABASE_INCLUDES and internalize force_upload
p-ddsign Mar 22, 2026
32e1875
Use DD_INTERNAL_FORCE_SYMBOL_DATABASE_UPLOAD matching Java
p-ddsign Mar 22, 2026
2c6f29e
Fix macOS CI: add instance method to ExtractAllMixed test module
p-ddsign Mar 22, 2026
9c9253c
Resolve symlinks in source_location paths (macOS /var fix)
p-ddsign Mar 22, 2026
58f14f8
Add macOS path diagnostics and fix integration_spec missing realpath
p-ddsign Mar 22, 2026
f9ef632
Fix extract_all tests: match by content, not file path
p-ddsign Mar 22, 2026
add8e38
Document Symbol Database in DynamicInstrumentation.md
p-ddsign Mar 23, 2026
f2c50da
Fix symdb test failures on JRuby and Ruby 2.5
p-ddsign Mar 25, 2026
311871b
Fix bare .filter_map breaking Ruby 2.6 in extract_all
p-ddsign Mar 25, 2026
bf6c020
Add symdb diagnostics: logger facade, trace level, prefix normalization
p-ddsign Mar 26, 2026
7330d0d
Move param_name nil log to trace level, document introspection limita…
p-ddsign Mar 26, 2026
c5abef8
Fix StandardRB Style/KeywordParametersOrder violation
p-ddsign Mar 26, 2026
47689f0
Add missing RBS signature for SymbolDatabase::Logger
p-ddsign Mar 26, 2026
88ad41c
Refactor Extractor from static class methods to component instance
p-ddsign Mar 26, 2026
719215d
Ignore symdb files in Steep typecheck
p-ddsign Mar 26, 2026
8c28eb1
Remove workarounds: logger defaults, respond_to guard, Steepfile ignores
p-ddsign Mar 26, 2026
c93334a
Add YARD docs to Logger#trace
p-ddsign Mar 26, 2026
93b95f6
Fix Steep type errors in SymbolDatabase RBS signatures
p-ddsign Mar 26, 2026
11955b5
Replace non-running test files with working RC integration test
p-ddsign Mar 26, 2026
b1d55f5
Revert JAVA workaround: use RUBY language and ruby ddsource
p-ddsign Mar 27, 2026
1d20c33
Add diagnostic logging: extraction summary and per-scope trace
p-ddsign Mar 27, 2026
76e774b
Fix NoMethodError when transport returns InternalErrorResponse
p-ddsign Mar 27, 2026
4e9e0b7
Remove upload retries — single attempt, matching Python behavior
p-ddsign Mar 27, 2026
999a9f1
Log full scope tree at trace level during extraction
p-ddsign Mar 27, 2026
42800bd
Remove synthetic self ARG from instance method symbols
p-ddsign Mar 27, 2026
0767875
Extract empty classes (AR models, Forwardable-only) via const_source_…
p-ddsign Mar 27, 2026
8f68ee4
Lowercase language field: 'RUBY' → 'ruby'
p-ddsign Mar 27, 2026
47fd872
Add /test/ path exclusion; fix DI docs on generated method filtering
p-ddsign Mar 27, 2026
d979c2b
Add DI.exception_backtrace C extension to avoid customer code dispatch
p-ddsign Mar 27, 2026
9501405
Backfill CodeTracker registry with iseqs for pre-loaded files
p-ddsign Mar 23, 2026
e4d573a
Add error boundary to backfill_registry and rewrite tests with mocks
p-ddsign Mar 24, 2026
e6edc3a
Add integration test for line probe on pre-loaded file via backfill
p-ddsign Mar 24, 2026
5f8d59a
Stub backfill_registry in pre-existing tests
p-ddsign Mar 24, 2026
2de1271
Add DI.iseq_type C extension; use type instead of first_lineno in bac…
p-ddsign Mar 24, 2026
485e23f
Guard rb_iseq_type behind have_func for Ruby < 3.1 compat
p-ddsign Mar 24, 2026
cd918c8
Review fixes: doc comments, error handling test coverage, spec_helper…
p-ddsign Mar 27, 2026
5d18304
Document iseq_type Ruby 3.1 dependency and two-strategy backfill
p-ddsign Mar 27, 2026
b6b6b81
Fix inaccurate comment: first_lineno == 0 heuristic matches iseq_type
p-ddsign Mar 27, 2026
59efad8
Fix exception_backtrace to convert Thread::Backtrace to Array<String>
p-ddsign Mar 27, 2026
9b777e4
Fix StandardRB: remove redundant begin blocks
p-ddsign Mar 27, 2026
5b5eb0b
Add set_backtrace test and fix formatting in specs
p-ddsign Mar 27, 2026
70ca916
Add tests for calling backfill_registry twice
p-ddsign Mar 27, 2026
84f9acb
Remove respond_to?(:all_iseqs) guard from backfill_registry
p-ddsign Mar 27, 2026
dad426d
Return nil explicitly from backfill_registry
p-ddsign Mar 27, 2026
532d82e
Initialize @current_components to suppress Ruby 2.6/2.7 warning
p-ddsign Mar 27, 2026
23af140
Fix backfill_registry tests on Ruby < 3.1 (iseq_type unavailable)
p-ddsign Mar 27, 2026
8e0dffa
Disable GC during backfill integration test to prevent iseq collection
p-ddsign Mar 27, 2026
9801c99
Fix undefined symbol: use UnboundMethod instead of internal Ruby func…
p-ddsign Mar 27, 2026
a1c75f4
Fix undefined symbol: use have_func to gate rb_backtrace_p
p-ddsign Mar 27, 2026
4f8e503
Replace C exception_backtrace with Ruby UnboundMethod + backtrace_loc…
p-ddsign Mar 27, 2026
02037d2
Fix RBS signature: exception_backtrace returns Location not String
p-ddsign Mar 27, 2026
95541ba
Inline exception_backtrace: use constant directly at call site
p-ddsign Mar 27, 2026
c98fb09
Fix Steep: update RBS for format_backtrace and remove BACKTRACE_FRAME…
p-ddsign Mar 27, 2026
ebbea4b
Fix backfill_registry test failures
p-ddsign Mar 27, 2026
171d8a2
Fix StandardRB: add parens to ternary, remove extra blank line
p-ddsign Mar 27, 2026
5b0b256
Fix Steep: allow nil for @current_components
p-ddsign Mar 27, 2026
d5ec1bf
Support per-method iseqs for line probes on pre-loaded files
p-ddsign Mar 24, 2026
e8536d1
Add integration test for line probe via per-method iseq
p-ddsign Mar 25, 2026
d069cd9
Fix throwable integration test to include stacktrace
p-ddsign Mar 25, 2026
c9e3096
Update remote config test for new error message format
p-ddsign Mar 25, 2026
dee647b
Improve DITargetNotInRegistry error messages
p-ddsign Mar 25, 2026
072667c
Merge #5521 (di-c-ext-exception-backtrace) into base
p-ddsign Mar 28, 2026
5360bc1
Merge #5501 (di-per-method-iseq) into base
p-ddsign Mar 28, 2026
9aa5c2d
Merge #5431 (symbol-database-upload) into base
p-ddsign Mar 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- Leave resources open (terminate threads, close files)
- Make breaking public API changes
- Use `sleep` in tests for synchronization (use deterministic waits: Queue, ConditionVariable, flush methods that block, or mock time)
- Use non-verifying `double()` in tests — always use `instance_double(ClassName)`, `class_double(ClassName)`, or `object_double(instance)` so RSpec verifies method existence and arity against the real class

## Ask First

Expand Down Expand Up @@ -66,6 +67,17 @@ yamllint --strict .github/workflows/your-workflow.yml
actionlint .github/workflows/your-workflow.yml
```

## Troubleshooting

When investigating a bug or unexpected behavior:
1. State the observed behavior clearly
2. Formulate a specific, testable hypothesis
3. Verify the hypothesis with evidence (run code, read logs, add instrumentation) before proceeding
4. Do not guess at causes or propose fixes until the hypothesis is confirmed
5. If the hypothesis is disproven, formulate a new one — do not stack speculations
6. When the fix is found, document in learnings: observed behavior, hypothesis chain, root cause, and fix
7. Every hypothesis verification must become a test — if you checked behavior manually, encode that check as a spec so the expected behavior is retained in the test suite

## Code Changes

- Read files before editing them
Expand Down
2 changes: 2 additions & 0 deletions Steepfile
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ target :datadog do
ignore 'lib/datadog/di/transport/http/api.rb'
ignore 'lib/datadog/di/transport/http/diagnostics.rb'
ignore 'lib/datadog/di/transport/http/input.rb'
ignore 'lib/datadog/symbol_database/component.rb'
ignore 'lib/datadog/symbol_database/extractor.rb'
# steep thinks the type of the class is 'self', whatever that is,
# and then complains that this type doesn't have any methods including
# language basics like 'send' and 'raise'.
Expand Down
140 changes: 138 additions & 2 deletions docs/DynamicInstrumentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,9 @@ The value will fall back to default serialization.

## What Data Is Captured

When a probe fires, Dynamic Instrumentation captures a snapshot of
application state and sends it to Datadog. The snapshot includes:
Dynamic instrumentation sends some of the application data to Datadog.

**Probe snapshots** (captured when probes fire):

- **Variable values** — local variables, method arguments, and return
values, subject to the capture depth and collection size limits
Expand All @@ -311,6 +312,141 @@ application state and sends it to Datadog. The snapshot includes:
redacted.
- **Stack traces** — the call stack at the point the probe fires.

**Symbol Database** (uploaded once at startup, see below):

- Class, module, and method names from user application code
- Method parameter names (not values)
- Source file paths and line ranges
- File content hashes (for source code version matching)
- No runtime values, variable contents, or application data

## Symbol Database

The Symbol Database powers auto-completion in the Dynamic Instrumentation
UI. When enabled, the tracer extracts symbol information (classes,
modules, methods, parameters) from your running application and uploads
it to Datadog via the Agent. This allows the DI UI to suggest class
names, method names, and method parameters when creating probes.

### Enabling the Symbol Database

Symbol Database upload is enabled by default when Dynamic Instrumentation
is enabled. No additional configuration is required. It activates via
Remote Configuration when the DI UI is opened for your service.

To explicitly disable it:

export DD_SYMBOL_DATABASE_UPLOAD_ENABLED=false

For testing without Remote Configuration:

export DD_INTERNAL_FORCE_SYMBOL_DATABASE_UPLOAD=true

### What Is Extracted

The Symbol Database extracts metadata about your application's structure.
It does **not** extract runtime values, variable contents, or any data
that flows through your application.

**Extracted:**
- Class and module names
- Method names and parameter names (not values)
- Method visibility (public, private, protected)
- Class inheritance (`superclass`) and module inclusion
(`included_modules`, `prepended_modules`)
- Class variables and constants (names only, not values)
- Source file paths and line ranges
- File content hashes (Git-compatible SHA-1, for commit inference)

**Note on generated methods:** Methods generated by `attr_writer`,
`attr_accessor`, ActiveRecord associations, and similar metaprogramming
are **not extracted**. Their `source_location` points to gem or stdlib
code (e.g. `activerecord/lib/...`, `forwardable.rb`), so they are
filtered out along with other non-user code. Only methods whose source
is in your application files appear in autocomplete.

**Not extracted:**
- Instance variable names or values
- Local variable names or values
- Method return types (Ruby is dynamically typed)
- Runtime data of any kind

### What Is Uploaded

Symbol data is uploaded to the Datadog Agent as compressed JSON via the
`/symdb/v1/input` endpoint. The Agent forwards it to the Datadog
backend. Uploads occur once at startup (after Remote Configuration
enables the feature) and are deduplicated — the same symbols are not
re-uploaded unless the application restarts.

### Which Code Is Included

Only **user application code** is extracted. The following are
automatically excluded:

- All installed gems (detected via `/gems/` in the source path)
- Ruby standard library
- The Datadog tracer itself (`Datadog::` namespace)
- Test code (`/spec/`, `/test/` paths)
- Code loaded via `eval()`

This means internal or private gems installed via Bundler are also
excluded. There is currently no mechanism to force-include specific
gems.

### Behavior Differences from Other Tracers

Ruby's Symbol Database implementation differs from Java, Python, and
.NET in several ways:

#### Scope hierarchy

Ruby uses `FILE` as the root scope type (one per source file), with
`CLASS` or `MODULE` scopes nested inside. Java uses `JAR`, .NET uses
`ASSEMBLY`, and Python uses `MODULE` (one per Python module file).
Within each root scope, all tracers extract `CLASS` and `METHOD` scopes.

#### Code filtering

Java, Python, and .NET ship curated lists of known third-party package
names (600+ to 5,000 entries) and support `DD_THIRD_PARTY_DETECTION_EXCLUDES`
to force-include specific libraries. Ruby uses path-based filtering
(`/gems/`, `/ruby/`) instead, which is effective for Ruby's gem
ecosystem but does not support overrides. The
`DD_THIRD_PARTY_DETECTION_INCLUDES` and `DD_THIRD_PARTY_DETECTION_EXCLUDES`
environment variables are not yet implemented for Ruby.

#### Deferred features

The following features available in other tracers are not yet
implemented for Ruby:

- **Instance variable extraction** (FIELD symbols) — Java and .NET
extract class fields; Ruby would require runtime introspection or
source parsing
- **Local variable extraction** (LOCAL scopes) — Java and .NET extract
local variables from bytecode/PDB debug info; not available via Ruby
introspection
- **Closure/block scopes** — .NET extracts lambda and async closure
scopes; Ruby blocks, procs, and lambdas are not yet extracted
- **Payload splitting** — Java splits uploads exceeding 50 MB into
smaller chunks; Ruby skips the upload entirely if it exceeds 50 MB
(unlikely for typical applications)
- **Fork deduplication** — Python coordinates uploads across forked
workers (Gunicorn, uWSGI); Ruby does not yet deduplicate uploads in
preforking servers (Puma clustered mode, Unicorn, Passenger), meaning
each worker uploads independently
- **Injectable line information** — Go and .NET report which lines
within a method can accept probes; Ruby does not include this metadata

#### Class methods

Class methods (`def self.foo`) are extracted but **not uploaded** by
default. Ruby's Dynamic Instrumentation can only instrument instance
methods (via `prepend`), so including class methods would present
completions for methods that cannot be probed. This may change when DI
gains singleton class instrumentation support.

## Rate Limiting and Performance

### Default Rate Limits
Expand Down
190 changes: 190 additions & 0 deletions docs/class_methods_di_design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Class Methods in Symbol Database

## What Are Class Methods in Ruby?

In Ruby, class methods are defined on the singleton class of the class object:

```ruby
class User
def digest(string) # instance method — User#digest
BCrypt::Password.create(string)
end

def self.digest(string) # class method — User.digest
BCrypt::Password.create(string)
end
end
```

Both can coexist with the same name. They are completely separate methods accessed
through different lookup chains.

## Cross-Language Equivalents

| Language | Equivalent | Same name as instance method possible? | DI support |
|----------|-----------|---------------------------------------|-----------|
| Ruby | `def self.foo` (singleton method) | Yes | No (see below) |
| Java | `static` method | Yes — resolves via `INVOKEVIRTUAL` vs `INVOKESTATIC` | Yes |
| C# (.NET) | `static` method | Yes | Yes |
| JavaScript | `static foo()` | Yes | Yes |
| Python | `@classmethod` / `@staticmethod` | No — second definition overwrites first | Yes |
| Go | Package-level function | Not applicable (no classes) | Yes (functions) |

Java, C#, and JavaScript all support same-name instance + class methods and DI
instruments both. Python avoids the naming collision entirely.

## Why Ruby Class Methods Are Not Uploaded by Default

Ruby DI instruments methods by prepending a module to a class's instance method
lookup chain:

```ruby
cls.prepend(instrumentation_module)
```

This intercepts calls to **instance methods** (`cls.instance_method(:foo)`).
It does **not** affect the singleton class. To instrument a class method, DI
would need:

```ruby
cls.singleton_class.prepend(instrumentation_module)
```

This is not currently implemented in `lib/datadog/di/instrumenter.rb` — it only
calls `cls.instance_method(method_name).source_location` (line 104) and never
touches the singleton class.

**Consequence:** Including class method scopes in symdb payloads would present
completions in the DI UI for methods that cannot be probed. This is misleading
and potentially confusing for users.

## Backend Disambiguation: Java Static vs Instance Methods

For languages where the same method name can exist as both instance and static,
the probe specification uses the `signature` field in `Where` (Java's probe location):

```java
// com.datadog.debugger.probe.Where
String typeName; // "com.example.User"
String methodName; // "digest"
String signature; // "(Ljava/lang/String;)Ljava/lang/String;" — JVM descriptor
```

The JVM method descriptor encodes parameter and return types. Since static and
instance methods both appear in the class's method table but with different
descriptors (static methods don't have an implicit `this`), the signature
disambiguates them.

For Ruby, `method_type: "class"` in `language_specifics` serves this purpose once
DI supports class method instrumentation.

## Current Implementation

Class methods are extracted but **gated behind an internal setting**:

```ruby
# Default: false — class methods not uploaded
Datadog.configuration.symbol_database.internal.upload_class_methods

# Or via env var (internal use only):
DD_INTERNAL_SYMBOL_DATABASE_UPLOAD_CLASS_METHODS=true
```

When enabled, class methods are emitted as `METHOD` scopes with:
- `name: "method_name"` (bare name, no `self.` prefix)
- `language_specifics.method_type: "class"`

The bare name (no `self.` prefix) matches Java/C# conventions. The
`method_type: "class"` field disambiguates from instance methods with the
same name — this is the standard cross-language approach used by all other
Datadog tracers.

## Path to Enabling Class Methods

1. Implement singleton class instrumentation in `lib/datadog/di/instrumenter.rb`:
- Detect `method_type: "class"` in probe definition
- Use `cls.singleton_class.prepend(...)` instead of `cls.prepend(...)`
- Use `cls.singleton_class.instance_method(name)` for source location lookup

2. Switch default to `true` and move setting from `internal` to public:
```ruby
option :upload_class_methods do |o|
o.type :bool
o.default true # once DI instruments class methods
end
```

3. The backend already stores `method_type` and can use it for DI UI completions
once the tracer can deliver on the probe.

## Probe Spec Disambiguation (UI → Tracer via RC)

The probe specification sent from the backend to the tracer via Remote Config uses
`MethodProbeLocation` (TypeScript type in web-ui):

```typescript
// packages/api/endpoints/live-debugger/types/probe/probe-location.types.ts
type MethodProbeLocation = {
typeName: string; // e.g. "User"
methodName: string; // e.g. "digest"
signature?: string; // e.g. "String(Number, Object)" — optional
};
```

There is **no `isClassMethod` or `isStatic` boolean** in the probe spec. For Java,
disambiguation relies on the `signature` field: since static and instance methods have
different JVM descriptors (static omits the implicit `this` parameter), the tracer can
match the signature to the bytecode `MethodNode.access & Opcodes.ACC_STATIC`.

**For Ruby, this approach doesn't work** because Ruby methods are untyped — a class
method `def self.digest(string)` and instance method `def digest(string)` have
identical `Method#parameters` output: `[[:req, :string]]`. There is no signature
to distinguish them.

**When Ruby DI adds class method support**, either:
1. A new boolean field must be added to `MethodProbeLocation` (e.g. `isClassMethod`)
2. Or the `signature` field is repurposed with a Ruby-specific convention

This requires coordination between the web-ui, backend probe spec, and Ruby tracer.

## `self` as an Implicit Argument

Ruby DI emits `self` as the first `ARG` symbol for **instance methods** only.
`self` is not in `Method#parameters` (it's implicit), but it must be registered so
DI expression language can evaluate `self.name`, `self.class`, etc. at a probe point.

For **class methods**, `self` is the class object itself — still accessible but less
useful for DI expression evaluation, and not emitted to keep parity with other tracers.

```ruby
# In extract_method_parameters (extractor.rb):
self_arg = if method_type == :instance
[Symbol.new(symbol_type: 'ARG', name: 'self', line: UNKNOWN_MIN_LINE)]
else
[] # class methods: self not emitted
end
```

## UI: How the Frontend Surfaces Methods

The frontend uses these symdb API endpoints (web-ui/packages/api/endpoints/live-debugger/):
- `/api/unstable/symdb-api/scopes/search` — search by class/method name
- `/api/unstable/symdb-api/completions/scope/method` — get completions for a method probe

The `DebuggerSymbolApi` type returned from search does NOT include `method_type` — the
`LanguageSpecifics` type exposed to the frontend has `accessModifiers`, `annotations`,
`interfaces`, `superClasses`, `returnType`, but no `method_type` or `isStatic`.

**Implication:** Even if we upload class methods, the UI currently cannot distinguish
them from instance methods in the search results. The `method_type: "class"` field
is stored in the backend database but not surfaced to the frontend. Surfacing it would
require a frontend change to `LanguageSpecifics` and UI rendering logic.

## References

- `lib/datadog/di/instrumenter.rb:104` — current instance-method-only lookup
- `lib/datadog/symbol_database/extractor.rb` — `extract_singleton_method_scope`, `extract_method_parameters`
- `lib/datadog/symbol_database/configuration/settings.rb` — `upload_class_methods` setting
- `debugger-backend/debugger-common/.../TracerVersionChecker.kt` — language min versions
- `web-ui/packages/api/endpoints/live-debugger/types/probe/probe-location.types.ts` — probe spec
- `web-ui/packages/api/endpoints/live-debugger/types/symdb-scopes.types.ts` — LanguageSpecifics type
Loading
Loading