Skip to content

Latest commit

 

History

History
1212 lines (931 loc) · 35.7 KB

File metadata and controls

1212 lines (931 loc) · 35.7 KB

JfrPath Reference

JfrPath is a path-based query language for navigating and querying Java Flight Recorder (JFR) files. It provides a concise syntax for accessing events, metadata, chunks, and constant pools with filtering, projection, and aggregation capabilities.

Grammar Overview

<query>     ::= <root> "/" <segments> [<filters>] [<projection>] [<pipeline>]
<root>      ::= "events" | "metadata" | "chunks" | "constants"
<segments>  ::= <segment> ("/" <segment>)*
<segment>   ::= <identifier> | <index> | <slice>
<filters>   ::= "[" <predicate> "]" ("[" <predicate> "]")*
<predicate> ::= <simple-filter> | <expr-filter>
<projection>::= "/" <segment> ("/" <segment>)*
<pipeline>  ::= "|" <operator> ("|" <operator>)*

Roots

JfrPath queries start with one of four roots:

events/<type>

Access event data from the recording.

  • Requires: Event type name (e.g., jdk.ExecutionSample, jdk.FileRead)
  • Returns: Event instances with all fields
  • Example: events/jdk.FileRead

metadata/<type>

Access type metadata (structure, fields, annotations).

  • Requires: Type name (e.g., java.lang.Thread, jdk.types.Method)
  • Returns: Type metadata as structured data
  • Example: metadata/jdk.types.StackTrace

chunks

Access chunk-level information from the recording.

  • Returns: Chunk metadata (offset, size, duration, compression status)
  • Example: chunks
  • Specific chunk: chunks/0 (by index)

constants

Access constant pool entries.

  • Summary: constants returns all CP types with counts
  • Entries: constants/<type> returns entries for specific type
  • Crossref: constants/<type> | crossref() crosschecks CP entries against event references
  • Example: constants/jdk.types.Symbol

Path Segments

After the root, segments navigate through the structure:

Field Access

events/jdk.FileRead/path
metadata/jdk.types.Method/name
constants/jdk.types.Symbol/string

Nested Fields

events/jdk.ExecutionSample/thread/name
events/jdk.FileRead/stackTrace/frames
metadata/jdk.types.StackTrace/fields/name

Array/List Access

events/jdk.ExecutionSample/stackTrace/frames/0          # First element
events/jdk.ExecutionSample/stackTrace/frames/0:3        # Slice [0,3)

Metadata Aliases

Convenient shortcuts for metadata navigation:

metadata/jdk.types.Method/fields.name           # Same as /fields/name
metadata/jdk.types.Method/fieldsByName.name     # Access field by name

Filters

Filters use square brackets [...] to constrain results. Filters can be placed:

  • After the root/type: events/jdk.FileRead[bytes>1000]
  • After any segment (interleaved): events/jdk.GCHeapSummary/heapSpace[committedSize>1000000]

Simple Filters

Simple field comparisons:

[field op value]

Operators:

  • = : Equal
  • != : Not equal
  • > : Greater than
  • >= : Greater than or equal
  • < : Less than
  • <= : Less than or equal
  • ~ : Regex match

Examples:

events/jdk.FileRead[bytes>1000]
events/jdk.ExecutionSample[thread/name="main"]
events/jdk.FileRead[path~"/tmp/.*"]
metadata/jdk.types.Method[name="toString"]

Boolean Expression Filters

Complex conditions with functions and logic:

[<expr> and <expr>]
[<expr> or <expr>]
[not <expr>]
[(<expr>) and (<expr>)]

Examples:

events/jdk.FileRead[bytes>1000 and path~"/tmp/.*"]
events/jdk.ExecutionSample[thread/name="main" or thread/name="worker"]
events/jdk.FileRead[not (bytes<100)]

Filter Functions

String Functions

  • contains(field, "substr") - Check if string contains substring
  • startsWith(field, "prefix") - Check if string starts with prefix
  • endsWith(field, "suffix") - Check if string ends with suffix
  • matches(field, "regex") - Check if string matches regex
  • matches(field, "regex", "i") - Case-insensitive regex match

Examples:

events/jdk.FileRead[contains(path, "tmp")]
events/jdk.ExecutionSample[startsWith(thread/name, "pool-")]
events/jdk.FileRead[endsWith(path, ".log")]
events/jdk.ExecutionSample[matches(thread/name, "worker-[0-9]+")]

Existence and Emptiness

  • exists(field) - Check if field is present and not null
  • empty(field) - Check if string/list is empty

Examples:

events/jdk.FileRead[exists(path)]
events/jdk.ExecutionSample[not empty(stackTrace/frames)]

Numeric Functions

  • between(field, min, max) - Check if value is between min and max (inclusive). Bounds can be numbers or datetime strings (see below)
  • len(field) - Get length of string or list (can be used in comparisons)

Examples:

events/jdk.FileRead[between(bytes, 1000, 10000)]
events/jdk.ExecutionSample[len(stackTrace/frames)>10]
events/jdk.FileRead[len(path)>50]

Time Filter Functions

Filter events by timestamp. All time fields (startTime) store epoch nanoseconds. Datetime strings are parsed in order: ISO-8601 instant → local datetime → date (start of day in local timezone).

  • before(field, datetime) - Event occurred before the given datetime
  • after(field, datetime) - Event occurred after the given datetime
  • between(field, "datetime1", "datetime2") - Event occurred within a datetime range (inclusive)
  • on(field, "yyyy-MM-dd") - Event occurred on a specific calendar date (local timezone)

Supported datetime formats:

  • ISO-8601 instant: "2024-08-13T16:24:00Z" or "2024-08-13T16:24:00+02:00"
  • Local datetime: "2024-08-13T16:24:00" (interpreted in system timezone)
  • Date only: "2024-08-13" (treated as start of day in system timezone)

Examples:

# Events before a point in time
events/jdk.ExecutionSample[before(startTime, "2024-08-13T17:00:00")]

# Events after a point in time
events/jdk.ExecutionSample[after(startTime, "2024-08-13T16:00:00")]

# Events within a time window
events/jdk.ExecutionSample[between(startTime, "2024-08-13T16:00:00", "2024-08-13T17:00:00")]

# Events on a specific date
events/jdk.ExecutionSample[on(startTime, "2024-08-13")]

# Combine with other filters
events/jdk.JavaMonitorEnter[on(startTime, "2024-08-13") and duration>1000000]

List/Array Matching

For list and array fields, control how filters apply to elements:

  • any: (default) - Filter matches if ANY element satisfies condition
  • all: - Filter matches if ALL elements satisfy condition
  • none: - Filter matches if NO elements satisfy condition

Syntax:

[any:<listField>[condition]]
[all:<listField>[condition]]
[none:<listField>[condition]]

Examples:

events/jdk.ExecutionSample[any:stackTrace/frames[matches(method/name/string, ".*Foo.*")]]
events/jdk.ExecutionSample[all:stackTrace/frames[lineNumber>0]]
events/jdk.ExecutionSample[none:stackTrace/frames[matches(method/name/string, ".*Test.*")]]

Interleaved Filters

Filters can be placed after any segment to filter at that level:

events/jdk.GCHeapSummary[when/when="After GC"]/heapSpace[committedSize>1000000]/reservedSize

This filters:

  1. Events where when/when="After GC"
  2. Then projects to heapSpace
  3. Then filters heapSpace entries where committedSize>1000000
  4. Then projects to reservedSize

Aggregation Pipeline

Pipeline operators transform or aggregate results. Append with |:

events/jdk.FileRead | count()
events/jdk.FileRead/bytes | stats()

Count

| count()

Count the number of rows/events.

Returns: { "count": N }

Examples:

events/jdk.FileRead | count()
metadata/jdk.types.Method/name | count()
constants/jdk.types.Symbol | count()

Sum

| sum([path])

Sum numeric values. If path is omitted, uses the projection path.

Returns: { "sum": total, "count": N }

Examples:

events/jdk.FileRead/bytes | sum()
events/jdk.FileRead | sum(bytes)

Stats

| stats([path])

Compute statistics for numeric values: min, max, avg, stddev.

Returns: { "min": M, "max": N, "avg": A, "stddev": S, "count": C }

Examples:

events/jdk.FileRead/bytes | stats()
events/jdk.FileRead | stats(bytes)

Quantiles

| quantiles(q1, q2, ...[, path=...])

Compute percentiles at specified quantiles (0.0 to 1.0).

Returns: Columns pXX for each quantile (e.g., p50, p90, p99)

Examples:

events/jdk.FileRead/bytes | quantiles(0.5, 0.9, 0.99)
events/jdk.FileRead | quantiles(0.5, 0.9, path=bytes)

Sketch

| sketch([path])

Shortcut for stats + common percentiles (p50, p90, p99).

Returns: { "min": M, "max": N, "avg": A, "stddev": S, "p50": X, "p90": Y, "p99": Z, "count": C }

Examples:

events/jdk.FileRead/bytes | sketch()
events/jdk.FileRead | sketch(bytes)

Head

| head(n)

Return only the first N rows from the result set.

Examples:

events/jdk.FileRead | head(10)
events/jdk.ExecutionSample | groupBy(thread/name) | head(5)

Tail

| tail(n)

Return only the last N rows from the result set.

Examples:

events/jdk.FileRead | tail(10)
events/jdk.FileRead | sortBy(bytes) | tail(5)

Filter

| filter([predicate])

Filter rows in the pipeline using the same predicate syntax as path filters.

Examples:

events/jdk.FileRead | groupBy(path, agg=sum, value=bytes) | filter([sum>1048576])
events/jdk.ExecutionSample | groupBy(thread/name) | filter([count>100])

Distinct

| distinct([field])

Return only distinct rows by the specified field, or deduplicate the entire row if no field is given.

Examples:

events/jdk.FileRead | distinct(path)
events/jdk.ExecutionSample | distinct(sampledThread/javaName)

Stack Profile

| stackprofile([direction=top-down|bottom-up][, buckets=N][, minPct=D])

Aggregate stack trace data into a weighted call tree with temporal bucketing. Intended for CPU profiling event types with a stackTrace field (e.g., jdk.ExecutionSample).

Parameters:

  • direction - top-down (default) or bottom-up
  • buckets - number of time buckets (default: 10)
  • minPct - minimum percentage threshold to include a frame (default: 1.0)

Examples:

events/jdk.ExecutionSample | stackprofile()
events/jdk.ExecutionSample | stackprofile(direction=bottom-up, buckets=20)
events/jdk.ExecutionSample[sampledThread/javaName="main"] | stackprofile(minPct=0.5)

Flame Graph

| flamegraph([direction=bottom-up|top-down])

Aggregate stack trace data into a flame graph. Intended for event types with a stackTrace field (e.g., jdk.ExecutionSample). Renders an interactive HTML flame graph in the terminal (inline ANSI in plain mode, scrollable pane in --tui mode).

Parameters:

  • direction - bottom-up (default, classic flame graph) or top-down (icicle graph)

Examples:

events/jdk.ExecutionSample | flamegraph()
events/jdk.ExecutionSample | flamegraph(direction=top-down)
events/jdk.ExecutionSample[sampledThread/javaName="main"] | flamegraph()

Group By

| groupBy(keyPath[, agg=count|sum|avg|min|max, value=path, sortBy=key|value, asc=false])

Group results by key and apply aggregation function with optional sorting.

Parameters:

  • keyPath - Field path to group by
  • agg - Aggregation function (default: count)
  • value - Value path for sum/avg/min/max
  • sortBy - Sort results by key (grouping key) or value (aggregated value)
  • asc - Sort ascending (default: false, descending)

Returns: { "key": groupKey, "<agg>": result }

Examples:

events/jdk.ExecutionSample/thread/name | groupBy(value)                    # Count by thread name
events/jdk.FileRead | groupBy(path, agg=count)                              # Count by file path
events/jdk.FileRead | groupBy(path, agg=sum, value=bytes)                   # Total bytes by path
events/jdk.ExecutionSample | groupBy(thread/name, agg=count)                # Count by thread name
events/jdk.FileRead | groupBy(path, agg=avg, value=bytes)                   # Avg bytes by path
events/jdk.FileRead | groupBy(path, agg=min, value=bytes)                   # Min bytes by path
events/jdk.FileRead | groupBy(path, agg=max, value=bytes)                   # Max bytes by path

# Sorted results
events/jdk.ExecutionSample | groupBy(thread/name, sortBy=value)             # Sort by count descending
events/jdk.ExecutionSample | groupBy(thread/name, sortBy=key, asc=true)     # Sort alphabetically
events/jdk.FileRead | groupBy(path, agg=sum, value=bytes, sortBy=value)     # Sort by total bytes

Sort By

| sortBy(field[, asc=false])

Sort rows by any field in the current result set. Works after any operator that produces multiple rows.

Parameters:

  • field - Field name to sort by (must exist in current row structure)
  • asc - Sort ascending (default: false, descending)

Key constraint: Can only sort by fields available after previous operators:

  • After select(a, b) → only a, b available
  • After groupBy(x) → only key, <aggFunc> available
  • After len(path) → all original fields + len

Examples:

events/jdk.FileRead | select(path, bytes) | sortBy(bytes)              # Sort by bytes descending
events/jdk.FileRead | select(path, bytes) | sortBy(path, asc=true)     # Sort by path ascending
events/jdk.ExecutionSample | groupBy(thread/name) | sortBy(count)      # Sort grouped results by count
events/jdk.FileRead | len(path) | sortBy(len)                          # Sort by computed length

Top

| top(n[, by=path, asc=false])

Sort and return top N rows.

Parameters:

  • n - Number of results to return
  • by - Path to sort by (default: value)
  • asc - Sort ascending (default: false, descending)

Examples:

events/jdk.FileRead | top(10, by=bytes)                   # Top 10 by bytes (descending)
events/jdk.FileRead/bytes | top(5)                         # Top 5 values
events/jdk.FileRead | top(10, by=bytes, asc=true)         # Bottom 10 by bytes (ascending)

Decorate By Time

| decorateByTime(decoratorEventType, fields=field1,field2[, threadPath=..., decoratorThreadPath=...])

Decorate events with information from time-overlapping events on the same thread.

Use Cases: Correlate events that occur during the same time period (e.g., execution samples during monitor waits, allocations during GC phases).

Parameters:

  • decoratorEventType - Event type to use as decorator (quoted string)
  • fields - Comma-separated list of fields to extract from decorator
  • threadPath - Optional: path to thread ID in primary event (default: eventThread/javaThreadId)
  • decoratorThreadPath - Optional: path to thread ID in decorator (default: eventThread/javaThreadId)

Overlap Logic: Events overlap if their time ranges intersect:

primaryStart < decoratorEnd && primaryEnd > decoratorStart

Decorator Field Access: Decorated fields are accessed using $decorator. prefix:

$decorator.fieldName

Examples:

# Find execution samples during monitor waits
events/jdk.ExecutionSample | decorateByTime(jdk.JavaMonitorWait, fields=monitorClass,duration)

# Correlate allocations with GC phases
events/jdk.ObjectAllocationSample | decorateByTime(jdk.GCPhase, fields=name,duration)

# Execution samples during I/O operations
events/jdk.ExecutionSample | decorateByTime(jdk.SocketWrite, fields=host,port,bytesWritten)

# Access decorator fields
events/jdk.ExecutionSample | decorateByTime(jdk.JavaMonitorEnter, fields=monitorClass)
  | groupBy($decorator.monitorClass)

Decorate By Key

| decorateByKey(decoratorEventType, key=keyPath, decoratorKey=decoratorKeyPath, fields=field1,field2)

Decorate events using correlation keys derived from event fields.

Use Cases: Join events with shared identifiers (e.g., request tracing, correlation by thread or custom IDs).

Parameters:

  • decoratorEventType - Event type to use as decorator (quoted string)
  • key - Path to correlation key in primary event
  • decoratorKey - Path to correlation key in decorator event
  • fields - Comma-separated list of fields to extract from decorator

Decorator Field Access: Decorated fields are accessed using $decorator. prefix:

$decorator.fieldName

Examples:

# Correlate execution samples with request context by thread ID
events/jdk.ExecutionSample | decorateByKey(RequestStart,
                                            key=sampledThread/javaThreadId,
                                            decoratorKey=thread/javaThreadId,
                                            fields=requestId,endpoint,userId)

# Join file reads with thread metadata
events/jdk.FileRead | decorateByKey(jdk.ThreadStart,
                                     key=eventThread/javaThreadId,
                                     decoratorKey=thread/javaThreadId,
                                     fields=javaName,group)

# Group execution samples by request endpoint
events/jdk.ExecutionSample | decorateByKey(RequestStart,
                                            key=sampledThread/javaThreadId,
                                            decoratorKey=thread/javaThreadId,
                                            fields=endpoint)
  | groupBy($decorator.endpoint)

# Access decorator fields in filters
events/jdk.ExecutionSample | decorateByKey(RequestStart,
                                            key=sampledThread/javaThreadId,
                                            decoratorKey=thread/javaThreadId,
                                            fields=endpoint,requestId)
  | top(10, by=$decorator.requestId)

Notes:

  • If no decorator matches, $decorator. fields will be null
  • Multiple decorators matching the same event: first match is used
  • Only requested fields from decorator are accessible
  • Memory-efficient: decorator fields are lazily accessed

Select

| select(field1, field2, expr1 as alias1, ...)

Project specific fields from events, filtering out all other fields. Supports both simple field paths and computed expressions.

Use Cases: Reduce output to only relevant fields, compute derived values, transform data, control JSON output structure, focus analysis on specific attributes.

Parameters:

  • field - Simple field path to include in output
  • field as alias - Field path with custom output name
  • expression as alias - Computed expression (requires alias)
  • Supports nested fields using / syntax (e.g., eventThread/javaThreadId)

Behavior:

  • Only specified fields/expressions are included in the output
  • Simple fields use leaf segment as column name (or alias if provided)
  • Expressions require as alias clause
  • Works with filters and other query operations
  • Expressions are evaluated per row

Simple Field Selection:

# Select single field
events/jdk.ExecutionSample | select(startTime)

# Select multiple top-level fields
events/jdk.FileRead | select(path, bytes)

# Select nested fields
events/jdk.ExecutionSample | select(eventThread/javaThreadId, eventThread/name)

# Field with alias
events/jdk.ExecutionSample | select(eventThread/javaThreadId as threadId)

# Combine with filters
events/jdk.FileRead[bytes>1000] | select(path, bytes)

# Select decorator fields
events/jdk.ExecutionSample | decorateByTime(jdk.JavaMonitorWait, fields=monitorClass)
  | select(startTime, $decorator.monitorClass)

Computed Expressions:

Expressions support arithmetic operations, string concatenation, and built-in functions.

Arithmetic Operators:

  • + - Addition or string concatenation
  • - - Subtraction
  • * - Multiplication
  • / - Division
# Convert bytes to kilobytes
events/jdk.FileRead | select(bytes / 1024 as kilobytes)

# Calculate throughput
events/jdk.FileRead | select(bytes / duration as bytesPerNs)

# Multiply duration by 1000
events/jdk.FileRead | select(duration * 1000 as micros)

# Complex arithmetic
events/jdk.FileRead | select((bytes * count) / 1024 as totalKb)

String Concatenation:

# Build descriptive string
events/jdk.FileRead | select(path + ' (' + bytes + ' bytes)' as description)

# Combine fields
events/jdk.ExecutionSample | select(thread/name + ' [' + thread/javaThreadId + ']' as threadInfo)

# Format output
events/jdk.FileRead | select('File: ' + path as label)

String Templates:

String templates provide a cleaner syntax for string interpolation using ${...} embedded expressions:

# Simple field interpolation
events/jdk.FileRead | select("File: ${path}" as description)

# Multiple expressions in one template
events/jdk.FileRead | select("${path} (${bytes} bytes)" as info)

# Arithmetic in templates
events/jdk.FileRead | select("${path}: ${bytes / 1024} KB" as summary)

# Functions in templates
events/jdk.FileRead | select("File: ${upper(path)} - ${bytes} bytes" as info)

# Nested fields in templates
events/jdk.ExecutionSample | select("Thread ${eventThread/name} (ID: ${eventThread/javaThreadId})" as threadInfo)

# Mix templates with regular fields
events/jdk.FileRead | select(path, "${bytes / 1024} KB" as sizeKb)

Templates are equivalent to string concatenation but more readable:

  • "${path} (${bytes} bytes)" is the same as path + ' (' + bytes + ' bytes)'
  • Use double quotes for templates: "${expr}"
  • Any expression can be embedded in ${...}
  • Null values render as empty strings

Built-in Functions:

if(condition, trueValue, falseValue) - Conditional expression

events/jdk.FileRead | select(if(bytes, 'large', 'small') as size)
events/jdk.FileRead | select(if(duration, 'slow', 'fast') as speed)

upper(string) - Convert to uppercase

events/jdk.FileRead | select(upper(path) as upperPath)
events/jdk.ExecutionSample | select(upper(thread/name) as threadName)

lower(string) - Convert to lowercase

events/jdk.FileRead | select(lower(path) as lowerPath)

substring(string, start[, length]) - Extract substring

events/jdk.FileRead | select(substring(path, 0, 20) as shortPath)
events/jdk.FileRead | select(substring(path, 5) as pathTail)
events/jdk.FileRead | select(substring(path, 0, 10) as prefix)

length(string) - Get string length

events/jdk.FileRead | select(length(path) as pathLength)
events/jdk.ExecutionSample | select(length(thread/name) as nameLen)

coalesce(value1, value2, ...) - Return first non-null value

events/jdk.FileRead | select(coalesce(path, altPath, 'unknown') as finalPath)
events/jdk.ExecutionSample | select(coalesce(thread/name, thread/osName, 'unnamed') as name)

asDateTime(epochNanos[, format]) - Format epoch-nanoseconds as datetime string

events/jdk.ExecutionSample | select(asDateTime(startTime) as time)
events/jdk.FileRead | select(asDateTime(startTime, "HH:mm:ss.SSS") as time, path)

truncate(epochNanos, unit) - Truncate timestamp to a time boundary, returns epoch nanoseconds

# Units: "second", "minute", "hour", "day", "week", "month"
events/jdk.ExecutionSample | select(asDateTime(truncate(startTime, "minute")) as bucket)
events/jdk.ExecutionSample
  | select(asDateTime(truncate(startTime, "minute")) as bucket, eventThread/name as thread)
  | groupBy(bucket, agg=count)

formatDuration(nanos) - Format nanosecond duration as human-readable string. Also available as a pipeline operator: | formatDuration([path])

events/jdk.JavaMonitorEnter | select(startTime, formatDuration(duration) as dur, monitorClass)
events/jdk.FileRead | select(path, formatDuration(duration) as dur) | sortBy(duration) | top(10)
events/jdk.JavaMonitorEnter/duration | formatDuration()

Mixed Fields and Expressions:

# Simple fields with computed expressions
events/jdk.FileRead | select(path, bytes / 1024 as kb, duration)

# Multiple expressions and fields
events/jdk.FileRead | select(
    path as file,
    bytes / 1024 as kilobytes,
    if(bytes, 'large', 'small') as sizeCategory,
    duration * 1000 as microseconds
)

# Transform and compute
events/jdk.ExecutionSample | select(
    startTime,
    upper(thread/name) as threadName,
    thread/javaThreadId as tid,
    length(stackTrace/frames) as stackDepth
)

Expression Evaluation:

  • Field references in expressions access the current row's data
  • Arithmetic operations convert values to numbers (null becomes 0)
  • String concatenation converts all values to strings
  • Division by zero returns NaN
  • Functions receive evaluated arguments

Column Naming:

  • Simple fields: Use leaf segment name (e.g., javaThreadId from eventThread/javaThreadId)
  • Aliased fields: Use the specified alias
  • Expressions: Must provide alias (e.g., bytes / 1024 as kb)

Value Transform Functions

Transform individual values (can also be used in filters where applicable):

String Transforms

  • | len([path]) - String or list length
  • | uppercase([path]) - Convert to uppercase
  • | lowercase([path]) - Convert to lowercase
  • | trim([path]) - Trim whitespace
  • | contains([path], "substr") - Check if contains substring
  • | replace([path], "old", "new") - Replace occurrences

Numeric Transforms

  • | abs([path]) - Absolute value
  • | round([path]) - Round to nearest integer
  • | floor([path]) - Round down
  • | ceil([path]) - Round up
  • | formatDuration([path]) - Format nanosecond value as human-readable duration string

Examples:

constants/jdk.types.Symbol/string | len()
events/jdk.ExecutionSample/thread/name | uppercase()
events/jdk.FileRead/path | replace("/tmp/", "/data/")
events/jdk.FileRead/bytes | abs()
events/jdk.JavaMonitorEnter/duration | formatDuration()

Time Analysis

Time Range

| timerange([path], [duration=path], [format=str])

Computes the min/max time span covered by events. Returns a single-row summary with human-readable wall-clock times and duration.

Parameters:

  • path - Time field to analyze (default: startTime)
  • duration - Duration field; if present, max is computed as startTime + duration
  • format - Output format string for minTime/maxTime (default: ISO local datetime)

Output fields: count, field, minEpochNanos, maxEpochNanos, minTime, maxTime, durationNanos, durationMs, duration

Examples:

# Recording time span
events/jdk.ExecutionSample | timerange()

# Span of file reads including their duration
events/jdk.FileRead | timerange(startTime, duration=duration)

# Custom output format
events/jdk.ExecutionSample | timerange(format="HH:mm:ss")

Format Timestamps — asDateTime()

| asDateTime([path][, format=str])

Converts epoch-nanosecond fields to human-readable datetime strings. Can be used both as a pipeline operator and as a select() expression function.

Parameters:

  • path - Time field to format (default: startTime)
  • format - Date format string (default: ISO local datetime)

Examples:

# Format startTime (pipeline operator)
events/jdk.ExecutionSample | asDateTime(startTime)

# Format as select expression
events/jdk.ExecutionSample | select(asDateTime(startTime) as time, eventThread/name as thread)

# Custom format
events/jdk.ExecutionSample | select(asDateTime(startTime, "HH:mm:ss.SSS") as time)

Time-Series Bucketing — truncate()

truncate(field, unit) is a select() expression function that truncates an epoch-nanoseconds value to a time boundary, enabling time-series groupby.

Supported units: "second", "minute", "hour", "day", "week", "month"

Returns epoch nanoseconds of the truncated instant (chains naturally with asDateTime()).

Examples:

# Count samples per minute
events/jdk.ExecutionSample
  | select(asDateTime(truncate(startTime, "minute")) as bucket, eventThread/name as thread)
  | groupBy(bucket, agg=count)

# Allocations per hour
events/jdk.ObjectAllocationSample
  | select(truncate(startTime, "hour") as hourBucket, allocationSize)
  | groupBy(hourBucket, agg=sum, value=allocationSize)

Format Durations — formatDuration()

formatDuration(field) is a select() expression function that converts a nanosecond duration to a human-readable string.

Output examples: "123ns", "4.56us", "789.12ms", "1.23s", "5m 30s", "2h 15m 30s"

Examples:

# Show lock wait durations in readable form
events/jdk.JavaMonitorEnter | select(startTime, formatDuration(duration) as dur, monitorClass)

# Top slowest file reads
events/jdk.FileRead | select(path, formatDuration(duration) as dur) | sortBy(duration) | top(10)

Usage Patterns

Event Queries

List all events of a type:

events/jdk.FileRead
events/jdk.ExecutionSample

Project to specific field:

events/jdk.FileRead/path
events/jdk.ExecutionSample/thread/name

Filter and project:

events/jdk.FileRead[bytes>1000]/path
events/jdk.ExecutionSample[thread/name="main"]/stackTrace

Count matching events:

events/jdk.FileRead[bytes>1000] | count()
events/jdk.ExecutionSample[thread/name~"worker-.*"] | count()

Aggregate values:

events/jdk.FileRead/bytes | stats()
events/jdk.FileRead[path~"/tmp/.*"]/bytes | sum()
events/jdk.ExecutionSample | groupBy(thread/name)
events/jdk.FileRead | top(10, by=bytes)

Metadata Queries

Inspect type structure:

metadata/jdk.types.StackTrace
metadata/java.lang.Thread

List field names:

metadata/jdk.types.Method/fields/name
metadata/jdk.types.StackTrace/fields.name

Access specific field metadata:

metadata/jdk.types.Method/fields/name/type
metadata/jdk.types.StackTrace/fields.frames/annotations

Tree view (recursive):

metadata/jdk.types.StackTrace --tree --depth 2
metadata/jdk.types.Method/fields/name --tree

Chunk Queries

List all chunks:

chunks

Specific chunk by index:

chunks/0
chunks/5

Filter chunks:

chunks[size>1000000]
chunks[compressed=true]

Chunk summary:

chunks --summary

Constant Pool Queries

CP summary (all types with counts):

constants

Entries for specific type:

constants/jdk.types.Symbol
constants/jdk.types.Method
constants/jdk.types.Package

Filter CP entries:

constants/jdk.types.Symbol[string~"java/.*"]
constants/jdk.types.Method[name="toString"]

Project CP entry field:

constants/jdk.types.Symbol/string
constants/jdk.types.Method/name

Aggregate:

constants/jdk.types.Symbol | count()
constants/jdk.types.Symbol/string | len()

Crosscheck CP entries against event references:

constants/jdk.types.StackTrace | crossref()
constants/jdk.types.Method | crossref()

Operator Chaining

Many operators are chainable in a pipeline. For example:

events/jdk.FileRead | select(path, bytes) | sortBy(bytes) | top(10)
events/jdk.ExecutionSample | groupBy(thread/name) | sortBy(count) | head(5)
events/jdk.ExecutionSample | decorateByTime(jdk.JavaMonitorWait, fields=monitorClass) | select(startTime, $decorator.monitorClass) | top(10)

Terminal aggregation operators (count(), sum(), stats(), quantiles(), sketch(), timerange(), flamegraph(), stackprofile()) consume the stream and produce a summary result — they cannot be chained with each other.

Transform and filter operators (select(), sortBy(), top(), head(), tail(), filter(), distinct(), groupBy(), decorateByTime(), decorateByKey(), value transforms) can be combined freely.

Design Principles

  1. Streaming First: All operations use streaming parser when possible
  2. Lazy Evaluation: Events processed incrementally, not loaded into memory
  3. Early Abort: --limit stops parsing once enough matches collected
  4. Minimal Syntax: Path-based navigation, filters inline with brackets
  5. Composability: Filters, projection, and pipelines compose naturally

Examples by Root

Events Examples

# Count execution samples
events/jdk.ExecutionSample | count()

# Top 10 files by bytes read
events/jdk.FileRead | top(10, by=bytes)

# Execution samples by thread
events/jdk.ExecutionSample | groupBy(thread/name)

# File reads to /tmp, sum bytes
events/jdk.FileRead[path~"/tmp/.*"] | sum(bytes)

# Execution samples with deep stacks
events/jdk.ExecutionSample[len(stackTrace/frames)>20] --limit 5

# GC events after GC
events/jdk.GCHeapSummary[when/when="After GC"]/heapSpace

# Monitor contention analysis: samples during lock waits
events/jdk.ExecutionSample | decorateByTime(jdk.JavaMonitorWait, fields=monitorClass,duration)

# Request tracing: correlate samples with request context
events/jdk.ExecutionSample | decorateByKey(RequestStart,
                                                  key=sampledThread/javaThreadId,
                                                  decoratorKey=thread/javaThreadId,
                                                  fields=requestId,endpoint)

# GC impact: allocations during GC phases
events/jdk.ObjectAllocationSample | decorateByTime(jdk.GCPhase, fields=name)
  | groupBy($decorator.name, agg=sum, value=allocationSize)

# Flame graph from execution samples
events/jdk.ExecutionSample | flamegraph()

# Icicle graph (top-down)
events/jdk.ExecutionSample | flamegraph(direction=top-down)

# Weighted call tree with temporal bucketing
events/jdk.ExecutionSample | stackprofile()

# Recording time span
events/jdk.ExecutionSample | timerange()

# Filter events to a specific hour
events/jdk.ExecutionSample[between(startTime, "2024-08-13T16:00:00", "2024-08-13T17:00:00")]

# Filter events on a specific date
events/jdk.ExecutionSample[on(startTime, "2024-08-13")]

# CPU samples per minute (time-series)
events/jdk.ExecutionSample
  | select(asDateTime(truncate(startTime, "minute")) as bucket, eventThread/name as thread)
  | groupBy(bucket, agg=count)

# Lock contention with human-readable durations
events/jdk.JavaMonitorEnter | select(startTime, formatDuration(duration) as dur, monitorClass)

Metadata Examples

# Inspect StackTrace structure
show metadata/jdk.types.StackTrace

# List all field names in Method
show metadata/jdk.types.Method/fields/name

# Field annotations
show metadata/jdk.types.StackTrace/fields.frames/annotations

# Recursive tree view
show metadata/jdk.types.StackTrace --tree --depth 3

# Count metadata types
show metadata/jdk.types.Method/name | count()

Chunks Examples

# List all chunks
show chunks

# Chunk summary stats
show chunks --summary

# Large chunks only
show chunks[size>10000000]

# Compressed chunks
show chunks[compressed=true]

# Specific chunk
show chunks/0

Constant Pool Examples

# CP summary
constants

# All Symbol entries
constants/jdk.types.Symbol

# Symbols matching pattern
constants/jdk.types.Symbol[string~"java/.*"]

# Count symbols
constants/jdk.types.Symbol | count()

# Symbol string lengths
constants/jdk.types.Symbol/string | len()

# Methods named "toString"
constants/jdk.types.Method[name="toString"]

# Crosscheck StackTrace CP entries against event references
constants/jdk.types.StackTrace | crossref()

Interactive Commands

In the interactive shell, use these commands:

  • open <path> [--alias NAME] - Open a recording
  • sessions - List all sessions
  • use <id|alias> (or session) - Switch session
  • close [<id|alias>|--all] - Close session(s)
  • info [<id|alias>] - Show session info
  • show <expr> [options] - Execute JfrPath query
  • metadata [options] - List types
  • metadata class <name> [options] - Inspect class
  • chunks [options] - List chunks
  • chunk <index> show - Show specific chunk
  • constants [<type>] [options] - List constant pool entries (alias: cp)
  • constants/<type> | crossref() - Crosscheck CP entries against event references
  • events/<type>[filter] [options] - Query events (shorthand for show events)
  • help [<command>] - Show help
  • exit / quit - Exit

Non-Interactive Mode

Execute queries without entering the shell:

# Show command
jfr-shell show recording.jfr "events/jdk.FileRead | count()"
jfr-shell show recording.jfr "events/jdk.FileRead/bytes | stats()" --format json

# Metadata command
jfr-shell metadata recording.jfr --events-only
jfr-shell metadata recording.jfr --search FileRead

# Chunks command
jfr-shell chunks recording.jfr --summary

# Constants command (alias: cp)
jfr-shell constants recording.jfr --type jdk.types.Symbol
jfr-shell constants recording.jfr --summary

All non-interactive commands:

  • Return exit code 0 on success, 1 on error
  • Write errors to stderr
  • Support --format json for structured output
  • Execute without prompts (suitable for CI/scripting)

See jfr-shell --help and jfr-shell <command> --help for full options.