{"id":37019207,"url":"https://github.com/thanglequoc/timer-ninja","last_synced_at":"2026-02-11T06:09:23.973Z","repository":{"id":274311138,"uuid":"615894475","full_name":"thanglequoc/timer-ninja","owner":"thanglequoc","description":"A handy Java utility for measuring execution time easily with annotation-based tracking, multiple time units, and stacktrace tree visualization.","archived":false,"fork":false,"pushed_at":"2025-12-06T18:04:10.000Z","size":290,"stargazers_count":4,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-10T03:22:20.096Z","etag":null,"topics":["aspectj","benchmark","benchmark-framework","execution-time","java","measuring","performance"],"latest_commit_sha":null,"homepage":"https://github.com/thanglequoc/timer-ninja","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/thanglequoc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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-03-19T01:32:01.000Z","updated_at":"2025-12-06T18:04:15.000Z","dependencies_parsed_at":"2025-04-06T14:28:20.818Z","dependency_job_id":"5f501b99-3ea5-41b4-ab54-7732d26e6697","html_url":"https://github.com/thanglequoc/timer-ninja","commit_stats":null,"previous_names":["thanglequoc/timer-ninja"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thanglequoc/timer-ninja","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanglequoc%2Ftimer-ninja","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanglequoc%2Ftimer-ninja/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanglequoc%2Ftimer-ninja/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanglequoc%2Ftimer-ninja/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thanglequoc","download_url":"https://codeload.github.com/thanglequoc/timer-ninja/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanglequoc%2Ftimer-ninja/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408711,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["aspectj","benchmark","benchmark-framework","execution-time","java","measuring","performance"],"created_at":"2026-01-14T02:04:01.399Z","updated_at":"2026-02-11T06:09:23.966Z","avatar_url":"https://github.com/thanglequoc.png","language":"Java","readme":"# Timer Ninja\n\n\u003cp align=\"center\"\u003e\u003cimg alt=\"timer-ninja-mascot\" src=\"https://i.postimg.cc/02xG4vmH/timer-ninja-mascot.png\" width=\"120\" /\u003e\u003c/p\u003e\n\u003cp style=\"font-size: 25px\" align=\"center\"\u003e\u003cb\u003eA sneaky library for Java Method Timing\u003c/b\u003e\u003c/p\u003e\n\n[![Sonartype](https://maven-badges.sml.io/sonatype-central/io.github.thanglequoc/timer-ninja/badge.svg)](https://central.sonatype.com/artifact/io.github.thanglequoc/timer-ninja)\n\u003cbr/\u003e\n\n\nTimer Ninja is a lightweight Java library that makes measuring method execution time effortless. Simply annotate your methods, and it automatically tracks execution duration, preserves the full call hierarchy, and displays it in a clear, visual call tree. With support for multiple time units and optional argument logging, Timer Ninja provides instant insights into your code’s performance.  \nBuilt on Aspect-Oriented Programming (AOP) with AspectJ, it integrates seamlessly into your application with minimal setup.\n\n## Problem Space\nMeasuring code execution time is a fundamental practice in software development. Whether optimizing performance, debugging slow processes, or ensuring system efficiency, developers frequently need insights into how long the methods take to execute.\n\n### Traditional approach\nA common way to measure method execution time is by capturing timestamps before and after the method runs and calculating the difference.  \nThis approach is straightforward and fast but quickly becomes cumbersome. You must manually declare two timestamp points around every method that needs evaluation, leading to excessive boilerplate code and reduced maintainability. As the codebase grows, keeping track of these measurements becomes inefficient and error-prone.\n\n```java\nlong beforeExecution = System.currentTimeMillis();\ndoSomethingInteresting();\nlong afterExecution = System.currentTimeMillis();\nSystem.out.println(\"Execution time (ms): \" + (afterExecution - beforeExecution));\n```\n\n### Timer Ninja to the rescue\n[![Gemini-Generated-Image-1g42wl1g42wl1g42.png](https://i.postimg.cc/LX8KDwD1/Gemini-Generated-Image-1g42wl1g42wl1g42.png)](https://postimg.cc/4KqSN8rf)\nTimer Ninja simplifies measuring method execution time by leveraging Aspect-Oriented Programming (AOP) with AspectJ under the hood. Instead of manually capturing timestamps, you simply annotate any method you want to track with the `@TimerNinjaTracker` annotation\n\n```java\n@TimerNinjaTracker\npublic String doSomethingInteresting() {\n}\n```\n\nTimer Ninja automatically keeps track of the method execution context. If a tracked method calls another tracked method, Timer Ninja preserves the execution hierarchy, making it easy to see the call relationships and timing details in a single trace output.\n\n**Example Timer Ninja trace output**  \n```shell\nTimer Ninja trace context id: 851ac23b-2669-4883-8c97-032b8fd2d45c\nTrace timestamp: 2023-04-03T07:16:48.491Z\n{===== Start of trace context id: 851ac23b-2669-4883-8c97-032b8fd2d45c =====}\npublic void requestMoneyTransfer(int sourceUserId, int targetUserId, int amount) - Args: [sourceUserId={1}, targetUserId={2}, amount={500}] - 1747 ms\n   |-- public User findUser(int userId) - 105000 µs\n   |-- public void processPayment(User user, int amount) - Args: [user={name='John Doe', email=johndoe@gmail.com}, amount={500}] - 770 ms\n     |-- public boolean changeAmount(User user, int amount) - 306 ms\n     |-- public void notify(User user) - 258 ms\n       |-- private void notifyViaSMS(User user) - 53 ms\n       |-- private void notifyViaEmail(User user) - 205 ms\n{====== End of trace context id: 851ac23b-2669-4883-8c97-032b8fd2d45c ======}\n```\n\n## Installation\nTo use Timer Ninja, you need to do two things: add the `timer-ninja` dependency and apply an AspectJ plugin so the library’s aspects can be compiled.\n\n### Add the Timer Ninja dependency\n**Gradle**  \n```groovy\nimplementation group: 'io.github.thanglequoc', name: 'timer-ninja', version: '1.3.0'\n```\n\n**Maven**  \n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.thanglequoc\u003c/groupId\u003e\n    \u003cartifactId\u003etimer-ninja\u003c/artifactId\u003e\n    \u003cversion\u003e1.3.0\u003c/version\u003e\n    \u003cscope\u003ecompile\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n### Declare plugin to compile the aspect\n**Gradle**  \nYou can use the [FreeFair AspectJ Gradle plugin](https://github.com/freefair/gradle-plugins)\n\nExample project's `build.gradle`:\n\n```groovy\nplugins {\n    // ...\n    id \"io.freefair.aspectj.post-compile-weaving\" version '9.1.0'\n}\n\ndependencies {\n    // ...\n    // Timer ninja dependency\n    implementation group: 'io.github.thanglequoc', name: 'timer-ninja', version: '1.3.0'\n    aspect 'io.github.thanglequoc:timer-ninja:1.3.0'\n\n    // Enable this if you want to track method in Test classes\n\ttestAspect(\"io.github.thanglequoc:timer-ninja:1.3.0\")\n}\n```\n\n### Maven project\nYou can use the [Forked Mojo's AspectJ Plugin](https://github.com/dev-aspectj/aspectj-maven-plugin)  \nExample project's `pom.xml`\n\n```xml\n\u003cproperties\u003e\n    \u003cjava.version\u003e25\u003c/java.version\u003e\n    \u003caspectj.version\u003e1.9.25\u003c/aspectj.version\u003e\n\u003c/properties\u003e\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.aspectj\u003c/groupId\u003e\n        \u003cartifactId\u003easpectjrt\u003c/artifactId\u003e\n        \u003cversion\u003e${aspectj.version}\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eio.github.thanglequoc\u003c/groupId\u003e\n        \u003cartifactId\u003etimer-ninja\u003c/artifactId\u003e\n        \u003cversion\u003e1.3.0\u003c/version\u003e\n        \u003cscope\u003ecompile\u003c/scope\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n\n\u003cbuild\u003e\n\u003cplugins\u003e\n    \u003c!-- Forked Codehaus Maven plugin (forked and up-to-date)\n      https://github.com/dev-aspectj/aspectj-maven-plugin\n     --\u003e\n    \u003cplugin\u003e\n        \u003cgroupId\u003edev.aspectj\u003c/groupId\u003e\n        \u003cartifactId\u003easpectj-maven-plugin\u003c/artifactId\u003e\n        \u003cversion\u003e1.14.1\u003c/version\u003e\n        \u003cdependencies\u003e\n            \u003cdependency\u003e\n                \u003cgroupId\u003eorg.aspectj\u003c/groupId\u003e\n                \u003cartifactId\u003easpectjtools\u003c/artifactId\u003e\n                \u003c!-- AspectJ compiler version, in sync with runtime --\u003e\n                \u003cversion\u003e${aspectj.version}\u003c/version\u003e\n            \u003c/dependency\u003e\n        \u003c/dependencies\u003e\n        \u003cconfiguration\u003e\n            \u003ccomplianceLevel\u003e${java.version}\u003c/complianceLevel\u003e\n            \u003caspectLibraries\u003e\n                \u003caspectLibrary\u003e\n                    \u003cgroupId\u003eio.github.thanglequoc\u003c/groupId\u003e\n                    \u003cartifactId\u003etimer-ninja\u003c/artifactId\u003e\n                \u003c/aspectLibrary\u003e\n            \u003c/aspectLibraries\u003e\n        \u003c/configuration\u003e\n        \u003cexecutions\u003e\n            \u003cexecution\u003e\n                \u003cgoals\u003e\n                    \u003cgoal\u003ecompile\u003c/goal\u003e\n                    \u003c!-- Enable the test-compile goal if you want to use Tracker in the Java Test --\u003e\n                    \u003cgoal\u003etest-compile\u003c/goal\u003e\n                \u003c/goals\u003e\n            \u003c/execution\u003e\n        \u003c/executions\u003e\n    \u003c/plugin\u003e\n\u003c/plugins\u003e\n\u003c/build\u003e\n```\n\n### Getting the time trace output\nThe library is logging the time trace with [SLF4J Logger](https://www.slf4j.org/). So if you've already had an Slf4j provider (e.g: Logback, Log4J) in your project, then\nyou should be able to see the time trace output after the method executed.  \nOtherwise, you will need to add a log provider into the project, my personal recommendation is [Logback](https://logback.qos.ch/) for \nrobustness and simplicity. You can refer to this [Logback tutorial from Baeldung](https://www.baeldung.com/logback)\n\nSee this [Slf4j manual](https://slf4j.org/manual.html) for how to configure your logging framework with Slf4j\n\n**Note**: Spring Boot project uses Logback as it default log provider, so you don't need to do anything here.\n\nThe logger class is `io.github.thanglequoc.timerninja.TimerNinjaUtil`, with the default log level is `INFO`.\n\nIf logging framework is not your preference, and you just want to have a quick result. Then you can choose to fall back\nto the good old `System.out.println` output by executing this code **once** (since this is a singleton configuration instance). This setting will instruct\nTimer Ninja to also print the time trace output to `System.out`\n\n```java\nTimerNinjaConfiguration.getInstance().toggleSystemOutLog(true);\n```\n\n## `@TimerNinjaTracker` usage\nNow that you're all set and ready to go. Just simply place the tracker by annotating `@TimerNinjaTracker` on any method/constructor\nthat you want to measure\n\n```java\n@TimerNinjaTracker\npublic void processPayment(User user, int amount) {\n    // Method logic\n}\n```\n\n### Tracker Options\n\nThe following options is available on the `@TimerNinjaTracker` annotation\n\n```java\n@TimerNinjaTracker(enabled = true, timeUnit = ChronoUnit.MILLIS, includeArgs = true, threshold = 2000)\npublic void processPayment(User user, int amount) {\n    // The method implementation\n}\n```\n#### Toggle tracking\nDetermine if this tracker should be active. Set to `false` will disable this tracker from the overall tracking trace result. Default: `true`\n\u003e @TimerNinjaTracker(enabled = false)\n\n#### Timing Unit\nThe tracker allows specifying the time unit for measurement. Supported units include:  \n•   Seconds (`ChronoUnit.SECONDS`)  \n•   Milliseconds (`ChronoUnit.MILLIS`)  \n•   Microseconds (`ChronoUnit.MICROS`)  \nBy default, the time unit of the tracker is **millisecond (ms)**.\n```java\nimport java.time.temporal.ChronoUnit;\n\n@TimerNinjaTracker(timeUnit = ChronoUnit.MICROS)\npublic void processPayment(User user, int amount) {\n\n}\n```\n\n#### Include argument information in the log trace context\nThe tracker can optionally log the arguments passed to the tracked method. This is particularly useful for gaining insights into the input data when analyzing performance. Default: `false`\n\n**Note**: Ensure that the `toString()` method of the argument objects is properly implemented to display meaningful details in the logs.\n\n```java\n@TimerNinjaTracker(includeArgs = true)\npublic void processPayment(User user, int amount) {\n    // Method logic\n}\n```\n\n**Sample output:**\n\u003e public void processPayment(User user, int amount) - Args: [user={name='John Doe', email=johndoe@gmail.com}, amount={500}] - 770 ms\n\n#### Threshold setting\nTimer Ninja allows you to suppress “acceptable speed” methods by defining a time threshold.\nIf the method’s execution time is below the threshold, it will be skipped in the final trace.  \nThe threshold value uses the same timeUnit defined on the tracker (default is **millisecond (ms)**)  \n\nWhen combined with `includeArgs` opt, threshold filtering becomes even more powerful:\nyou see only the slow methods along with the exact arguments that caused the delay—ideal for debugging performance issues tied to specific inputs.\n```java\n@TimerNinjaTracker(includeArgs = true, threshold = 200)\npublic void requestMoneyTransfer(int sourceUserId, int targetUserId, int amount) {\n    // Method logic\n}\n```\n\n**Sample output:**\n\u003e public void requestMoneyTransfer(int sourceUserId, int targetUserId, int amount) - Args: [sourceUserId={1}, targetUserId={2}, amount={3000}] - 1037 ms ¤ [Threshold Exceed !!: 200 ms]\n\n\n\n## Block Tracking with `TimerNinjaBlock`\n\nTimerNinjaBlock allows you to measure arbitrary code blocks within a method without extracting separate methods. This is perfect for tracking specific phases or operations inside a method.\n\n### Basic Usage\n\n```java\npublic void processOrder(Order order) {\n    // Regular code not tracked\n    \n    TimerNinjaBlock.measure(\"database query\", () -\u003e {\n        database.query(\"SELECT * FROM orders WHERE id = \" + order.getId());\n    });\n    \n    // More code not tracked\n}\n```\n\nUse TimerNinjaBlock for granular tracking within a method without creating separate tracked methods.\n\nFor more advanced block tracking usage, see the [User Guide Wiki](https://github.com/thanglequoc/timer-ninja/wiki/User-Guide#block-tracking).\n\n\n\n## Reading the time trace output\nOnce the method is executed, you should be able to find the result similar to this one in the output/log\n\n```log\n2023-04-06T21:27:50.878+07:00  INFO 14796 --- [nio-8080-exec-1] c.g.t.timerninja.TimerNinjaUtil          : Timer Ninja trace context id: c9ffeb39-3457-48d4-9b73-9ffe7d612165\n2023-04-06T21:27:50.878+07:00  INFO 14796 --- [nio-8080-exec-1] c.g.t.timerninja.TimerNinjaUtil          : Trace timestamp: 2023-04-06T14:27:50.322Z\n2023-04-06T21:27:50.878+07:00  INFO 14796 --- [nio-8080-exec-1] c.g.t.timerninja.TimerNinjaUtil          : {===== Start of trace context id: c9ffeb39-3457-48d4-9b73-9ffe7d612165 =====}\n2023-04-06T21:27:50.878+07:00  INFO 14796 --- [nio-8080-exec-1] c.g.t.timerninja.TimerNinjaUtil          : public User getUserById(int userId) - 554 ms\n2023-04-06T21:27:50.878+07:00  INFO 14796 --- [nio-8080-exec-1] c.g.t.timerninja.TimerNinjaUtil          :   |-- public User findUserById(int userId) - 251 ms\n2023-04-06T21:27:50.878+07:00  INFO 14796 --- [nio-8080-exec-1] c.g.t.timerninja.TimerNinjaUtil          : {====== End of trace context id: c9ffeb39-3457-48d4-9b73-9ffe7d612165 ======}\n```\nIn detail:  \n`Timer Ninja trace context id`: The auto generated uuid of a trace context. A trace context is initiated for the very first method encountered with `@TimerNinjaTracker` annotation.\nAny sequence execution of other annotated tracker methods inside the parent method will also be accounted for in the existing trace context.  \n`Trace timestamp`: The timestamp when the trace context is initiated, in UTC timezone.  \n`Begin-end of trace context`: The detailed execution time of each method. The `|--` sign indicate the call to this method originated from the above parent method, which help to visualize the execution stacktrace.\n\n\n## User Guide\nFor comprehensive documentation, examples, and best practices on using the Timer-Ninja library efficiently, visit the [Wiki page](https://github.com/thanglequoc/timer-ninja/wiki/User-Guide).\n\n## Troubleshooting\nIf you need to troubleshoot, you can toggle the `DEBUG` log level on logger `io.github.thanglequoc.timerninja.TimerNinjaThreadContext`.\n\n## Issue and contribution\nAny contribution is warmly welcome. Please feel free to open an Issue if you have any problem setting up timer-ninja. Or open a Pull Request\nif you have any improvement to this project.\n\n## Example projects\nBelow are some example projects which has Timer Ninja integrated for your setup reference \n\n[Spring Boot - Ninja Coffee Shop - Gradle](https://github.com/thanglequoc/timer-ninja-examples/tree/main/ninja-coffee-shop-gradle)  \n[Spring Boot - Ninja Coffee Shop - Maven](https://github.com/thanglequoc/timer-ninja-examples/tree/main/ninja-coffee-shop-maven)\n\n\n----\n###### 🦥 Project logo generated by [Google Gemini](https://gemini.google.com)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanglequoc%2Ftimer-ninja","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthanglequoc%2Ftimer-ninja","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanglequoc%2Ftimer-ninja/lists"}