Skip to content

Commit fac69a3

Browse files
author
Yuriy Bezsonov
committed
feat(perf-platform): add agentic performance analysis platform
1 parent 4a99ff0 commit fac69a3

26 files changed

Lines changed: 3595 additions & 5 deletions

File tree

apps/perf-analyzer/README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# perf-analyzer
2+
3+
The brain of the agentic performance platform. Receives triggers (developer
4+
on-demand and Grafana webhook), drives the `perf-collector` to dump JFR and
5+
thread snapshots, queries Pyroscope for the top hot functions, calls Amazon
6+
Bedrock via Spring AI with source-code grounding, and writes a Markdown
7+
report to S3 alongside the raw artifacts.
8+
9+
The full deployment walkthrough lives in the workshop content at
10+
`content/analysis/perf-platform/analyzer/`. This README covers build and
11+
the contract only.
12+
13+
## Build
14+
15+
```bash
16+
cd apps/perf-analyzer
17+
mvn compile jib:build -Dimage=${ECR_URI}/perf-analyzer:latest
18+
```
19+
20+
Multi-arch (`linux/amd64` + `linux/arm64`), Amazon Corretto 25 JRE base.
21+
22+
## Endpoints
23+
24+
| Method | Path | Purpose |
25+
|--------|------|---------|
26+
| POST | `/api/v1/analyze` | Developer on-demand. Body: `{service, platform, pod or task, reason}`. |
27+
| POST | `/api/v1/grafana-webhook` | Grafana alert payload; one analysis per firing alert. |
28+
| GET | `/actuator/health` | Liveness + readiness probes. |
29+
| GET | `/actuator/prometheus` | Metrics. |
30+
31+
Both `/api/v1/*` endpoints return `202 Accepted` with
32+
`{analysisId, s3Prefix}`. Analysis runs asynchronously on a virtual thread.
33+
34+
## Environment variables
35+
36+
| Name | Required | Description |
37+
|------|----------|-------------|
38+
| `AWS_REGION` | yes | AWS Region for Bedrock, S3, ECS SDK clients. |
39+
| `AWS_S3_BUCKET` | yes | Workshop bucket (SSM `workshop-bucket-name`). |
40+
| `PYROSCOPE_URL` | yes | `http://pyroscope.monitoring:4040` on EKS. |
41+
| `SPRING_AI_BEDROCK_CONVERSE_CHAT_OPTIONS_MODEL` | yes | Claude Sonnet 4.6 model id. |
42+
| `SPRING_AI_BEDROCK_CONVERSE_CHAT_OPTIONS_MAX_TOKENS` | no | Default 10000. |
43+
| `GITHUB_REPO_URL` | no | `https://api.github.com/repos/aws-samples/java-on-aws`. |
44+
| `GITHUB_REPO_PATH` | no | `apps/unicorn-store-spring`. |
45+
| `GITHUB_TOKEN` | no | GitHub PAT for private repos. |
46+
47+
## Flow
48+
49+
```
50+
POST /api/v1/analyze or /api/v1/grafana-webhook
51+
52+
53+
AnalysisService.submit ──► 202 {analysisId, s3Prefix}
54+
│ (virtual thread)
55+
56+
Resolve collector URL
57+
- EKS: pod → nodeName → DaemonSet pod IP on that node (K8s API)
58+
- ECS: task → DescribeTasks → sidecar ENI private IP
59+
60+
61+
Three parallel lanes (virtual threads):
62+
a. POST /dump{jfr} → poll S3 → JfrParser.formatForModel
63+
b. POST /dump{threaddump} → poll S3 → first 200 lines
64+
c. PyroscopeTool.topFunctions (pre-fetched canonical prompt section)
65+
66+
67+
AiService builds layered prompt, calls Bedrock via Spring AI ChatClient
68+
69+
70+
S3 writes: request.json, events.md, threaddump.json, analysis.md
71+
```
72+
73+
## Spring AI tools (@Tool)
74+
75+
- **PyroscopeTool** — top-level `@Component`. Always registered. Used both
76+
by `AnalysisService` to pre-fetch the canonical Pyroscope section and by
77+
the model to request additional windows/labels during reasoning.
78+
- **GitHubSourceCodeTool** — nested package-private class in `AiService`.
79+
Instantiated only when `GITHUB_REPO_URL` is set. Lets the model look up
80+
methods from stacks and cite file paths and line numbers in findings.
81+
82+
## S3 layout
83+
84+
```
85+
perf-platform/
86+
analysis/{platform}/{service}/{target}/{YYYYMMDD-HHMMSS-hex}/
87+
request.json # normalized AnalysisRequest
88+
events.md # JfrParser Markdown (model input, captured)
89+
threaddump.json # raw Thread.print wrapped in JSON
90+
analysis.md # Markdown report (model output)
91+
profiling/{platform}/{service}/{target}/
92+
dump-{jobId}.jfr # collector drop consumed by the JFR lane
93+
dump-{jobId}.json # thread dump drop consumed by the thread-dump lane
94+
```
95+
96+
## JFR events extracted
97+
98+
`jdk.ExecutionSample`, `jdk.CPULoad`, `jdk.GCHeapSummary`, `jdk.JVMInformation`,
99+
`jdk.GCPhasePause`, `jdk.Compilation`, `jdk.Deoptimization`,
100+
`jdk.JavaMonitorEnter`, `jdk.SafepointBegin`, `jdk.ContainerConfiguration`.
101+
102+
Each produces top-5 aggregates for model input, not raw events.

apps/perf-analyzer/pom.xml

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>4.0.6</version>
9+
<relativePath/>
10+
</parent>
11+
12+
<groupId>com.example.perf</groupId>
13+
<artifactId>perf-analyzer</artifactId>
14+
<version>1.0.0</version>
15+
<name>perf-analyzer</name>
16+
<description>Agentic Performance Platform analyzer (Spring AI + Amazon Bedrock)</description>
17+
18+
<properties>
19+
<java.version>25</java.version>
20+
<maven.compiler.release>25</maven.compiler.release>
21+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
22+
<spring-ai.version>2.0.0-M5</spring-ai.version>
23+
<aws-sdk.version>2.40.15</aws-sdk.version>
24+
<kubernetes-client.version>22.0.0</kubernetes-client.version>
25+
</properties>
26+
27+
<dependencyManagement>
28+
<dependencies>
29+
<dependency>
30+
<groupId>software.amazon.awssdk</groupId>
31+
<artifactId>bom</artifactId>
32+
<version>${aws-sdk.version}</version>
33+
<type>pom</type>
34+
<scope>import</scope>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.springframework.ai</groupId>
38+
<artifactId>spring-ai-bom</artifactId>
39+
<version>${spring-ai.version}</version>
40+
<type>pom</type>
41+
<scope>import</scope>
42+
</dependency>
43+
</dependencies>
44+
</dependencyManagement>
45+
46+
<dependencies>
47+
<dependency>
48+
<groupId>org.springframework.boot</groupId>
49+
<artifactId>spring-boot-starter-web</artifactId>
50+
</dependency>
51+
<dependency>
52+
<groupId>org.springframework.boot</groupId>
53+
<artifactId>spring-boot-starter-actuator</artifactId>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.springframework.boot</groupId>
57+
<artifactId>spring-boot-starter-validation</artifactId>
58+
</dependency>
59+
60+
<!-- Spring AI + Amazon Bedrock Converse -->
61+
<dependency>
62+
<groupId>org.springframework.ai</groupId>
63+
<artifactId>spring-ai-starter-model-bedrock-converse</artifactId>
64+
</dependency>
65+
66+
<!-- AWS SDK: S3, ECS DescribeTasks -->
67+
<dependency>
68+
<groupId>software.amazon.awssdk</groupId>
69+
<artifactId>s3</artifactId>
70+
</dependency>
71+
<dependency>
72+
<groupId>software.amazon.awssdk</groupId>
73+
<artifactId>ecs</artifactId>
74+
</dependency>
75+
76+
<!-- Kubernetes client: pod -> nodeName -> collector pod IP -->
77+
<dependency>
78+
<groupId>io.kubernetes</groupId>
79+
<artifactId>client-java</artifactId>
80+
<version>${kubernetes-client.version}</version>
81+
</dependency>
82+
83+
<!-- Micrometer -> Prometheus -->
84+
<dependency>
85+
<groupId>io.micrometer</groupId>
86+
<artifactId>micrometer-registry-prometheus</artifactId>
87+
</dependency>
88+
89+
<dependency>
90+
<groupId>org.springframework.boot</groupId>
91+
<artifactId>spring-boot-starter-test</artifactId>
92+
<scope>test</scope>
93+
</dependency>
94+
</dependencies>
95+
96+
<build>
97+
<plugins>
98+
<plugin>
99+
<groupId>com.google.cloud.tools</groupId>
100+
<artifactId>jib-maven-plugin</artifactId>
101+
<version>3.5.1</version>
102+
<configuration>
103+
<from>
104+
<image>public.ecr.aws/docker/library/amazoncorretto:25-al2023</image>
105+
<platforms>
106+
<platform>
107+
<architecture>amd64</architecture>
108+
<os>linux</os>
109+
</platform>
110+
<platform>
111+
<architecture>arm64</architecture>
112+
<os>linux</os>
113+
</platform>
114+
</platforms>
115+
</from>
116+
<container>
117+
<user>1000</user>
118+
</container>
119+
</configuration>
120+
</plugin>
121+
</plugins>
122+
</build>
123+
</project>

0 commit comments

Comments
 (0)