Skip to content

Commit 9bf2500

Browse files
committed
docs + sample application
1 parent 6151b88 commit 9bf2500

34 files changed

+429
-71
lines changed

README-ELK.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,20 @@ For TCP, use:
122122

123123
Example run (hello world sample):
124124

125+
```bash
126+
cd sample_application && mvn clean package
127+
```
128+
129+
Then start with agent and UDP output:
130+
125131
```bash
126132
java \
127133
-javaagent:"${PWD}/target/java-code-tracer-1.0-SNAPSHOT-jar-with-dependencies.jar" \
128134
-Djct.loglevel=INFO \
129135
-Djct.config="${PWD}/doc/config-sample-helloworld-udp.yaml" \
130136
-Djct.logDir=/tmp/jct \
131137
-noverify \
132-
-jar "${PWD}/doc/helloworld-loop.jar"
138+
-jar "${PWD}/doc/java-code-tracer-sample-application.jar"
133139
```
134140

135141
To run over TCP, switch config file to:

README.md

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ If you work in a legacy app and ask things like "Can we remove this?" or "Is thi
2222
- [Hello World Walkthrough](#hello-world-walkthrough)
2323
- [Tools](#tools)
2424
- [ELK Integration Guide](#elk-integration-guide)
25+
- [Sample Application Screenshots](#sample-application-screenshots)
2526
- [Similar Projects](#similar-projects)
2627
- [IntelliJ JVM Options Example](#intellij-jvm-options-example)
2728
- [License](#license)
@@ -60,7 +61,7 @@ Minimum commands:
6061
```bash
6162
mvn clean package
6263
mkdir -p "$HOME/.jct"
63-
cp doc/config-sample-file.yaml "$HOME/.jct/config-sample-file.yaml"
64+
cp doc/config-sample-application-file.yaml "$HOME/.jct/config-sample-file.yaml"
6465
java \
6566
-javaagent:"${PWD}/target/java-code-tracer-1.0-SNAPSHOT-jar-with-dependencies.jar" \
6667
-Djct.config="$HOME/.jct/config-sample-file.yaml" \
@@ -207,11 +208,20 @@ processor:
207208
208209
```json
209210
{
210-
"stack": [
211-
"de.example.Service.doWork()",
212-
"de.example.Repository.findById()"
213-
],
214-
"timestampMillis": "1528120883697"
211+
"stack": [
212+
"de.marcelsauer.sample.ClassA.methodA_1()",
213+
"de.marcelsauer.sample.ClassB.methodB_2()",
214+
"de.marcelsauer.sample.ClassB.methodB_3()",
215+
"de.marcelsauer.sample.ClassC.methodC_4()",
216+
"de.marcelsauer.sample.ClassD.methodD_5()",
217+
"de.marcelsauer.sample.ClassE.methodE_6()",
218+
"de.marcelsauer.sample.ClassF.methodF_7()",
219+
"de.marcelsauer.sample.ClassG.methodG_8()",
220+
"de.marcelsauer.sample.ClassH.methodH_9()",
221+
"de.marcelsauer.sample.ClassI.methodI_10()",
222+
"de.marcelsauer.sample.ClassJ.methodJ_11()"
223+
],
224+
"timestampMillis": "1528120883697"
215225
}
216226
```
217227

@@ -228,20 +238,30 @@ For more instrumentation details, increase log level:
228238
-Djct.loglevel=DEBUG
229239
```
230240

231-
## Hello World Walkthrough
241+
Hint: `DEBUG` is useful when you want to see what happens behind the scenes (for example class matching, instrumentation attempts, and skipped classes).
242+
243+
## Sample Application Walkthrough
244+
245+
Build the sample app jar to `doc/java-code-tracer-sample-application.jar`:
246+
247+
```bash
248+
cd sample_application && mvn clean package && cd ..
249+
```
232250

233-
Use the sample loop jar in `doc/helloworld-loop.jar`:
251+
Then run it with the agent from the repository root (`java-code-tracer`):
234252

235253
```bash
236254
java \
237255
-javaagent:"${PWD}/target/java-code-tracer-1.0-SNAPSHOT-jar-with-dependencies.jar" \
238256
-Djct.loglevel=INFO \
239-
-Djct.config="${PWD}/doc/config-sample-helloworld-file.yaml" \
257+
-Djct.config="${PWD}/doc/config-sample-application-file.yaml" \
240258
-Djct.logDir=/tmp/jct \
241259
-noverify \
242-
-jar "${PWD}/doc/helloworld-loop.jar"
260+
-jar "${PWD}/doc/java-code-tracer-sample-application.jar"
243261
```
244262

263+
> **Note on class patterns:** JCT emits a stack trace only when the *outermost* tracked frame returns. If you include a class whose method runs forever (like `main()` or an endless loop driver), no traces will ever be written. Use a pattern that targets the inner chain classes — see `doc/config-sample-application-file.yaml` for an example using `^de.marcelsauer.sample.Class.*`.
264+
245265
Check agent logs:
246266

247267
```bash
@@ -253,7 +273,6 @@ cat /tmp/jct/jct_agent.log
253273
### Stack Formatter (`tools/format_stack.py`)
254274

255275
Pretty-prints a raw JCT `stack` array into an aligned, human-readable call sequence.
256-
Consecutive calls to the same class are grouped — package names are abbreviated.
257276

258277
Requires Python 3.9+, no dependencies.
259278

@@ -271,12 +290,19 @@ xclip -o | python3 tools/format_stack.py
271290
Example output:
272291

273292
```
274-
# package class method
275-
──────────────────────────────────────────────────────
276-
1 o.b.s.u.ldap LdapConnectionFactory .initialize(LdapConnectionConfigurationDTO)
277-
2 .connect()
278-
3 o.b.s.u.ldap LdapConnectionConfigurationDTO .getLdapServer1()
279-
...
293+
# package class method
294+
─────────────────────────────────────────────────────────────────────────
295+
1 de.marcelsauer.sample ClassA .methodA_1()
296+
2 de.marcelsauer.sample ClassB .methodB_2()
297+
3 .methodB_3()
298+
4 de.marcelsauer.sample ClassC .methodC_4()
299+
5 de.marcelsauer.sample ClassD .methodD_5()
300+
6 de.marcelsauer.sample ClassE .methodE_6()
301+
7 de.marcelsauer.sample ClassF .methodF_7()
302+
8 de.marcelsauer.sample ClassG .methodG_8()
303+
9 de.marcelsauer.sample ClassH .methodH_9()
304+
10 de.marcelsauer.sample ClassI .methodI_10()
305+
11 de.marcelsauer.sample ClassJ .methodJ_11()
280306
```
281307

282308
## ELK Integration Guide
@@ -286,6 +312,19 @@ For local Elasticsearch + Logstash + Kibana setup (Docker), UI access, data view
286312
- [README-ELK.md](README-ELK.md)
287313
- [README-analysis-ELK.md](README-ELK-analysys.md)
288314

315+
## Sample Application Screenshots
316+
317+
### Start with agent
318+
![Kibana Discover](doc/sample_app_start.png)
319+
### JCT logs after start
320+
![Kibana Discover](doc/sample_app_jct_log.png)
321+
### Captured stacks if AsyncFileWritingStackProcessor is configured
322+
![Kibana Discover](doc/sample_app_stacks.png)
323+
### Captured stacks in Kibana 'Discover' View if ELK stack is used
324+
![Kibana Discover](doc/kibana_1.png)
325+
### Captured stacks in Kibana 'Visualization/Lens' View if ELK stack is used
326+
![Kibana Visualization](doc/kibana_2.png)
327+
289328
## Similar Projects
290329

291330
- [Datadog dd-trace-java](https://github.com/DataDog/dd-trace-java/)
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
# some comment
22
classes:
33
included:
4-
- ^.*hell.*
5-
excluded:
6-
- .*HelloWorldLoop.*
4+
- ^de.marcelsauer.sample.Class.*
5+
excluded: []
76
processor:
87
fullQualifiedClass: de.marcelsauer.profiler.processor.file.AsyncFileWritingStackProcessor
98
stackFolderName: /tmp/stacks/
9+
# false = report every captured stack event
10+
# true = report only new stacks in dedup time window (dedupResetIntervalMillis)
1011
enableStackDeduplication: false
12+
# used in dedup mode (enableStackDeduplication: true)
1113
dedupResetIntervalMillis: 300000
14+
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# some comment
22
classes:
33
included:
4-
- ^.*hell.*
5-
excluded:
6-
- .*HelloWorldLoop.*
4+
- ^de.marcelsauer.sample.Class.*
5+
excluded: []
76
processor:
87
fullQualifiedClass: de.marcelsauer.profiler.processor.tcp.AsyncTcpStackProcessor
98
tcpHost: localhost
109
tcpPort: 9999
1110
tcpConnectTimeoutMillis: 1000
1211
tcpReconnectDelayMillis: 1000
13-
# true = report every captured stack event
12+
# false = report every captured stack event
13+
# true = report only new stacks in dedup time window (dedupResetIntervalMillis)
1414
enableStackDeduplication: false
1515
# used in dedup mode (enableStackDeduplication: true)
1616
dedupResetIntervalMillis: 300000
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# some comment
2+
classes:
3+
included:
4+
- ^de.marcelsauer.sample.Class.*
5+
excluded: []
6+
processor:
7+
fullQualifiedClass: de.marcelsauer.profiler.processor.udp.AsyncUdpStackProcessor
8+
udpHost: localhost
9+
udpPort: 9999
10+
# false = report every captured stack event
11+
# true = report only new stacks in dedup time window (dedupResetIntervalMillis)
12+
enableStackDeduplication: false
13+
# used in dedup mode (enableStackDeduplication: true)
14+
dedupResetIntervalMillis: 300000

doc/config-sample-file.yaml

Lines changed: 0 additions & 16 deletions
This file was deleted.

doc/config-sample-helloworld-udp.yaml

Lines changed: 0 additions & 14 deletions
This file was deleted.

doc/helloworld-loop.jar

-4.99 KB
Binary file not shown.

doc/helloworldloop_overview.png

-666 KB
Binary file not shown.
8.49 MB
Binary file not shown.

0 commit comments

Comments
 (0)