{"id":38407450,"url":"https://github.com/dpsoft/ap-agent","last_synced_at":"2026-01-17T04:01:32.127Z","repository":{"id":65716367,"uuid":"591414493","full_name":"dpsoft/ap-agent","owner":"dpsoft","description":"Java agent that acts as a proxy to the almighty Async Profiler","archived":false,"fork":false,"pushed_at":"2025-11-28T04:08:02.000Z","size":229,"stargazers_count":34,"open_issues_count":8,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-11-30T09:35:20.704Z","etag":null,"topics":["async-profiler","firefox-profile","flamegraph","flamescope","java","performance","pprof","profiling"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dpsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-20T17:44:24.000Z","updated_at":"2025-11-27T11:04:20.000Z","dependencies_parsed_at":"2023-10-01T21:48:33.898Z","dependency_job_id":null,"html_url":"https://github.com/dpsoft/ap-agent","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/dpsoft/ap-agent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpsoft%2Fap-agent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpsoft%2Fap-agent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpsoft%2Fap-agent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpsoft%2Fap-agent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dpsoft","download_url":"https://codeload.github.com/dpsoft/ap-agent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpsoft%2Fap-agent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28494127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T02:39:23.645Z","status":"ssl_error","status_checked_at":"2026-01-17T02:34:19.649Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-profiler","firefox-profile","flamegraph","flamescope","java","performance","pprof","profiling"],"created_at":"2026-01-17T04:01:12.332Z","updated_at":"2026-01-17T04:01:32.086Z","avatar_url":"https://github.com/dpsoft.png","language":"Java","readme":"# AP-Agent\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.dpsoft/ap-agent)](https://search.maven.org/search?q=ap-agent)\n[![Maven CI/CD](https://github.com/dpsoft/ap-agent/actions/workflows/build.yml/badge.svg)](https://github.com/dpsoft/ap-agent/actions/workflows/build.yml)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\nAsync Profiler Agent is a minimal Java agent that allows you to proxy to [Async Profiler] via a minimal REST API, making it easy to profile your applications. Simply add it to the start of the JVM and as it uses the [AP-Loader], there is no need for Async Profiler up front.\n\n\n## Usage\nDownload the [latest version](https://s01.oss.sonatype.org/service/local/repositories/releases/content/io/github/dpsoft/ap-agent/0.1.9/ap-agent-0.1.9.jar).\n\nTo use the `AP-Agent`, simply add it to the JVM startup. The agent exposes a REST API for profiling with the following endpoint: `http://localhost:8080/profiler/profile`.\n\n```shell\njava -javaagent:/path/to/ap-agent.jar -jar /path/to/my-awesome-app.jar\n```\n\nThe endpoint accepts the following parameters:\n\n* `event`: The type of event to profile (e.g. `cpu`, `itimer`, `ctimer`, `wall` `nativemem`)\n* `output`: The desired output format (e.g. `flamegraph`, `heatmap`, `jfr`, `pprof`, `collapsed`)\n* `params`: Additional parameters to pass to the flame graph (e.g. `simple`, `title=My Title`, `threads`, `reverse`)\n* `duration`: The length of time to profile for (in seconds)\n\n### Flame Graph\nFor example, to profile CPU usage for 30 seconds and output the results in Flamegraph format, the following API call would be used: `http://localhost:8080/profiler/profile?event=cpu\u0026output=flame\u0026duration=30`\n\n![image](https://user-images.githubusercontent.com/2567525/214323977-af9a4c92-8cbc-48dd-a0c6-f1f7a37122ee.png)\n\n### Flame Graph from Collapsed Stack Traces\nThe collapsed stack trace format is a collection of call stacks, where each line represents a semicolon-separated list of frames followed by a counter. The frames represent the function calls in the stack and the counter indicates how many times that particular stack has been executed.\n\nThe format is as follows:\n```shell\nmain;run;doSomething;processData;readFile;open;readBytes:5\nmain;run;doSomething;processData;readFile;open;readBytes:3\nmain;run;doSomething;processData;readFile;open;readBytes:2\nmain;run;doSomething;processData;readFile;close:1\nmain;run;doSomething;processData;writeFile;open;writeBytes:4\nmain;run;doSomething;processData;writeFile;close:1\n```\n\nTo generate a flame graph from the collapsed stack trace format, and share it easily using [flamegraph.com], you can use the following command:\n\n```shell\ncurl http://localhost:8080/profiler/profile?event=cpu\u0026output=collapsed\u0026duration=30 | curl --data-binary @- https://flamegraph.com | jq -r '.\"url\"' \n...\n...\nhttps://flamegraph.com/share/4672162e-a978-11ed-aa32-fa99570776b6\n```\nFinally, you can open the URL in your browser to view the flame graph.\n\n![image](https://user-images.githubusercontent.com/2567525/218182805-34568aa7-71ae-420e-9385-1b788918956b.png)\n\n## Continuous Profiling a la Bash\nWe can create a simple bash script to continuously profile our application and output the results to a file. \n\n```bash\n#!/bin/bash\n\nevent=${1:-itimer}\nprofiling_duration=${2:-30}\nresults_folder=${3:-profiling_results}\n\nmkdir -p $results_folder\n\nwhile true; do\n    timestamp=$(date +%Y-%m-%d_%H-%M-%S)\n    output_file=\"${event}_profile_$timestamp.html\"\n    start_time=$(date +%s)\n    curl -s \"http://localhost:8080/profiler/profile?event=$event\u0026output=flame\u0026duration=$profiling_duration\" -o \"$results_folder/$output_file\"\n    end_time=$(date +%s)\n    duration=$((end_time - start_time))\n    echo \"Profile saved to $results_folder/$output_file at $(date) took $duration seconds.\"\ndone\n```\nRunning the script with the `cpu` event and `60 second` duration, we can see the results in the `profiling_results` folder.\n\n```shell\n./loop.sh cpu 60 profiling_results\n\nProfile saved to profiling_results/cpu_profile_2023-01-24_16-16-24.html at 04:17:24 took 60 seconds.\nProfile saved to profiling_results/cpu_profile_2023-01-24_16-16-24.html at 04:18:24 took 60 seconds.\n```\n\n## Go Mode\nThe agent also supports a `GO`(lang) mode, which exposes the `/debug/pprof/profile` endpoint. This is where we can use the go [pprof] tools.\n\n```shell\njava -Dap-agent.handler.go-mode=true -javaagent:/path/to/ap-agent.jar -jar /path/to/my-awesome-app.jar\n\ngo tool pprof -http :8000 http://localhost:8080/debug/pprof/profile?seconds=30  \n```\n\n![image](https://user-images.githubusercontent.com/2567525/214324772-91ac9a97-13b3-4ed1-90a8-175882e79a5b.png)    \n\n![image](https://user-images.githubusercontent.com/2567525/214325045-0907e055-8f17-45cf-9f57-c2b52c366854.png)\n\n\n### Additional Endpoints\nIn addition, the `AP-Agent` also supports two additional endpoints:\n\n* `/debug/pprof/block`: Returns a profiling report of contended locks that are blocking on synchronization primitives. This endpoint can help identify where resources are being locked and where contention is occurring.\n* `/debug/pprof/allocs`: Returns a profiling report of memory allocations performed by the application. This endpoint can help identify where memory is being allocated and what kind of objects are consuming the most memory.\n\n### Example using [pprof.me] \nOne way to analyze the profiling results generated by the **AP-Agent** is to use pprof.me. It is a free online tool that allows you to upload profiling data and visualize it, without having to install any additional tools.\n\n ```shell\ncurl -s http://localhost:8080/debug/pprof/allocs \u003e allocs.pb.gz\npprofme upload -d \"java allocs\" allocs.pb.gz\nfirefox | chrome https://pprof.me/a25a2a9\n\n```\n\n![image](https://user-images.githubusercontent.com/2567525/235777910-3f2c25e6-e66d-4d00-b3a7-eab950562368.png)\n\n### Can I use the ap-agent as a library?\n\nYes, you can use the ap-agent as library, just add the following dependency to your project:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.dpsoft\u003c/groupId\u003e\n    \u003cartifactId\u003eap-agent\u003c/artifactId\u003e\n    \u003cversion\u003e0.1.9\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand then, you can use the API as follows(spring-boot controller example):\n\n```java\n@RestController\npublic class PPROFController {\n    private final static Logger log = LoggerFactory.getLogger(PPROFController.class);\n\n    private final AsyncProfiler asyncProfiler = AsyncProfilerLoader.loadOrNull();\n\n    @GetMapping(value = {\"/debug/pprof/profile\", \"/debug/pprof/block\", \"/debug/pprof/allocs\"})\n    @ResponseBody\n    public void profile(@RequestParam Map\u003cString,String\u003e queryParams, HttpServletRequest request, HttpServletResponse response)  {\n        final var operation = Functions.lastSegment(request.getServletPath());\n        final var command = Command.from(operation, queryParams);\n\n        ProfilerExecutor\n                .with(asyncProfiler, command)\n                .run()\n                .onSuccess(result -\u003e result.pipeTo(response::getOutputStream))\n                .onFailure(cause -\u003e log.error(\"It has not been possible to execute the profiler command.\", cause))\n                .andFinallyTry(response::flushBuffer);\n    }\n}\n```\n\n\n## License\nThis code base is available under the Apache License, version 2.\n\n[AP-Loader]: https://github.com/jvm-profiling-tools/ap-loader\n[Async Profiler]: https://github.com/jvm-profiling-tools/async-profiler\n[pprof]: https://go.dev/blog/pprof\n[flamegraph.com]:https://flamegraph.com/\n[pprof.me]: https://pprof.me/\n[experimental]:  https://s01.oss.sonatype.org/content/repositories/releases/io/github/dpsoft/ap-agent-experimental/0.1.3/ap-agent-experimental-0.1.3.jar\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpsoft%2Fap-agent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdpsoft%2Fap-agent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpsoft%2Fap-agent/lists"}