General availability (GA) Open source

pyroscope.java

pyroscope.java continuously profiles Java processes running on the local Linux OS using async-profiler.

Note

To use the pyroscope.java component you must run Alloy as root and inside host PID namespace.

Usage

Alloy
pyroscope.java "<LABEL>" {
  targets    = <TARGET_LIST>
  forward_to = <RECEIVER_LIST>
}

Target JVM configuration

When you use pyroscope.java to profile Java applications, you can configure the target JVMs with some command line flags that ensure accurate profiling, especially for inlined methods. Add the following flags to your Java application’s startup command:

java
-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints

For more details, refer to Restrictions/Limitations in the async-profiler documentation.

Additional configuration for Linux capabilities

If your Kubernetes environment has Linux capabilities enabled, configure the following in your Helm values to ensure pyroscope.java functions properly:

YAML
alloy:
  securityContext:
    runAsUser: 0
    runAsNonRoot: false
    capabilities:
      add:
        - PERFMON
        - SYS_PTRACE
        - SYS_RESOURCE
        - SYS_ADMIN

These capabilities enable Alloy to access performance monitoring subsystems, trace processes, override resource limits, and perform necessary system administration tasks for profiling.

Note

Adjust capabilities based on your specific security requirements and environment, following the principle of least privilege. The capability behavior depends on Container Runtime Interface (CRI) settings. For example, in Docker, capabilities that aren’t on the allowlist are dropped by default.

Arguments

You can use the following arguments with pyroscope.java:

NameTypeDescriptionDefaultRequired
forward_tolist(ProfilesReceiver)List of receivers to send collected profiles to.yes
targetslist(map(string))List of java process targets to profile.yes
tmp_dirstringTemporary directory to store async-profiler."/tmp"no

Profiling behavior

The special label __process_pid__ must always be present in each target of targets and corresponds to the PID of the process to profile.

After component startup, pyroscope.java creates a temporary directory under tmp_dir and extracts the async-profiler binaries for both glibc and musl into the directory with the following layout.

text
/tmp/alloy-asprof-glibc-{SHA1}/bin/asprof
/tmp/alloy-asprof-glibc-{SHA1}/lib/libasyncProfiler.so
/tmp/alloy-asprof-musl-{SHA1}/bin/asprof
/tmp/alloy-asprof-musl-{SHA1}/lib/libasyncProfiler.so

After process profiling startup, the component detects libc type and copies according libAsyncProfiler.so into the target process file system at the exact same path.

Note

The asprof binary runs with root permissions. If you change the tmp_dir configuration to something other than /tmp, then you must ensure that the directory is only writable by root.

The filesystem mounted at tmp_dir in the Alloy and target containers, needs to allow execution of files stored there. Typically a mount option called noexec would prevent files from being executed.

targets

The special __process_pid__ label must always be present and corresponds to the process PID that’s used for profiling.

Labels starting with a double underscore (__) are treated as internal, and are removed prior to scraping.

The special label service_name is required and must always be present. If it’s not specified, pyroscope.scrape will attempt to infer it from either of the following sources, in this order:

  1. __meta_kubernetes_pod_annotation_pyroscope_io_service_name which is a pyroscope.io/service_name Pod annotation.
  2. __meta_kubernetes_namespace and __meta_kubernetes_pod_container_name
  3. __meta_docker_container_name
  4. __meta_dockerswarm_container_label_service_name or __meta_dockerswarm_service_name

If service_name isn’t specified and couldn’t be inferred, then it’s set to unspecified.

Blocks

You can use the following block with pyroscope.java:

profiling_config

The profiling_config block describes how async-profiler is invoked.

The following arguments are supported:

NameTypeDescriptionDefaultRequired
allocstringAllocation profiling sampling configuration. It’s passed as an --alloc argument to async-profiler."512k"no
cpuboolA flag to enable CPU profiling, using itimer async-profiler event by default.trueno
custom_argumentslist(string)Sends raw args to async-profiler, skipping all Alloy arguments except interval. Refer to custom_arguments.[]no
eventstringSets the CPU profiling event. Refer to event for supported values."itimer"no
intervaldurationHow frequently to collect profiles from the targets."60s"no
lockstringLock profiling sampling configuration. It’s passed as an --lock argument to async-profiler."10ms"no
log_levelstringSets the log level in async profiler. One of TRACE, DEBUG, INFO, WARN, ERROR, or NONE."INFO"no
per_threadboolSets per thread mode on async profiler. It’s passed as an -t argument to async-profiler.falseno
quietboolIf set, suppresses the Profiling started/stopped log message.falseno
sample_rateintCPU profiling sample rate. It’s converted from Hz to interval and passed as an -i argument to async-profiler.100no

Refer to profiler-options for more information about async-profiler configuration.

event

The event argument configures the profiling mode used by async-profiler. async-profiler supports various profiling modes including CPU profiling, wall-clock profiling, and hardware performance monitoring events. For a complete overview of all available profiling modes and their use cases, refer to Profiling modes in the async-profiler documentation.

per_thread

Warning

The per_thread option doesn’t apply when using JFR output format. Since pyroscope.java uses JFR format exclusively, this option has no effect. For more details, refer to Options applicable to any output format except JFR in the async-profiler documentation.

custom_arguments

custom_arguments passes async-profiler start flags directly.

When custom_arguments is set, Alloy skips these options from this block:

cpu, event, per_thread, sample_rate, alloc, lock, log_level.

For example, this enables multi-event profiling (cpu, alloc, and lock) with custom thresholds:

Alloy
pyroscope.java "java" {
  targets    = discovery.relabel.java.output
  forward_to = [pyroscope.write.staging.receiver]

  profiling_config {
    interval = "60s"
    custom_arguments = ["-e", "cpu,alloc,lock", "--alloc", "2m", "--lock", "10ms"]
  }
}

Refer to Profiling modes and profiler-options for the complete async-profiler option list.

Exported fields

pyroscope.java doesn’t export any fields that can be referenced by other components.

Component health

pyroscope.java is only reported as unhealthy when given an invalid configuration. In those cases, exported fields retain their last healthy values.

Debug information

pyroscope.java doesn’t expose any component-specific debug information.

Debug metrics

pyroscope.java doesn’t expose any component-specific debug metrics.

Examples

Profile every java process on the current host

Alloy
pyroscope.write "staging" {
  endpoint {
    url = "http://localhost:4040"
  }
}

discovery.process "all" {
  refresh_interval = "60s"
  discover_config {
    cwd = true
    exe = true
    commandline = true
    username = true
    uid = true
    container_id = true
  }
}

discovery.relabel "java" {
  targets = discovery.process.all.targets
  rule {
    action = "keep"
    regex = ".*/java$"
    source_labels = ["__meta_process_exe"]
  }
}

pyroscope.java "java" {
  targets = discovery.relabel.java.output
  forward_to = [pyroscope.write.staging.receiver]
  profiling_config {
    interval = "60s"
    alloc = "512k"
    cpu = true
    sample_rate = 100
    lock = "1ms"
  }
}

Compatible components

pyroscope.java can accept arguments from the following components:

Note

Connecting some components may not be sensible or components may require further configuration to make the connection work correctly. Refer to the linked documentation for more details.