Project: Grafana Pyroscope (Observability and Analysis / Observability)
File: java.md

title: "Java" menuTitle: "Java" description: "Instrumenting Java applications for continuous profiling." weight: 30 aliases: /docs/phlare/latest/configure-client/language-sdks/java The Java Profiler, integrated with Pyroscope, offers a comprehensive solution for performance analysis in Java applications. It provides real-time insights, enabling developers to understand and optimize their Java codebase effectively. This tool is crucial for improving application responsiveness, reducing resource consumption, and ensuring top-notch performance in Java environments. {{< admonition type="note" >}} Refer to for a list of profile types supported by each language. {{< /admonition >}} To capture and analyze profiling data, you need either a hosted Pyroscope OSS server or a hosted (requires a free Grafana Cloud account). The Pyroscope server can be a local server for development or a remote server for production use. Java integration is distributed as a single jar file (`pyroscope.jar`) or a Maven package. Supported platforms include: Linux on x64 Linux on ARM64 MacOS on x64 MacOS on ARM64 Visit the GitHub page to download the latest version of `pyroscope.jar`. The latest release is also available on . You can start Pyroscope either from your application's code or attach it as javaagent. First, add the Pyroscope dependency: {{< code >}} ```maven <dependency> <groupId>io.pyroscope</groupId> <artifactId>agent</artifactId> <version>0.13.1</version> </dependency> ``` ```gradle implementation("io.pyroscope:agent:0.13.1") ``` {{< /code >}} Add the following code to your application: {{< code >}} ```java PyroscopeAgent.start( new Config.Builder() .setApplicationName("ride-sharing-app-java") .setProfilingEvent(EventType.ITIMER) .setFormat(Format.JFR) .setServerAddress("http://pyroscope-server:4040") .build() ); ``` ```spring import io.pyroscope.javaagent.PyroscopeAgent; import io.pyroscope.javaagent.config.Config; import io.pyroscope.javaagent.EventType; import io.pyroscope.http.Format; @PostConstruct public void init() { PyroscopeAgent.start( new Config.Builder() .setApplicationName("ride-sharing-app-java") .setProfilingEvent(EventType.ITIMER) .setFormat(Format.JFR) .setServerAddress("http://pyroscope-server:4040") // Optionally, if authentication is enabled, specify the API key. // .setBasicAuthUser("<User>") // .setBasicAuthPassword("<Password>") // Optionally, if you'd like to set allocation threshold to register events, in bytes. '0' registers all events // .setProfilingAlloc("0") .build() ); } ``` {{< /code >}} You can also optionally replace some Pyroscope components: ```java PyroscopeAgent.start( new PyroscopeAgent.Options.Builder(config) .setExporter(snapshot -> { // Your custom export/upload logic may go here // It is invoked every 10 seconds by default with snapshot of // profiling data }) .setLogger((l, msg, args) -> { // Your custom logging may go here // Pyroscope does not depend on any logging library System.out.printf((msg) + "%n", args); }) .setScheduler(profiler -> { // Your custom profiling schedule logic may go here }) .build() ); ``` To start profiling a Java application, run your application with `pyroscope.jar` `javaagent`: ```shell export PYROSCOPEAPPLICATIONNAME=my.java.app export PYROSCOPESERVERADDRESS=http://pyroscope-server:4040 java -javaagent:pyroscope.jar -jar app.jar ``` You can add dynamic tags (labels) to the profiling data. These tags can filter the data in the

Add labels dynamically: ```java Pyroscope.LabelsWrapper.run(new LabelsSet("controller", "slow_controller"), () -> { slowCode(); }); ``` You can also add static tags (labels) to the profiling data: ```java Pyroscope.setStaticLabels(Map.of("region", System.getenv("REGION"))); // or with Config.Builder if you start pyroscope with PyroscopeAgent.start PyroscopeAgent.start(new Config.Builder() .setLabels(mapOf("region", System.getenv("REGION"))) // ... .build() ); ``` When you start Pyroscope as `javaagent` or obtain configuration by `Config.build()`, Pyroscope searches for configuration in multiple sources: system properties, environment variables, and `pyroscope.properties`. Property keys have the same names as environment variables, but are in lowercase and underscores (``) are replaced with periods (`.`). For example, `PYROSCOPEFORMAT` becomes `pyroscope.format` The Java integration supports JFR format to be able to support multiple events (JFR is the only output format that supports ). There are several environment variables that define how multiple event configuration works: | Flag | Description | ||| | `PYROSCOPEAGENTENABLED` | Enables the agent. The default is `true`. | | `PYROSCOPE_FORMAT` | Sets the profiler output format. The default is `collapsed`, but in order to support multiple formats it must be set to `jfr`. | | `PYROSCOPEPROFILEREVENT` | Sets the profiler event. With JFR format enabled, this event refers to one of the possible CPU profiling events: `itimer`, `cpu`, `wall`. The default is `itimer`. | | `PYROSCOPEPROFILERALLOC` | Sets the allocation threshold to register the events, in bytes (equivalent to `--alloc=` in `async-profiler`). The default value is `""` - empty string, which means that allocation profiling is disabled. Setting it to `0` will register every event, causing significant CPU and network overhead, making it not suitable for production environments. We recommend setting a starting value of 512k and adjusting it as needed. | | `PYROSCOPEPROFILERLOCK` | Sets the lock threshold to register the events, in nanoseconds (equivalent to `--lock=` in `async-profiler`). The default value is `""` - empty string, which means that lock profiling is disabled. Setting it to `0` will register every event, causing significant CPU and network overhead, making it not suitable for production environments. We recommend setting a starting value of 10ms and adjusting it as needed. | | `PYROSCOPECONFIGURATIONFILE` | Sets an additional properties configuration file. The default value is `pyroscope.properties`. | | `PYROSCOPEBASICAUTH_USER` | HTTP Basic authentication username. The default value is `""` - empty string, no authentication. | | `PYROSCOPEBASICAUTH_PASSWORD` | HTTP Basic authentication password. The default value is `""` - empty string, no authentication. | | `PYROSCOPETENANTID` | pyroscope tenant ID, passed as X-Scope-OrgID http header. The default value is `""` - empty string, no tenant

| | `PYROSCOPEHTTPHEADERS` | Extra HTTP headers in JSON format, for example: `{"X-Header": "Value"}`. The default value is `{}` - no extra headers. | | `PYROSCOPE_LABELS` | Sets static labels in the form of comma separated `key=value` pairs. The default value is `""` - empty string, no labels. | | `PYROSCOPELOGLEVEL` | Determines the level of verbosity for Pyroscope's logger. Available options include `debug`, `info`, `warn`, and `error`. The default value is set to `info`. | | `PYROSCOPEPUSHQUEUE_CAPACITY` | Specifies the size of the ingestion queue that temporarily stores profiling data in memory during network outages. The default value is set to 8. | | `PYROSCOPEINGESTMAX_TRIES` | Sets the maximum number of times to retry an ingestion API call in the event of failure. A value of `-1` indicates that the retries will continue indefinitely. The default value is set to `8`. | | `PYROSCOPEEXPORTCOMPRESSIONLEVELJFR` | Sets the level of GZIP compression applied to uploaded JFR files. This option accepts values of `NOCOMPRESSION`, `BESTSPEED`, `BESTCOMPRESSION`, and `DEFAULTCOMPRESSION`. | | `PYROSCOPEEXPORTCOMPRESSIONLEVELLABELS` | Operates similarly to `PYROSCOPEEXPORTCOMPRESSIONLEVELJFR`, but applies to the dynamic labels part. The default value is set to `BEST_SPEED`. | | `PYROSCOPEGCBEFORE_DUMP` | A boolean value that executes a `System.gc()` command before dumping the profile when set to `true`. This option may be useful for live profiling, but is disabled by default. | Add the following code to your application: ```java PyroscopeAgent.start( new Config.Builder() .setApplicationName("test-java-app") .setProfilingEvent(EventType.ITIMER) .setFormat(Format.JFR) .setServerAddress("<URL>") // Set these if using Grafana Cloud: .setBasicAuthUser("<User>") .setBasicAuthPassword("<Password>") // Optional Pyroscope tenant ID (only needed if using multi-tenancy). Not needed for Grafana cloud. // .setTenantID("<TenantID>") .build() ); ``` To configure the Java SDK to send data to Pyroscope, replace the `<URL>` placeholder with the appropriate server URL. This could be the Grafana Cloud URL or your own custom Pyroscope server URL. If you need to send data to Grafana Cloud, you'll have to configure HTTP Basic authentication. Replace `<User>` with your Grafana Cloud stack user and `<Password>` with your Grafana Cloud API key. If your Pyroscope server has multi-tenancy enabled, you'll need to configure a tenant ID. Replace `<TenantID>` with your Pyroscope tenant ID. The following configuration sets application name, Pyroscope format, profiling interval, event, and lock. This example is an excerpt from the available in the Pyroscope repository. ``` ENV PYROSCOPEAPPLICATIONNAME=rideshare.java.push.app ENV PYROSCOPE_FORMAT=jfr ENV PYROSCOPEPROFILINGINTERVAL=10ms ENV PYROSCOPEPROFILEREVENT=itimer ENV PYROSCOPEPROFILERLOCK=10ms ``` This configuration excerpt enables allocation and lock profiling: ``` PYROSCOPEPROFILERALLOC=512k PYROSCOPEPROFILERLOCK=10ms ``` Check out the following resources to learn more about Java profiling: showing Java example with tags