{"id":27012001,"url":"https://github.com/0xaa4eb/ulyp","last_synced_at":"2025-04-04T11:39:38.694Z","repository":{"id":40409411,"uuid":"393146539","full_name":"0xaa4eb/ulyp","owner":"0xaa4eb","description":"Recording debugger for Java/Kotlin apps","archived":false,"fork":false,"pushed_at":"2025-02-14T16:58:23.000Z","size":8406,"stargazers_count":23,"open_issues_count":6,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-14T17:38:27.691Z","etag":null,"topics":["agent","byte-buddy","bytecode-instrumentation","bytecode-manipulation","debugger","debugging","flamegraph","java","javafx","reverse-engineering"],"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/0xaa4eb.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}},"created_at":"2021-08-05T19:07:31.000Z","updated_at":"2025-02-14T16:58:12.000Z","dependencies_parsed_at":"2023-10-22T20:24:19.241Z","dependency_job_id":"4c5b379d-ebca-4596-a723-549aefb5c387","html_url":"https://github.com/0xaa4eb/ulyp","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xaa4eb%2Fulyp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xaa4eb%2Fulyp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xaa4eb%2Fulyp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xaa4eb%2Fulyp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0xaa4eb","download_url":"https://codeload.github.com/0xaa4eb/ulyp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247174051,"owners_count":20896071,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["agent","byte-buddy","bytecode-instrumentation","bytecode-manipulation","debugger","debugging","flamegraph","java","javafx","reverse-engineering"],"created_at":"2025-04-04T11:39:38.154Z","updated_at":"2025-04-04T11:39:38.689Z","avatar_url":"https://github.com/0xaa4eb.png","language":"Java","readme":"[![Price](https://img.shields.io/badge/price-FREE-0098f7.svg)](https://github.com/0xaa4eb/ulyp/blob/master/LICENSE)\n[![Build Status](https://circleci.com/gh/0xaa4eb/ulyp/tree/master.svg?style=svg)](https://circleci.com/gh/0xaa4eb/ulyp/tree/master)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=0xaa4eb_ulyp\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=0xaa4eb_ulyp)\n[![Maintainability](https://api.codeclimate.com/v1/badges/e76192efb9583aca1170/maintainability)](https://codeclimate.com/github/0xaa4eb/ulyp/maintainability)\n![lines of code](https://raw.githubusercontent.com/0xaa4eb/ulyp/project-badges/loc-badge.svg)\n\n## TL;DR\n\nTurn your software inside out. The tool records everything you app does, and you then can analyze the execution flow.\nBytecode instrumentation is handled by [byte-buddy](https://github.com/raphw/byte-buddy), UI is built on JavaFX.\n\nHere is a basic example. We have a transactional method service and Hibernate is used as a JPA provider. \n\n    ```\n    @Service\n    @Transactional\n    public class PersonStoreService {\n        @Autowired\n        private PersonRepository repository;\n    \n        public void save(Person person) {\n            repository.save(person);\n        }\n    }\n    ```\n\nCalling this method with ulyp agent enabled is able to provide a full call tree. No code change is required.\n\n![Spring/Hibernate call recorded](https://github.com/0xaa4eb/ulyp/blob/master/images/hibernate.png)\n\n## Blog posts\n\nThe underlying rationale for the development, technical design, as well as some use cases are outlined in the following blog posts:\n* [Ulyp: Recording Java code execution for faster debugging (ENG)](https://dzone.com/articles/ulyp-recording-java-execution-flow-for-faster-debugging)\n* [Reverse engineer Spring Web in 5 minutes using a recording debugger (ENG)](https://0xaa4eb.github.io/2024/12/14/reverse-engineer-spring-boot.html)\n\n## How to use\n\nUsage is relatively simple.\n\n* First, download or build the agent\n* Second, use VM properties in order to enable the recording. Here is the minimum set of options one will need for recording.\n    \n    \n    ```\n    -javaagent:/path/to/ulyp-agent-1.0.0.jar\n    -Dulyp.methods=**.HibernateShowcase.*\n    -Dulyp.file=/tmp/recording.dat\n    ```\n\nRecording starts when any method of a class which has class name `HibernateShowcase` is called. The data is written to the \nspecified file which can later be opened in the UI.\n\nExamples of method matchers are:\n\u003ctable\u003e\n\u003ctr\u003e\n\t\t\u003cth\u003eMatcher\u003c/th\u003e\n\t\t\u003cth\u003eExplanation\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eorg.springframework.**.Service.*\u003c/td\u003e\u003ctd\u003eRecord any method of class Service in package org.springframework (or nested) package\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e**.Runnable.run\u003c/td\u003e\u003ctd\u003eRecord all Runnable instances\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e*.*\u003c/td\u003e\u003ctd\u003eRecord all calls (Experimental)\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n## Options\n\nThe agent is controlled via JVM system properties.\n\n| Property                          | Description                                                                                                                                                                                                                                       | Example                                                   | Default      |\n|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------|--------------|\n| ulyp.file                         | A path to a file where all recording data should be written                                                                                                                                                                                       | `-Dulyp.file=/tmp/test.dat`                               | -            |\n| ulyp.methods                      | A list of method matchers where recording should start                                                                                                                                                                                            | `-Dulyp.methods=**.Runnable.run`                          | Main method  |\n| ulyp.start                        | Controls when recording can start. `default` is start recording any time when some of `ulyp.method` is called.\u003cbr/\u003e Another option is `delay:X` where X is the number of seconds to wait from the app launch, `api` - remote enable/disable (WIP) | `-Dulyp.start=delay:120`                                  | `default`    |\n| ulyp.packages                     | A list of packages to instrument                                                                                                                                                                                                                  | `-Dulyp.packages=org.springframework,io.grpc`             | All packages |\n| ulyp.record-timestamps            | Record duration of calls                                                                                                                                                                                                                          | `-Dulyp.record-timestamps`                                | Disabled     |\n| ulyp.exclude-packages             | A list of packages to exclude from instrumentation                                                                                                                                                                                                | `-Dulyp.exclude-packages=org.springframework`             | -            |\n| ulyp.exclude-types                | A list of type matchers to exclude from instrumentation                                                                                                                                                                                           | `-Dulyp.exclude-types=org.springframework.**.Interceptor` | -            |\n| ulyp.record-constructors          | Enables instrumentation (and possibly recording) of constructors                                                                                                                                                                                  | `-Dulyp.record-constructors`                              | Disabled     |\n| ulyp.record-collections           | Records values (some number of items) of collections. Possible values are: `NONE`, `JDK` (only JDK collections), `ALL` (dangerous)                                                                                                                | `-Dulyp.record-collections=JDK`                           | `NONE`       |\n| ulyp.record-collections.max-items | Max items of collections to record                                                                                                                                                                                                                | `-Dulyp.record-collections.max-items=5`                   | 3            |\n| ulyp.record-arrays                | Records values (some number of items) of arrays                                                                                                                                                                                                   | `-Dulyp.record-arrays`                                    | Disabled     |\n| ulyp.record-arrays.max-items      | Max items of arrays to record                                                                                                                                                                                                                     | `-Dulyp.record-arrays.max-items=10`                       | 3            |\n| ulyp.record-lambdas               | Enabled instrumentation (and possibly recording) of lambdas (experimental)                                                                                                                                                                        | `-Dulyp.record-lambdas`                                   | Disabled     |\n| ulyp.record-static-blocks         | Enabled instrumentation (and possibly recording) of static blocks (experimental)                                                                                                                                                                  | `-Dulyp.record-static-blocks`                             | Disabled     |\n| ulyp.print-types                  | A list of type matchers to print with toString() while recording their values                                                                                                                                                                     | `-Dulyp.print-types=com.enterprise.**.SomeEntity`         | -            |\n| ulyp.recorder.max-string-length   | A maximum number of characters for String recording                                                                                                                                                                                               | `-Dulyp.recorder.max-string-length=400`                   | 200          |\n\n## UI\n\n### Controls\n\n\u003ctable border=\"1\"\u003e\n\u003ctr\u003e\n\t\t\u003cth\u003eHotkey\u003c/th\u003e\n\t\t\u003cth\u003eAction\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eHold Shift\u003c/td\u003e\u003ctd\u003eShow full type names\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eHold X\u003c/td\u003e\u003ctd\u003eShow method call duration (if enabled with -Dulyp.record-timestamps while recording)\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003ePress =\u003c/td\u003e\u003ctd\u003eIncrease font size\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003ePress -\u003c/td\u003e\u003ctd\u003eDecrease font size\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n## Build from source\n\nBuild agent (no tests):\n`./gradlew :ulyp-agent:shadowJar`\n\nBuild UI jar file (Java 11+ (preferred) or Java 8 Oracle with Java FX bundled) :\n`./gradlew :ulyp-ui:fatJar`\n\nUI jar file for a particular platform can be built as follows:\n`./gradlew :ulyp-ui:fatJar -Pplatform=mac`\n\nAvailable platforms for the build are: `linux`, `linux-aarch64`, `win`, `mac`, `mac-aarch64`","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xaa4eb%2Fulyp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0xaa4eb%2Fulyp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xaa4eb%2Fulyp/lists"}