Skip to content

Support Kotlin (.kt) file extension in Java source code integration #4878

@myeongseok-rpls

Description

@myeongseok-rpls

Problem

The current Java source code integration (find_java.go) hardcodes the .java file extension when resolving function names to source file paths:

const ExtJava = ".java"

The convertJavaFunctionNameToPath function always appends .java:

  • com/example/MyClass.methodcom/example/MyClass.java

This means Kotlin applications get 404 errors for every source code lookup, since Kotlin source files use the .kt extension.

Context

Kotlin is a JVM language officially supported by Google for Android and widely used in server-side applications (Spring Boot, Ktor, etc.). Kotlin compiles to JVM bytecode, so the async-profiler / JFR profiling agent captures Kotlin classes the same way as Java classes. However, when Pyroscope tries to fetch the source code from GitHub, it looks for MyClass.java instead of MyClass.kt, resulting in a 404.

Reproduction

  1. Set up a Kotlin project with .pyroscope.yaml:
    version: v1
    source_code:
      mappings:
        - function_name:
            - prefix: com/example/myapp
          language: java
          source:
            github:
              owner: my-org
              repo: my-kotlin-app
              ref: main
              path: src/main/kotlin
  2. Profile the application and click on any function in the flame graph
  3. Pyroscope requests src/main/kotlin/com/example/myapp/MyClass.java from GitHub
  4. GitHub returns 404 because the actual file is MyClass.kt

Proposed Solution

When language: java, try multiple JVM file extensions before returning "not found":

  1. Try .java first (current behavior)
  2. If 404, try .kt (Kotlin)
  3. Optionally try .scala, .groovy for other JVM languages

Alternatively, add a new language: kotlin option that uses .kt as the primary extension.

Suggested change in find_java.go:

var jvmExtensions = []string{".java", ".kt"}

func (ff *FileFinder) findJavaFile(ctx context.Context, mapping []MappingConfig) (*connect.Response[vcsv1.GetFileResponse], error) {
    span, ctx := opentracing.StartSpanFromContext(ctx, "findJavaFile")
    defer span.Finish()

    path := convertJavaFunctionNameToPath(ff.file)
    // path has .java extension, try .kt as fallback
    basePath := strings.TrimSuffix(path, ExtJava)
    
    for _, ext := range jvmExtensions {
        candidate := basePath + ext
        for _, m := range mapping {
            resp, err := ff.fetchMappingFile(ctx, candidate, m)
            if err == nil {
                return resp, nil
            }
            // continue on 404, return on other errors
        }
    }
    return nil, CodeNotFound
}

Impact

This affects all JVM projects using non-Java languages:

  • Kotlin — widely used in Android and server-side (Spring Boot)
  • Scala — used in data engineering (Spark, Akka)
  • Groovy — used in Gradle build scripts and some web apps

Environment

  • Grafana Cloud with Pyroscope
  • Kotlin 1.9.x + Spring Boot 3.x application
  • Profiled via Grafana Alloy with pyroscope.java component
  • .pyroscope.yaml with 33 mappings, all returning 404 due to .java extension

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions