Java
Pyroscope uses async-profiler to collect profiling data from Java applications.
#
Supported platformsLinux | macOS | Windows | Docker |
---|---|---|---|
✅ | ✅ | ✅ |
#
InstallationJava integration is distributed as a single jar file: pyroscope.jar
. It contains native async-profiler
libraries for:
- Linux on x64;
- Linux on ARM64;
- MacOS on x64.
- MacOS on ARM64.
Visit our GitHub releases page to download the latest version of pyroscope.jar
.
The latest release is also available on Maven Central.
#
Profiling Java applicationYou can start pyroscope either from your apps's java code or attach it as javaagent
#
Start pyroscope from app's java codeAdd pyroscope dependency:
- Maven
- Gradle
<dependency> <groupId>io.pyroscope</groupId> <artifactId>agent</artifactId> <version>pyroscope_version</version></dependency>
Then add the following code to your application:
- Java
- Spring Framework
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. // .setAuthToken(System.getenv("PYROSCOPE_AUTH_TOKEN")) .build() );
You can also optionally replace some pyroscope components
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());
#
Start pyroscope as javaagentTo start profiling a Java application, run your application with pyroscope.jar
javaagent:
export PYROSCOPE_APPLICATION_NAME=my.java.appexport PYROSCOPE_SERVER_ADDRESS=http://pyroscope-server:4040
# Optionally, if authentication is enabled, specify the API key.# export PYROSCOPE_AUTH_TOKEN={YOUR_API_KEY}
java -javaagent:pyroscope.jar -jar app.jar
#
ConfigurationWhen you start pyroscope as javaagent or obtain configuration by Config.build()
pyroscope searches
for configuration in multiple sources: system properties, environment variables, pyroscope.properties file. Properties keys has same name as environment variables, but lowercased and replaced _
with .
, so PYROSCOPE_FORMAT
becomes pyroscope.format
Java integration supports JFR format to be able to support multiple events (JFR is the only output format that supports multiple events in async-profiler
). There are several environment variables that define how multiple event configuration works:
PYROSCOPE_FORMAT
sets the profiler output format. The default iscollapsed
, but in order to support multiple formats it must be set tojfr
.PYROSCOPE_PROFILER_EVENT
sets the profiler event. With JFR format enabled, this event refers to one of the possible CPU profiling events:itimer
,cpu
,wall
. The default isitimer
.PYROSCOPE_PROFILER_ALLOC
sets the allocation threshold to register the events, in bytes (equivalent to--alloc=
inasync-profiler
). The default value is "" - empty string, which means that allocation profiling is disabled. Setting it to0
will register all the events.PYROSCOPE_PROFILER_LOCK
sets the lock threshold to register the events, in nanoseconds (equivalent to--lock=
inasync-profiler
). The default value is "" - empty string, which means that lock profiling is disabled. Setting it to0
will register all the events.
There are some extra configuration options:
PYROSCOPE_CONFIGURATION_FILE
sets an additional properties configuration file. The default value ispyroscope.properties
.PYROSCOPE_BASIC_AUTH_USER
HTTP Basic authentication username. The default value is""
- empty string, no authentication.PYROSCOPE_BASIC_AUTH_PASSWORD
HTTP Basic authentication password. The default value is""
- empty string, no authentication.PYROSCOPE_TENANT_ID
phlare tenant ID, passed as X-Scope-OrgID http header. The default value is""
- empty string, no tenant ID.PYROSCOPE_HTTP_HEADERS
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 separatedkey=value
pairs. The default value is""
- empty string, no labels.PYROSCOPE_LOG_LEVEL
determines the level of verbosity for Pyroscope's logger. Available options includedebug
,info
,warn
, anderror
. The default value is set toinfo
.PYROSCOPE_PUSH_QUEUE_CAPACITY
specifies the size of the ingestion queue that temporarily stores profiling data in memory during network outages. It is recommended to keep this queue size reasonably small, and the default value is set to 8.PYROSCOPE_INGEST_MAX_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.PYROSCOPE_EXPORT_COMPRESSION_LEVEL_JFR
sets the level of GZIP compression applied to uploaded JFR files. This option accepts values ofNO_COMPRESSION
,BEST_SPEED
,BEST_COMPRESSION
, andDEFAULT_COMPRESSION
, as well as numeric values between -1 and 9, where -1 representsDEFAULT_COMPRESSION
, 0 representsNO_COMPRESSION
, 1 representsBEST_SPEED
, and 9 representsBEST_COMPRESSION
. The default value is set toBEST_SPEED
.PYROSCOPE_EXPORT_COMPRESSION_LEVEL_LABELS
perates similarly toPYROSCOPE_EXPORT_COMPRESSION_LEVEL_JFR
, but applies to the dynamic labels part. The default value is set toBEST_SPEED
.PYROSCOPE_ALLOC_LIVE
is a boolean value that enables live object profiling when set to true. It is disabled by default.PYROSCOPE_GC_BEFORE_DUMP
is a boolean value that executes aSystem.gc()
command before dumping the profile when set to true. This option may be useful for live profiling, but is disabled by default.
#
LabelsIt is possible to add dynamic tags (labels) to the profiling data. These tags can be used to filter the data in the UI.
Add labels dynamically:
Pyroscope.LabelsWrapper.run(new LabelsSet("controller", "slow_controller"), () -> { slowCode();});
It is also possible to possible to add static tags (labels) to the profiling data:
Pyroscope.setStaticLabels(Map.of("region", System.getenv("REGION")));// or with Config.Builder if you start pyroscope with PyroscopeAgent.startPyroscopeAgent.start(new Config.Builder() .setLabels(mapOf("region", System.getenv("REGION"))) // ... .build());
#
Sending data to Phlare with Pyroscope java integrationStarting with weekly-f8 you can ingest pyroscope profiles directly to phlare.
- From code
- As javaagent
PyroscopeAgent.start( new Config.Builder() .setApplicationName("phlare.java.app") .setFormat(Format.JFR) .setServerAddress("<URL>") // Optional HTTP Basic authentication .setBasicAuthUser("<User>") .setBasicAuthPassword("<Password>") // Optional Phlare tenant ID .setTenantID("<TenantID>") .build());
To configure java integration to send data to Phlare, replace the <URL>
placeholder with the appropriate server URL. This could be the grafana.com Phlare URL or your own custom Phlare server URL.
If you need to send data to grafana.com, you'll have to configure HTTP Basic authentication. Replace <User>
with your grafana.com stack user and <Password>
with your grafana.com API key.
If your Phlare server has multi-tenancy enabled, you'll need to configure a tenant ID. Replace <TenantID>
with your Phlare tenant ID.
#
Java profiling examplesCheck out the following resources to learn more about Java profiling:
- Java examples
- Java Demo showing Java example with tags
- Java blog post