Open-source project
LinShunKang/MyPerf4J avatar
LinShunKang/MyPerf4J

MyPerf4J: A JavaAgent Method Profiler That Writes Plain Text Logs

High performance Java APM. Powered by ASM. Try it. Test it. If you feel its better, use it.

3,565 stars554 forksJavaBSD-3-Clause

At a glance

What is it?
MyPerf4J instruments Java methods through a javaagent and reports per-method RPS, latency percentiles and JVM counters. It is a good fit when you want method-level numbers without changing application code, and a poor fit when you need distributed tracing or a hosted backend.
Who is it for?
Adopt MyPerf4J if you run a JVM service and want per-method RPS and TP99 numbers without editing code, and if shipping metrics to InfluxDB or reading method_metrics.log is acceptable. Do not adopt it if you need cross-service traces or a managed backend, since the project is a single-process agent with no distributed context propagation in the supplied material.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 47 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap MyPerf4J fills: method-level numbers without code changes

Most JVM monitoring stops at the process boundary. You get heap usage, GC pause times and thread counts, and none of that tells you which of your own methods is slow. Finding that out usually means either adding timing code around suspects or attaching a sampling profiler that shows a flame graph but no stable per-method request rate. MyPerf4J targets the middle ground. The README describes it as a performance monitoring and statistics tool designed for high-concurrency, low-latency applications, and the stated value is locating performance bottlenecks and fault causes quickly. The audience is Java teams running services where a specific method's tail latency matters. The README's own example output is telling: it lists DemoServiceImpl.getId2(long) at 6524 RPS with a TP99 of 1 ms, alongside a DynamicProxy DAO method at 2176 RPS. That is the shape of answer the tool produces. It is a per-method table, not a trace. If your question is "which method in this service is responsible for the p99," the output answers it directly. If your question is "which of my twelve services contributed to this slow user request," it does not.

How the ASM agent collects and reports method statistics

The mechanism is bytecode instrumentation at class load time. The README states the tool uses a JavaAgent approach and is non-intrusive to the application, requiring no source changes, and the repository topics list both java-agent and bytecode. The distribution artifact is named MyPerf4J-ASM.jar, which matches ASM as the bytecode library. So the data flow is: the JVM loads a class, the agent transforms matching methods to record start and end timestamps, and an internal recorder aggregates those samples into per-method counters. The README claims a single thread can record 16 million response times per second at 63 nanoseconds per record, and describes the storage approach as memory reuse, with very few temporary objects created over the lifecycle so application GC is not disturbed. Those are the project's own figures from its wiki, not independent measurements. Aggregation is described as second-level, with a minimum statistics granularity of 1 second, and the README stresses that it is full statistics with no record dropped. That last point is the design bet: instead of sampling, MyPerf4J counts every invocation and computes percentiles from the full set. It is why the recorder has to be cheap, and why the memory-reuse claim matters. The output is a fixed-width text table per interval, containing RPS, Count, Avg, Min, Max, StdDev and the TP50 through TP100 ladder, plus a Type and Level column that comes from your filter configuration.

Starting the agent: two JVM flags and one properties file

The README's quick start is short. Download and unzip MyPerf4J-ASM.zip, read the bundled README, then edit three settings in MyPerf4J.properties: app_name, metrics.log.xxx and filter.packages.include. Then add two JVM arguments. The first is -javaagent:/path/to/MyPerf4J-ASM.jar and the second is -DMyPerf4JPropFile=/path/to/MyPerf4J.properties. The README gives the combined form as java -javaagent:/path/to/MyPerf4J-ASM.jar -DMyPerf4JPropFile=/path/to/MyPerf4J.properties -jar yourApp.jar. There is a version caveat that will bite people on modern runtimes: if you use JDK 9 or above, the README says you must additionally add --add-opens java.base/java.lang=ALL-UNNAMED. Without it the agent cannot reach into java.lang, which is where the instrumentation hooks live. Note the ordering requirement implied by the example: the -javaagent flag precedes -jar. On startup the metrics are written to the log path you configured, shown in the README as /path/to/log/method_metrics.log. Uninstalling is the reverse: remove the two JVM arguments and restart. There is no runtime detach command documented, so removal is a restart. Building from source is also documented: git clone the repository, then mvn clean package, producing MyPerf4J-ASM-${MyPerf4J-version}.jar under MyPerf4J-ASM/target/.

What the metrics actually cover, and where the coverage stops

Two metric families are documented. Method Metrics cover RPS, Count, Avg, Min, Max, StdDev and the percentile ladder TP50, TP90, TP95, TP99, TP999, TP9999 and TP100. JVM Metrics cover Thread, Memory, ByteBuff, GC, Class, Compilation and FileDescriptor. Both are described as collected and displayed in real time. The README points at two Grafana dashboards, 7766 for method metrics and 8787 for JVM metrics, and at a wiki page for installing and configuring InfluxDB as the backend. So there are two consumption paths: tail the log file, or ship to InfluxDB and view in Grafana. The log path is the one that works with zero extra infrastructure. The Grafana path requires you to stand up InfluxDB yourself. What is absent is as informative as what is present. There is no mention of trace IDs, span propagation, context across process boundaries, or a query language for slicing metrics by request attribute. The Type and Level columns in the sample output (General, Service, DynamicProxy, DAO) come from configuration, not from runtime discovery of a call graph. MyPerf4J tells you a method is slow. It does not tell you which upstream call caused that method to be invoked.

The instrumentation trade-off: what filter.packages.include decides

The single most consequential config key is filter.packages.include. The README lists it among the three settings you must edit before first run, which signals that the default is not usable for a real application. Everything the agent transforms costs something at class load and on every invocation, and the recorder's per-record cost is the number the project emphasizes. Broadening the include pattern to cover a large dependency tree multiplies both the transformation work at startup and the number of recorded methods in every interval. The sample output shows six methods across a service and a DAO, which is a narrow, deliberate scope. This is the failure mode to watch for: an include pattern that is too wide produces a metrics table dominated by framework internals you did not want to measure, and an include pattern that is too narrow silently yields nothing, because the agent has no way to tell you it matched zero classes. The README's troubleshooting guidance is process-oriented rather than diagnostic: it asks that you read the question template, quick start, Chinese documentation and FAQ before filing an issue. That suggests configuration problems are a common support load. Plan to verify the include pattern against a staging run before trusting a production deployment, and check that method_metrics.log actually contains rows.

MyPerf4J against a sampling profiler like async-profiler

The closest comparison in kind is async-profiler, a JVM sampling profiler. The difference in approach is fundamental. A sampling profiler interrupts the JVM at intervals and records stack traces, so it discovers the call graph without configuration and shows you where time is spent across the whole process, including code you did not know to look at. MyPerf4J instruments specific methods and counts every call, so it produces exact counts and stable percentiles for the methods you named, but it cannot report on a method you did not include. Sampling has statistical error at low call counts and can miss rare, very slow invocations; MyPerf4J's full-count approach is designed to avoid exactly that, which is why the README stresses no records dropped. The practical split: use a sampler when you do not know where the problem is and need to explore. Use MyPerf4J when you know which methods matter and want continuous, low-overhead numbers for them over time, particularly tail percentiles that a sampler would estimate. They are complementary, not substitutes. If you already run async-profiler for incident investigation, MyPerf4J covers the standing-dashboard role.

Maintenance, licensing and the cost of staying current

MyPerf4J is licensed BSD-3-Clause, a permissive licence that allows commercial use and modification with the copyright notice and disclaimer retained. That is the standard permissive arrangement, and it means the agent can be bundled into a proprietary deployment. This is not legal advice; read the LICENSE file in the repository for the binding terms. On maintenance, the release history supplied shows 3.6.0 on 2025-11-16, 3.5.0 on 2025-10-18 and 3.4.0 on 2024-09-08. The gap between 3.4.0 and 3.5.0 is roughly thirteen months, followed by two releases about a month apart. The most recent push to the develop branch is dated 2026-07-31. The default branch is develop, not main or master, which means the branch you would clone by default is the integration branch rather than a release branch. For upgrade cost, the concrete exposure is the javaagent contract with the JDK. The --add-opens requirement for JDK 9 and above is a reminder that this class of tool is coupled to JVM internals, and a major JDK upgrade is the moment to re-verify attachment rather than assume it. Budget a staging run per JDK major version, and pin the MyPerf4J-ASM.jar version in your deployment rather than tracking develop.

Editorial conclusion

Adopt MyPerf4J if you run a JVM service and want per-method RPS and TP99 numbers without editing code, and if shipping metrics to InfluxDB or reading method_metrics.log is acceptable. Do not adopt it if you need cross-service traces or a managed backend, since the project is a single-process agent with no distributed context propagation in the supplied material. Before rollout, verify three things on the exact JDK you deploy: that the agent attaches, that --add-opens java.base/java.lang=ALL-UNNAMED is present on JDK 9 and later, and that filter.packages.include matches your own package names rather than the demo ones in the template.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. LinShunKang/MyPerf4J on GitHub
  4. README
  5. Releases
Community notes

Community notes