Scavenger Documentation

repository·develop·Indexed 19 days ago

https://github.com/naver/scavenger

A 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.

Tokens
7K
Snippets
21
Records
36
Agent score
67%

What's inside Scavenger

  1. Overview of Scavenger

    develop
    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.
  2. Understand Scavenger Codebases and Lifecycle

    develop

    In 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:

    1. The content of the code changes.
    2. 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.
  3. How Scavenger components work together

    develop

    Scavenger 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.
  4. Limitations of Scavenger Agent Python

    develop

    Keep the following technical limitations in mind when using the Python agent:

    1. 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!'
    2. No pyc Support: Direct instrumentation for .pyc files is not supported; the agent requires access to the original Python source code.
    3. Manual Shutdown: As noted, agent.shutdown() must be manually invoked.
  5. Generate a Scavenger Agent configuration file

    develop

    If 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:

    1. In the Scavenger UI, click the Show Scavenger configuration file generator button.
    2. In the Create scavenger configuration file modal, configure your desired settings.
    3. Click the Download button to save the configuration file for use with your agent.
  6. Build the Scavenger Agent from source

    develop

    If you prefer to build the Scavenger Agent manually rather than downloading a pre-built JAR, follow these steps:

    1. Clone the Scavenger repository from Git.
    2. 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-java
  7. Analyze snapshots and call treemaps

    develop

    Once 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.
  8. Create a Snapshot to analyze invocation history

    develop

    Snapshots 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

    1. Navigate to Snapshots in the LNB (Left Navigation Bar) menu.
    2. Click the Create button.
    3. Fill in the configuration details in the Create Snapshot modal.
    4. Click Create.

    Snapshot Configuration Reference

    ConfigurationDescription
    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., api and batch).
    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:00 means methods only invoked before this time will be evaluated as dead code.
  9. Debug the Scavenger Agent using Remote JVM Debug

    develop

    To 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

    1. Execute the agent startup script: ./run-agent.sh.
    2. Run the Remote JVM Debug configuration you created in step 1.
    3. 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
  10. Create a workspace in Scavenger

    develop

    To begin managing your data, connect to the Scavenger API at http://{API host}:8081/scavenger and follow these steps:

    1. Click the Create workspace button in the bottom left corner.
    2. In the modal that appears, enter a name for your workspace.
    3. Click Create to finalize the workspace setup.
  11. Build and install the Scavenger API

    develop

    The API can be obtained via the GitHub releases page or built manually.

    To build the API manually, run:

    ./gradlew assemble -p scavenger-api

    To start the API, you must specify the Collector's URL using the scavenger.collector-server-url property:

    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