Skip to content

Add support for JFR contextual information #2057

@egahlin

Description

@egahlin

Component(s)

jfr-events

Is your feature request related to a problem? Please describe.

JDK 25 introduces the concept of contextual information that allows lower-level events in the JVM/JDK, such as lock contention and exceptions, to inherit information in contextual fields from higher-level events, such as the trace or span IDs available in https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/jfr-events/src/main/java/io/opentelemetry/contrib/jfrevent

Example:

The jdk.JavaMonitorEnter event is emitted when a lock is contended. If a user looks at that event using the jfr print command, users can observe the context in which the lock contention happens:

$ jfr print --events jdk.JavaMonitorEnter recording.jfr 
jdk.JavaMonitorEnter {
    Context: Scope.traceId = "4bf92f3577b34da6a3ce929d0e0e4736"
    Context: Span.operationName ="HTTP GET /api/orders"
    Context: Span.operationName ="Service: order service - getOrders"
    Context: Span.operationName ="Service: payment service - authorizePayment"
    Context: Span.operationName ="Service: bank-gateway - requestAuthorization"
    startTime = 17:51:29.038 (2025-02-07)
    duration = 50.56 ms
    monitorClass = java.util.ArrayDeque (classLoader = bootstrap)
    previousOwner = "Order Thread" (javaThreadId = 56209, virtual = true)
    address = 0x60000232ECB0
    eventThread = "Order Thread" (javaThreadId = 52613, virtual = true)
    ...
}

For more information about the contextual annotation, see https://download.java.net/java/early_access/jdk25/docs/api/jdk.jfr/jdk/jfr/Contextual.html

Describe the solution you'd like

To support this, there is no need to actual compile against JDK 25, since the visualization happens in the tool, e.g. jfr print in JDK 25 or JDK Mission Control (in a future release). All that is needed is to create an annotation with @Name("jdk.jfr.Contextual"):

@MetadataDefinition
@Label("Context")
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.FIELD})
@Name("jdk.jfr.Contextual")
@interface Contextual {
} 

and annotate the operationName and traceID event fields with it to make it work.

To avoid repetition in the presentation, it's probably best to annotate traceId only in a top-level event, such as the ScopeEvent or perhaps a new event that is even higher-level. SpanID is likely not that interesting either. If too much is annotated with @Contextual, it will be hard for humans to parse.

Describe alternatives you've considered

No response

Additional context

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions