{"id":47634897,"url":"https://github.com/dansiviter/jule","last_synced_at":"2026-04-02T00:02:00.367Z","repository":{"id":39990039,"uuid":"342797176","full_name":"dansiviter/jule","owner":"dansiviter","description":"Java Util Logging Enhancer (JULE) to improve both implementation, performance and testing of logging with `java.util.logging`.","archived":false,"fork":false,"pushed_at":"2026-03-17T21:11:55.000Z","size":343,"stargazers_count":3,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-18T10:06:13.888Z","etag":null,"topics":["asynchronous-handlers","cdi","fallback-handlers","logging"],"latest_commit_sha":null,"homepage":"https://jule.dansiviter.uk","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/dansiviter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-02-27T07:26:56.000Z","updated_at":"2026-03-17T20:49:02.000Z","dependencies_parsed_at":"2025-09-23T20:19:15.094Z","dependency_job_id":"40d141b8-48e7-4295-9e52-7f5594c40cb1","html_url":"https://github.com/dansiviter/jule","commit_stats":null,"previous_names":["dansiviter/juli"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/dansiviter/jule","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dansiviter%2Fjule","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dansiviter%2Fjule/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dansiviter%2Fjule/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dansiviter%2Fjule/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dansiviter","download_url":"https://codeload.github.com/dansiviter/jule/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dansiviter%2Fjule/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31293142,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["asynchronous-handlers","cdi","fallback-handlers","logging"],"created_at":"2026-04-02T00:01:05.977Z","updated_at":"2026-04-02T00:02:00.345Z","avatar_url":"https://github.com/dansiviter.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dansiviter/jule/deploy.yaml)](https://github.com/dansiviter/jule/actions/workflows/build.yaml) [![Known Vulnerabilities](https://snyk.io/test/github/dansiviter/jule/badge.svg?style=flat-square)](https://snyk.io/test/github/dansiviter/jule) [![Sonar Coverage](https://img.shields.io/sonar/coverage/dansiviter_jule?server=https%3A%2F%2Fsonarcloud.io\u0026style=flat-square)](https://sonarcloud.io/dashboard?id=dansiviter_jule) [![Maven Central](https://img.shields.io/maven-central/v/uk.dansiviter.jule/jule-project?style=flat-square)](https://search.maven.org/artifact/uk.dansiviter.jule/jule-project) ![Java 11+](https://img.shields.io/badge/-Java%2011%2B-informational?style=flat-square)\n\n\n# Java Util Logging Enhancer (JULE) #\n\nAlthough rarely the preferred framework `java.util.logging` (JUL) is embedded into Java so aids minimal applications but is not the easiest to use. This library is here to make life a little easier:\n* Minimal (~21KB for v0.3.0) layer to improve:\n  * Type-safety to reduce errors,\n  * Improve maintenance overhead by reducing complexity,\n  * Simplify unit testing (especially with CDI),\n  * Reduce performance impact by deferring array initialisation and auto-boxing until actually needed,\n  * Automatic unwrapping of `java.util.function.*Supplier` and `java.util.Optional` parameters.\n* Asynchronous handlers to mitigate logging impact on critical path,\n* Fallback handlers to mitigate loss of logs to aid debugging.\n\n\n## Log Wrapper ##\n\nThe wrapper uses [Annotation Processing](https://docs.oracle.com/en/java/javase/11/docs/api/java.compiler/javax/annotation/processing/package-summary.html) to generate an implementation that includes many logging best practices without a developer needing to worry about these.\n\n\u003e :information_source: [JBoss Logging Tools](https://github.com/jboss-logging/jboss-logging-tools) was the inspiration but designed to be even simpler, leaner and not dependent on JBoss Log Manager.\n\nLets get started... first import dependencies:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003euk.dansiviter.jule\u003c/groupId\u003e\n  \u003cartifactId\u003ejule\u003c/artifactId\u003e\n  \u003cversion\u003e${jule.version}\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n  \u003cgroupId\u003euk.dansiviter.jule\u003c/groupId\u003e\n  \u003cartifactId\u003ejule-processor\u003c/artifactId\u003e\n  \u003cversion\u003e${jule.version}\u003c/version\u003e\n  \u003cscope\u003eprovided\u003c/scope\u003e \u003c!-- only needed during compilation --\u003e\n  \u003coptional\u003etrue\u003c/optional\u003e\n\u003c/dependency\u003e\n```\n\nDefine a logger interface:\n```java\npackage com.foo;\n...\n\n@Logger\npublic interface MyLog {\n  @Message(\"Hello %s\")  // Uses java.util.Formatter and defaults to `INFO` level\n  void hello(String name);\n\n  @Message(value = \"Oh no! %s\", level =.ERROR)  // \u003c- 'ERROR' level\n  void error(String name, Throwable t);  // \u003c- Throwables must be last parameter\n\n  @Message(\"Hello %s\")\n  void unwrap(Supplier\u003cString\u003e name);  // \u003c- value extracted on the calling thread if #isLoggable passes\n\n  @Message(\"Number %d\")\n  void number(int value);  // \u003c- primitives only auto-boxed if the log level is consumed. w00t!\n\n  @Message(\"Another number %d\")\n  void numberUnwrap(IntSuppler value);  // \u003c- primitive suppliers work too!\n}\n```\n\nThis will generate a class `com.foo.MyLogImpl` which actually does the logging. For Maven this can be seen in the `target/generated-sources/annotations/` folder for reference.\n\nTo get an instance use `uk.dansiviter.jule.LogFactory`:\n```java\npublic class MyClass {\n  private final static MyLog LOG = LogFactory.log(MyLog.class);\n\n  public void myMethod() {\n    LOG.hello(\"foo\");\n  }\n}\n```\n\n\u003e :information_source: The log levels are reduced to just `ERROR`, `WARN`, `INFO`, `DEBUG` and `TRACE` as, frankly, that's all you really need.\n\n\n## CDI ##\n\nIf you wish for CDI to manage the logger and and make it available for injection, just use:\n\n```java\n@Logger(lifecycle = Lifecycle.CDI)\ninterface MyLog {\n  ...\n}\n```\n\nThis will generage a `@Dependent` logger implementation.\n\nThen just inject:\n```java\n@ApplicationScoped\npublic class MyClass {\n  @Inject\n  private MyLog log;\n\n  public void myMethod() {\n    log.hello(\"foo\");\n  }\n}\n```\n\nThis will inject a `@Dependent` scoped instance of the logger to prevent proxying.\n\n\u003e :information_source: Testing can be done easily by injecting a mock of `MyLog` which helps validating behaviour which is especially pertinent for `WARN` and `ERROR` messages.\n\n\n## Asynchronous Handlers ##\n\nJUL handlers are all synchronous which puts IO directly within the path of execution; this is a bottleneck. To address this, this library has a very simple `uk.dansiviter.jule.AsyncHandler` implementation that uses `java.util.concurrent.Flow` to asynchronously process log events. Using this can significantly improve the execution performance of methods that have 'chatty' logging at the expense of a little memory and CPU. There is only one concrete implementation as the moment which is `uk.dansiviter.jule.AsyncConsoleHandler` which can be used as a direct replacement for `java.util.logging.ConsoleHandler`.\n\n\u003e :warning: If the buffer saturates, then the much of the performance benefits of the asynchronous handler can be lost. However, once the back-pressure is reduced this will return, due to this it _should_ still outperform a synchronous implementation.\n\n\u003e :information_source: `com.lmax:disruptor` has been trialed as an alternative to using Java 9 `Flow` but its bulk (~90KB) and no significant out-of-the-box performance improvement it has been discounted (see [#6](../../issues/6)).\n\n\n## Fallback Handler ##\n\nSome handlers have external factors that may prevent a log record being flushed. This might include a remote log aggregator where a network failure prevents the message being delivered. To prevent loss of log records the `uk.dansiviter.jule.FallbackHandler` can be used to manage this case. For example:\n\n```\nhandlers=uk.dansiviter.jule.FallbackHandler\nuk.dansiviter.jule.FallbackHandler.delegate=com.acme.MyRemoteHandler\nuk.dansiviter.jule.FallbackHandler.fallback=java.util.logging.ConsoleHandler\n```\nWith the above configuration, if either `MyRemoteHandler` `delegate` cannot be created or `Handler#publish(...)` fails the `fallback` handler will be used instead. If no `fallback` is defined then `AsyncConsoleHandler` is used.\n\n## FAQ ##\n\n### Does this work in an IDE? ###\n\nThis uses vanilla Annotation Processing so there is no reason for it not to work. It's known to work fine with VSCode (with Java Tools Pack) out of the box and Eclipse and IntelliJ when Annotation Processing is enabled.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdansiviter%2Fjule","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdansiviter%2Fjule","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdansiviter%2Fjule/lists"}