{"id":28446604,"url":"https://github.com/parttimenerd/meta-agent","last_synced_at":"2025-06-30T01:32:09.901Z","repository":{"id":225876845,"uuid":"767061915","full_name":"parttimenerd/meta-agent","owner":"parttimenerd","description":"Instrument instrumenting agents to see how they transform classes","archived":false,"fork":false,"pushed_at":"2025-03-26T11:26:45.000Z","size":538,"stargazers_count":21,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-06T11:07:33.585Z","etag":null,"topics":["instrumentation","java","java-agent"],"latest_commit_sha":null,"homepage":"https://mostlynerdless.de/blog/2024/05/10/who-instruments-the-instrumenters/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/parttimenerd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2024-03-04T16:28:43.000Z","updated_at":"2025-04-09T10:59:42.000Z","dependencies_parsed_at":"2025-03-26T10:23:22.881Z","dependency_job_id":"5827bde9-e795-47a2-ade0-bdcd6f2cae10","html_url":"https://github.com/parttimenerd/meta-agent","commit_stats":null,"previous_names":["parttimenerd/meta-agent"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/parttimenerd/meta-agent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parttimenerd%2Fmeta-agent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parttimenerd%2Fmeta-agent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parttimenerd%2Fmeta-agent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parttimenerd%2Fmeta-agent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/parttimenerd","download_url":"https://codeload.github.com/parttimenerd/meta-agent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parttimenerd%2Fmeta-agent/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262693232,"owners_count":23349697,"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":["instrumentation","java","java-agent"],"created_at":"2025-06-06T11:07:33.129Z","updated_at":"2025-06-30T01:32:09.891Z","avatar_url":"https://github.com/parttimenerd.png","language":"Java","readme":"Meta-Agent\n==========\n\nWho instruments the instrumenter? This project is a Java agent that instruments Java agents,\nor specifically, it instruments the ClassFileTransformers of other agents to observe how they transform\nthe bytecode of classes.\n\nThis is especially useful to check what libraries like [Mockito](https://site.mockito.org/) do to your classes at runtime.\n\nTo run it, build the project with `mvn package -DskipTests` and run your Java program with the agent:\n\n```shell\njava -javaagent:target/meta-agent.jar -jar your-program.jar\n\n# or run a Mockito based sample test\nmvn package -DskipTests\nmvn test -DargLine=\"-javaagent:target/meta-agent.jar=server\"\n\n# or run with an instrumentation handler\nmvn -DargLine=\"-javaagent:target/meta-agent.jar=server,cb=me.bechberger.meta.LoggingInstrumentationHandler\" test\n```\n\nThe executed [MockitoTest](src/test/java/me/bechberger/meta/MockitoTest.java) looks as follows:\n\n```java\n@ExtendWith(MockitoExtension.class)\npublic class MockitoTest {\n\n  @Mock\n  List\u003cString\u003e mockedList;\n\n  @Test\n  public void whenNotUseMockAnnotation_thenCorrect() throws InterruptedException {\n    mockedList.add(\"one\");\n    Mockito.verify(mockedList).add(\"one\");\n    assertEquals(0, mockedList.size());\n\n    Mockito.when(mockedList.size()).thenReturn(100);\n    assertEquals(100, mockedList.size());\n\n    Thread.sleep(10000000L);\n  }\n}\n```\n\nOpening [localhost](http://localhost:7071) will show you a list of available commands, most importantly\n- [/help](http://localhost:7071) to show the help, available comands and decompilation and output options\n- [/instrumentators](http://localhost:7071/instrumentators) to list all instrumentators (ClassFileTransformers) that have been used\n- [/full-diff/instrumentator?pattern=.*](http://localhost:7071/full-diff/instrumentator?pattern=.*)\n  to show the full diff for all instrumentators\n- [/classes](http://localhost:7071/classes) to list all classes that have been transformed\n- [/full-diff/class?pattern=.*](http://localhost:7071/full-diff/class?pattern=.*)\n  to show the full diff for all classes and all instrumentators\n- [/all/decompile?pattern=\u003cpattern\u003e](http://localhost:7071/all/decompile?pattern=\u003cpattern\u003e)\n  to decompile the classes matching the pattern\n\nIn our example, we can see via [/instrumentators](http://localhost:7071/instrumentators) that Mockito uses\nthe `org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker` to transform classes.\nUsing [/full-diff/instrumentator/.*](http://localhost:7071/full-diff/instrumentator/.*), we can see the diff of all\ntransformations that this instrumentator has done:\n\n![Screenshot of http://localhost:7071/full-diff/instrumentator/.*](img/instrumentators.png)\n\nYet we also see via [/classes](http://localhost:7071/classes) that Mockito only transforms the `java.util.List` \ninterface and all its parents:\n\n![Screenshot of http://localhost:7071/classes](img/classes.png)\n\nThe [LoggingInstrumentationHandler](src/test/java/me/bechberger/meta/LoggingInstrumentationHandler.java)\nwhich is passed to the agent via the `cb` argument, logs all added and existing transformers.\n\nIt is implemented as follows:\n\n```java\npublic class LoggingInstrumentationHandler implements InstrumentationCallback {\n  @Override\n  public CallbackAction onAddTransformer(ClassFileTransformer transformer) {\n    System.err.println(\"New transformer \" + transformer.getClass().getName());\n    return CallbackAction.ALLOW;\n  }\n\n  @Override\n  public void onExistingTransformer(ClassFileTransformer transformer) {\n    System.err.println(\"Existing transformer \" + transformer.getClass().getName());\n  }\n\n  @Override\n  public CallbackAction onInstrumentation(ClassFileTransformer transformer, ClassArtifact before, ClassArtifact after) {\n    return CallbackAction.ALLOW;\n  }\n}\n```\n\nThe meta-agent can also be used via a [maven plugin](maven-plugin/README.md),\nsee the [sample project](maven-plugin-sample/README.md) for an example usage.\n\nHow this works\n--------------\n\nThe agent wraps all ClassFileTransformers with a custom transformer that records the diff of the bytecode.\nIt then uses [vineflower](http://vineflower.org/) to decompile the bytecode and \n[diff](https://www.gnu.org/software/diffutils/)\nto compute the diff between the original and the transformed bytecode.\n\nThe front-end is implemented using the built-in HttpServer as a simple web server started by the agent.\n\nThis is essentially a more capable version of the [classviewer-agent](https://github.com/parttimenerd/classviewer-agent).-\n\nContributions\n-------------\nIf you have sample programs where this tool helped to see something interesting, please share.\nContributions, issues and PRs are welcome.\n\nDeploy\n------\n```shell\nmvn package -DskipTests=true deploy -U\nmvn package -f pom_runtime.xml -DskipTests=true deploy -U\n```\n\nLicense\n-------\nMIT, Copyright 2024 SAP SE or an SAP affiliate company, Johannes Bechberger\nand meta-agent agent contributors\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparttimenerd%2Fmeta-agent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparttimenerd%2Fmeta-agent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparttimenerd%2Fmeta-agent/lists"}