Scavenger Documentation
repository·develop·Indexed 19 days ago
https://github.com/naver/scavengerA runtime dead code analysis system for JVM-based languages. Scavenger identifies unused code without requiring code changes using a full stack consisting of a Collector, API, and Frontend. It includes a Java agent and a BETA Python agent (scavenger-agent-python v0.1.2) to collect invocation data and visualize it via a web-based interface.
What's inside Scavenger
- Scavenger is a tool designed to analyze runtime dead code in JVM-based languages without requiring code changes. It helps developers identify unused code that accumulates due to changing requirements and specifications. It provides a web-based interface for project management, invocation snapshots, and dashboards.
Understand Scavenger Codebases and Lifecycle
developIn Scavenger, a codebase is a representation of the code being scanned at the time of collection.
New Codebase Triggers
Scavenger treats the code as a new codebase and performs a new upload if:
- The content of the code changes.
- The scanning settings (such as
packages) are modified.
Data Preservation and Garbage Collection
- Method Identification: Each method is identified by a unique signature (a function signal).
- Call Information: Call information is recorded based on the method in each codebase. If a method's signature remains unchanged between codebase uploads, its call information is preserved.
- Garbage Collection: When a new codebase is uploaded, a garbage collector runs at regular intervals to remove methods from the old codebase that are no longer present in the new one, while inserting new methods.
How Scavenger components work together
developScavenger operates through several interconnected components:
- Scavenger Agent: Collects the codebase and regularly sends host application invocation data to collectors. There are versions for Java and a (BETA) Python agent.
- Scavenger Collector: Receives data from the agent and stores it in a database (supporting MySQL, Vitess, or H2). It also handles garbage cleanup.
- Scavenger API: Provides APIs for exploring and querying invocation data.
- Scavenger Frontend: Provides the web-based user interface for interacting with the system.
Limitations of Scavenger Agent Python
developKeep the following technical limitations in mind when using the Python agent:
- Reference-based Instrumentation: The agent works by replacing the reference of the current module/class. It will not work if a function is called without using a reference (e.g., if a framework uses a Decorator to save only the function reference without the module context).
Example of what currently fails:
@app.route('/') def hello_world(): return 'Hello World!' - No pyc Support: Direct instrumentation for
.pycfiles is not supported; the agent requires access to the original Python source code. - Manual Shutdown: As noted,
agent.shutdown()must be manually invoked.
- Reference-based Instrumentation: The agent works by replacing the reference of the current module/class. It will not work if a function is called without using a reference (e.g., if a framework uses a Decorator to save only the function reference without the module context).
Example of what currently fails:
Generate a Scavenger Agent configuration file
developIf you are using the Scavenger Agent, you need a configuration file to define its runtime settings. Scavenger provides a built-in generator to simplify this process:
- In the Scavenger UI, click the Show Scavenger configuration file generator button.
- In the Create scavenger configuration file modal, configure your desired settings.
- Click the Download button to save the configuration file for use with your agent.
Build the Scavenger Agent from source
developIf you prefer to build the Scavenger Agent manually rather than downloading a pre-built JAR, follow these steps:
- Clone the Scavenger repository from Git.
- Use the Gradle wrapper to assemble the Java agent specifically.
Note: You must have the Scavenger project built before running the agent-specific assembly command.
./gradlew assemble -p scavenger-agent-javaPrerequisites for Scavenger
developBefore using Scavenger, you must install both the Collector and the API.
By default, this guide assumes the following network configuration:
- Collector: port
8080 - API: port
8081
- Collector: port
Analyze snapshots and call treemaps
developOnce a snapshot is created, you can analyze the invocation state through the Scavenger UI. The analysis view provides:
- Snapshot Recreation: Ability to recreate a snapshot based on the most recent invocation state currently collected.
- Call Treemap: A visual graph of calls within a selected package.
- Area Size: Represents the number of methods (larger area = more methods).
- Color: Represents the call percentage (black color = lower percentage of calls).
- Package-level Status: Displays the number of methods and the invocation rate per package.
- Code Integration: Links to open the specific class directly in IntelliJ or GitHub.
Create a Snapshot to analyze invocation history
developSnapshots allow you to view the invocation history of methods after a specific point in time (similar to a heap dump) based on data gathered by the Scavenger Collector.
How to create a snapshot
- Navigate to Snapshots in the LNB (Left Navigation Bar) menu.
- Click the Create button.
- Fill in the configuration details in the Create Snapshot modal.
- Click Create.
Snapshot Configuration Reference
Configuration Description NameA unique name for the snapshot. ApplicationThe applications to include. You can specify multiple applications. Note: To correctly detect dead code in a shared module (e.g., core), you must include all applications that use it (e.g.,apiandbatch).EnvironmentThe environments to include. You can target specific environments or all environments. PackagesThe packages to include. Supports comma-separated values and ant-style matching (e.g., *,**). If left empty, all packages are included.Filter invoked atOnly counts invocations occurring after this timestamp. For example, specifying 2022.10.23 10:00means methods only invoked before this time will be evaluated as dead code.Debug the Scavenger Agent using Remote JVM Debug
developTo debug the Scavenger Agent, you must configure a Remote JVM Debug session in your IDE (such as IntelliJ IDEA) and run the agent with specific JVM options to allow the debugger to attach via a socket.
1. Prepare the Debug Configuration
In your IDE, create a new Run/Debug Configuration of type Remote JVM Debug. Use the following settings:
- Host:
localhost - Port:
5005 - JVM option:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
2. Start Debugging
- Execute the agent startup script:
./run-agent.sh. - Run the Remote JVM Debug configuration you created in step 1.
- Begin debugging using your IDE's standard tools (breakpoints, stepping, etc.).
# Step 1: Run the agent ./run-agent.sh # Step 2: Use these JVM options in your configuration -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005- Host:
Create a workspace in Scavenger
developTo begin managing your data, connect to the Scavenger API at
http://{API host}:8081/scavengerand follow these steps:- Click the Create workspace button in the bottom left corner.
- In the modal that appears, enter a name for your workspace.
- Click Create to finalize the workspace setup.
Build and install the Scavenger API
developThe API can be obtained via the GitHub releases page or built manually.
To build the API manually, run:
./gradlew assemble -p scavenger-apiTo start the API, you must specify the Collector's URL using the
scavenger.collector-server-urlproperty:java -Dscavenger.collector-server-url=http://localhost:8080 -jar scavenger-api-boot.jar./gradlew assemble -p scavenger-api java -Dscavenger.collector-server-url=http://localhost:8080 -jar scavenger-api-boot.jar