{"id":24871209,"url":"https://github.com/PhilKes/slf4j-caller-info-plugins","last_synced_at":"2025-10-15T14:32:01.205Z","repository":{"id":65704129,"uuid":"589520123","full_name":"PhilKes/slf4j-caller-info-plugins","owner":"PhilKes","description":"Maven plugin to inject caller location information into all SLF4J log statements without performance loss","archived":false,"fork":false,"pushed_at":"2025-09-18T05:24:08.000Z","size":1357,"stargazers_count":3,"open_issues_count":13,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-10T14:42:35.130Z","etag":null,"topics":["asm","caller-location","log4j","logback","logger","maven-plugin","performance","slf4j"],"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/PhilKes.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-16T10:09:55.000Z","updated_at":"2025-09-13T18:03:56.000Z","dependencies_parsed_at":"2023-09-29T07:13:31.980Z","dependency_job_id":"389d3646-3c61-49ab-9505-56777a91c3e7","html_url":"https://github.com/PhilKes/slf4j-caller-info-plugins","commit_stats":null,"previous_names":["philkes/slf4j-caller-info-plugins"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/PhilKes/slf4j-caller-info-plugins","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhilKes%2Fslf4j-caller-info-plugins","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhilKes%2Fslf4j-caller-info-plugins/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhilKes%2Fslf4j-caller-info-plugins/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhilKes%2Fslf4j-caller-info-plugins/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PhilKes","download_url":"https://codeload.github.com/PhilKes/slf4j-caller-info-plugins/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhilKes%2Fslf4j-caller-info-plugins/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279085462,"owners_count":26100017,"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","status":"online","status_checked_at":"2025-10-15T02:00:07.814Z","response_time":56,"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":["asm","caller-location","log4j","logback","logger","maven-plugin","performance","slf4j"],"created_at":"2025-02-01T04:31:19.171Z","updated_at":"2025-10-15T14:32:00.736Z","avatar_url":"https://github.com/PhilKes.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# slf4j-caller-info-maven-plugin\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.philkes/slf4j-caller-info-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.philkes/slf4j-caller-info-maven-plugin)\n[![Known Vulnerabilities](https://snyk.io/test/github/PhilKes/slf4j-caller-info-maven-plugin/badge.svg)](https://snyk.io/test/github/PhilKes/slf4j-caller-info-maven-plugin)\n[![License](https://img.shields.io/badge/License-Apache--2.0-blue)](./LICENSE)\n\nMaven plugin to **inject caller-location-information** to all [SLF4J Logger](https://www.slf4j.org/api/org/slf4j/Logger.html) log statement invocations (`info()`, etc.) in your compiled code, as a better alternative to SLF4J caller location evaluation during runtime. Also allows to inject caller-information when using wrapper classes/methods (see [Configuration/injectedMethods](#configuration)).\n\n\n## Description\nBy default SLF4J implementations such as `logback` or `log4j` offer to log the caller-location (e.g. [Logback/Layouts#method](https://logback.qos.ch/manual/layouts.html#method)), but this comes at a huge performance loss (see [Apache/Log4j2-Performance-Caller-Location](https://logging.apache.org/log4j/2.x/performance.html#asynchronous-logging-with-caller-location-information)). \n\nInstead of evaluating the caller-location (method, source code line number) during runtime, this plugin injects the caller-location info to all log statements when building the project.\nThe injection is done with a [MDC.put(...)](https://www.slf4j.org/api/org/slf4j/MDC.html#put-java.lang.String-java.lang.String-) call before every SLF4J log invocation, putting the class name, line number (optionally also method name) into the MDC in the compiled `.class` files. This allows to conveniently **print out where exactly in the code the log statement originates from** for every single log statement, without any overhead or performance loss, by simply adding the **Mapped Diagnostic Context** ([MDC](https://logback.qos.ch/manual/mdc.html)) parameter `callerInformation` to your logging-pattern configuration. It can therefore be used with any SLF4J implementation, such as [logback](https://logback.qos.ch/), [log4j2](https://logging.apache.org/log4j/2.x/), etc.\n\nSince this plugin adds the necessary code during the build stage, there is **nearly no performance loss** by injecting the caller-location-information in comparison to using e.g. the `%class` or `%line` pattern parameters (see [Log4j2 manual](https://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns) or [Logback manual](https://logback.qos.ch/manual/layouts.html#class) in your logging pattern, which look for the caller-information on the stacktrace during runtime which is very costly.\n\n## Usage\nAdd the plugin to your `pom.xml`:\n\n```xml\n\u003cbuild\u003e\n    \u003cplugins\u003e\n        \u003cplugin\u003e\n            \u003cgroupId\u003eio.github.philkes\u003c/groupId\u003e\n            \u003cartifactId\u003eslf4j-caller-info-maven-plugin\u003c/artifactId\u003e\n            \u003cversion\u003e1.1.0\u003c/version\u003e\n            \u003cexecutions\u003e\n                \u003cexecution\u003e\n                    \u003cgoals\u003e\n                        \u003cgoal\u003einject\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*Note: JDK 8 or higher required*\n\nThe plugin is executed in the `process-classes` phase or can be explicitly run with:\n```shell\nmvn slf4j-caller-info:inject\n```\n\n_Note: The `inject` goal is idempotent_\n\n## Code Example\nSee [logback.xml](./src/it/projects/logback/src/test/resources/logback.xml):\n```xml\n...\n\u003cappender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\"\u003e\n    \u003cencoder\u003e\n        \u003c!-- Example log pattern including the needed 'callerInformation' MDC parameter --\u003e\n        \u003cpattern\u003e%d{HH:mm:ss.SSS} %-5level %logger{36} \\(%X{callerInformation}\\) - %msg%n\u003c/pattern\u003e\n    \u003c/encoder\u003e\n\u003c/appender\u003e\n...\n```\nSee [LoggingTest.java](./src/it/projects/logback/src/main/java/io/github/philkes/slf4j/callerinfo/LoggingTest.java):\n```java\n1   package io.github.philkes.slf4j.callerinfo;\n2\n3   import org.slf4j.Logger;\n4   import org.slf4j.LoggerFactory;\n5\n6   /**\n7    * Example Class using an SLF4J Logger on different Levels\n8    */\n9   public class LoggingTest {\n10      private final Logger log = LoggerFactory.getLogger(LoggingTest.class);\n11\n12      public void log(String msg) {\n13          log.info(msg);\n14          log.warn(msg);\n15          log.error(msg);\n16          log.debug(msg);\n17          log.trace(msg);\n18      }\n19  }\n```\n\nLog Output of `LoggingTest.log(\"This is a test message\")`:\n\n\u003cimg src=\"./doc/log-output.png\" width=\"800\" style=\"border: 1px\"\u003e\n\n*(Screenshot from IntelliJ, automatically detects class + linenumber as links to jump directly into the source code)*\n\n## Performance at runtime\n\n\u003cimg src=\"./benchmark/results/results.png\" width=\"500\"\u003e\n\nAs you can see using the `slf4j-caller-info-maven-plugin` (orange bars) printing the caller location is about **4x faster** than using Log4j2's or Logback's caller-location built-in pattern (red bars). In total there is a performance loss of only ~9% for Log4j2 and ~8% for Logback in comparison to not logging the caller-location at all (blue bars).\n\nSystem specs for the benchmarks:\nJDK 17 on Linux Mint 20.3 with 8 cores CPU AMD Ryzen 2700X@3.7Ghz\n\nThe benchmarking was done with [JMH](https://github.com/openjdk/jmh) based on log4j's [log4j-perf](https://github.com/apache/logging-log4j2) module.\nFor more details about the benchmarks see the [benchmark](./benchmark/) module.\n\n\n### Performance at compiletime\nAs for the time it takes the `inject` goal to execute, the compilation time of the plugin is evaluated by generating Java projects with n classes, that all contain 5 SLF4J log-statements and running the plugin on these projects and averaging the plugin's execution time.\n\n\u003cimg src=\"./benchmark/results/results-compiletime.png\" width=\"500\"\u003e\n\nWe can see that the plugin's execution time obviously goes up the more classes and `SLF4J` log statements there are in the source code,\nbut even for a project with 10,000 classes the compilation time is ~2 seconds, which is only about twice as long as with only 1 class.\n\n\n### Configuration\nThere are several parameters you can overwrite:\n```xml\n\u003cconfiguration\u003e\n\u003c!-- All parameters are optional, the shown default values are used if they are not overwritten in your pom.xml --\u003e \n    \u003c!-- Injection format which can include conversion words: class,line,method --\u003e\n    \u003cinjection\u003e%class:%line\u003c/injection\u003e\n    \u003c!-- MDC parameter name for the injection, this parameter has to be present in your logging.pattern ('%X{callerInformation}') --\u003e\n    \u003cinjectionMdcParameter\u003ecallerInformation\u003c/injectionMdcParameter\u003e\n    \u003c!-- Regex for specifying which packages/classfiles should be injected into (path and class-file name) --\u003e\n    \u003cfilters\u003e\n        \u003cincludes\u003e\n            \u003cinclude\u003e.*\u003c/include\u003e\n        \u003c/includes\u003e\n        \u003cexcludes\u003e\u003c/excludes\u003e\n    \u003c/filters\u003e\n    \u003c!-- Method descriptors to configure for which method calls the caller-information should be injected to --\u003e\n    \u003c!-- By default all common SLF4J log methods are injected into, but this parameter also allows to inject to custom methods, e.g. when using wrapper classes for logging --\u003e\n    \u003cinjectedMethods\u003e\n        \u003cinjectedMethod\u003eorg/slf4j/Logger#info\u003c/injectedMethod\u003e\n        \u003cinjectedMethod\u003eorg/slf4j/Logger#warn\u003c/injectedMethod\u003e\n        \u003cinjectedMethod\u003eorg/slf4j/Logger#error\u003c/injectedMethod\u003e\n        \u003cinjectedMethod\u003eorg/slf4j/Logger#debug\u003c/injectedMethod\u003e\n        \u003cinjectedMethod\u003eorg/slf4j/Logger#trace\u003c/injectedMethod\u003e\n    \u003c/injectedMethods\u003e\n    \u003c!-- Whether or not to print the package-name of the class, if '%class' is present in 'injection' parameter --\u003e\n    \u003cincludePackageName\u003efalse\u003c/includePackageName\u003e\n    \u003c!-- Target directory which contains the compiled '.class' files --\u003e\n    \u003ctarget\u003e${project.build.outputDirectory}\u003c/target\u003e\n\u003c/configuration\u003e\n```\n\n### Compiled .class File of Code Example\n```java\n// import ...\npublic class LoggingTest {\n    //...\n    public void log(String msg) {\n        Logger var10000 = this.log;\n        MDC.put(\"callerInformation\", \"LoggingTest.class:13\");\n        var10000.info(msg);\n        MDC.remove(\"callerInformation\");\n        var10000 = this.log;\n        MDC.put(\"callerInformation\", \"LoggingTest.class:14\");\n        var10000.warn(msg);\n        ...\n    }\n}\n```\n\n\n## Dependencies\n- [ASM](https://asm.ow2.io/) for Java bytecode manipulation\n- [Apache Commons IO](https://commons.apache.org/proper/commons-io/) for FileUtils\n- Built with Java 17\n- [JMH](https://github.com/openjdk/jmh) for benchmarks\n\n\nThis project is licensed under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPhilKes%2Fslf4j-caller-info-plugins","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPhilKes%2Fslf4j-caller-info-plugins","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPhilKes%2Fslf4j-caller-info-plugins/lists"}