Logged is a lightweight Spring Boot library for method-level logging using Aspect-Oriented Programming (AOP). It provides an annotation-based mechanism to log method entry, return values, exceptions, and timing, with rich customization, masking, plugins, and optional weaving for private/self calls.
Think of it as a careful scribe for your code: precise, flexible, and useful.
Compatible with Java 21, Spring Boot 3.x, and SLF4J backends (Logback/Log4j2).
-
↓○ Entry, ↑○ Exit, ↑x Exception logging per method or per class (
@Logged) -
Argument names/types/values with configurable masking and truncation
-
Return value logging modes:
ALL,NONE,NULL -
Execution time capture and thresholds: auto-promote slow calls and add markers
-
Custom templates and icons; optional color decoration and icon themes
-
Depth indicators for nested/self calls
-
Global configuration via
application.yml/application.properties -
Plugins:
- SLF4J formatting with templates, icons, colors
- MDC enrichment: injects class/method/trace context into MDC
- OpenTelemetry: enriches spans with method metadata and MDC
- Logback/Log4j2 helpers: marker filters and configuration glue
-
AspectJ weaving option to log private and self-invoked methods
-
Utilities for banners, colorized output, string interpolation, and text transformation
Maven
<dependency>
<groupId>io.github.darkona</groupId>
<artifactId>logged</artifactId>
<version>1.7.1</version>
</dependency>Gradle (Groovy)
dependencies {
implementation "io.github.darkona:logged:1.7.1"
}Spring Boot autoconfiguration wires everything by default.
@Logged
public String greet(String name) {
return "Hello, " + name;
}Example log output:
↓○ DemoService::greet called with args: [(String)name:Ana]
↑○ DemoService::greet returned with value: Hello, Ana Time taken: 1 ms
The core of this library is the @Logged annotation. Place it on methods or classes (all public methods inside will be logged). It controls what is logged for method entry, arguments, return values, execution time, and exceptions.
| Attribute | Default | Description |
|---|---|---|
onCall |
true |
Emit on method entry. |
args |
true |
Include argument names/types. |
argValues |
ALL |
Values: ALL, NONE, NULL. |
onReturn |
true |
Emit on normal return. |
returnValue |
ALL |
Log return value. |
onException |
true |
Emit on exception. |
time |
true |
Add duration. |
callMsg |
"" |
Entry template override. |
returnMsg |
"" |
Return template override. |
exceptionMsg |
"" |
Exception template override. |
level |
INFO |
Base level for entry/return. |
exceptionLevel |
ERROR |
Level for exception. |
logStackTrace |
false |
Include stack trace in log. |
maskArgValues |
{} |
Mask by argument name. |
maskAtPos |
{} |
Mask by 0-based position. |
maskTypes |
{} |
Mask by type. |
maskPatterns |
{} |
Mask when toString() matches regex. |
maskReturn |
false |
Mask return value. |
markers |
{} |
Extra markers to attach. |
warnIfOverMs |
-1 |
Promote level if duration exceeds threshold. |
slowMarker |
"" |
Marker for slow calls. |
Enum Values for argValues/returnValue: ALL, NONE, NULL.
logged:
enabled: true
color: true
icons: true
useUtf8: true # opt-in (default false): replaces System.out/System.err JVM-wide
callIcon: "↓○"
returnIcon: "↑○"
exceptionIcon: "↑x"
depthIcon: ">"
maxValueLength: 2048logged:
maskString: "*****"
maskLength: 5
maskPatterns:
- "\d{16}"
- "(?i)secret|token"
maskTypeNames:
- "java.util.UUID"
failOnInvalidMaskPatterns: false
failOnUnresolvedMaskTypes: false
maskReturn: falselogged:
threshold:
warnMs: 250
promoteLevel: WARNlogged:
useIconTheme: true
iconTheme: SJET_3logged:
cache:
# Max compiled @Logged(maskPatterns=...) regexes kept in an LRU cache.
# Mask patterns should be compile-time constants; generating them
# dynamically churns the cache and forces repeated recompilation.
max-annotation-patterns: 512logged:
stack:
# Class-name prefixes skipped when resolving the exception origin frame
# ({ec}, {em}, {L} and {f} tokens). Setting this REPLACES the defaults,
# so include them if you only want to add more prefixes.
skip-prefixes:
- "java."
- "jdk."
- "sun."
- "org.springframework."
- "org.aspectj."
- "io.github.darkona.logged."logged:
slf4j:
enabled: true
color: true
iconColors: true
callMsgNoArgs: "{h:}{cI:} {c}::{m} called."
callMsgArgs: "{h:}{cI:} {c}::{m} called with args: [{a}]"
returnMsg: "{h:}{rI:} {c}::{m} returned."
returnMsgValue:"{h:}{rI:} {c}::{m} returned with value: {rV}"
timeTakenMsg: "Time taken: {d} ms"
logDepth: true
captureFromMdc: [trace_id, span_id, call_id]
markers: []
maxValueLength: 2048logged:
mdc:
enabled: true
classKey: class
methodKey: method
traceKey: trace_idlogged:
otel:
enabled: true
mdcKey: trace
attributes: {}Tokens inside templates:
{c}Class simple name{C}Fully qualified class name{m}Method name{t}Return type{a}Arguments list{rV}Return value{rC}Return type class name{d}Duration (ms){f}Exception origin file{L}Exception origin line{ex}Exception class name{eM}Exception message{ec}Exception origin class{em}Exception origin method{eI}Entry icon{xI}Exit icon{tI}Throw icon{dI}Depth icon{h}Depth string when enabled{mdc.<key>}Value from MDC
Supports defaults: {token:default}. Use {{ and }} for escaping.
- Bannerizer: ASCII/Unicode banners, centering, tables, menus.
- Colorizer: ANSI colors, RGB, predefined palettes, reset.
- Transformer:
objectString,mask,truncate,capitalize, substrings, safe string ops. - StringInterpolator: generic token interpolation with map.
- LogDecorator: apply colors, banners, ornaments, case adjustments.
Spring AOP proxies only intercept public methods. To log private/self calls, use AspectJ weaving.
- Add dependencies (
spring-boot-starter-aop,aspectjweaver). - Create
META-INF/aop.xmlincluding your packages andio.github.darkona.logged..*. - Start JVM with
-javaagent:/path/to/aspectjweaver.jar.
Classes are woven at build time, so no agent runs. Three things are required, and skipping any of them breaks the app at the first annotated call:
- Put logged on the AspectJ aspect path, non-transitively.
- Pass the shipped allow-list
META-INF/logged/logged-weaving.xmltoajc. The jar carries two aspects and ajc weaves both unless told otherwise. - Set
logged.weaving: enabled. CTW leaves no agent for the defaultautodetection to find, so Spring would otherwise register its proxy next to the woven aspect and every annotated method would be instrumented twice.
plugins {
id 'io.freefair.aspectj.post-compile-weaving' version '9.5.0'
}
configurations { loggedArtifact }
dependencies {
implementation "io.github.darkona:logged:1.7.1"
aspect("io.github.darkona:logged:1.7.1") { transitive = false }
loggedArtifact("io.github.darkona:logged:1.7.1") { transitive = false }
}
def weavingConfigDir = layout.buildDirectory.dir('aspectj')
def weavingConfig = weavingConfigDir.map { it.file('META-INF/logged/logged-weaving.xml') }
tasks.register('extractLoggedWeavingConfig', Copy) {
from({ zipTree(configurations.loggedArtifact.singleFile) }) {
include 'META-INF/logged/logged-weaving.xml'
}
into weavingConfigDir
}
tasks.withType(JavaCompile).configureEach {
def ajc = extensions.findByName('ajc')
if (ajc != null) {
dependsOn 'extractLoggedWeavingConfig'
ajc.options.compilerArgs.addAll('-xmlConfigured', weavingConfig.get().asFile.absolutePath)
// Neither the compiler args nor the file they name are task inputs by default:
// without this line, editing the allow-list leaves compileJava UP-TO-DATE and the
// previous weaving in place.
inputs.file(weavingConfig).withPropertyName('loggedWeavingConfig')
}
}logged:
weaving: enabledCTW weaves only the module being compiled. In a multi-module build, apply the plugin to every module whose classes you want woven.
See docs/ref/weaving-aspectj.md for Maven, for load-time weaving and for troubleshooting.
Both LTW and CTW:
- Log private/protected methods.
- Capture self-invocation.
// Default usage
@Logged
public String salute() { return "Hello World!"; }
// Disable entry logging
@Logged(onCall = false)
public String hello() { return "Hi"; }
// Mask arguments
@Logged(maskArgValues = {"password"}, maskAtPos = {1})
public void login(String username, String password) { }
// Custom templates
@Logged(callMsg = "{eI}{c}.{m} → args={a}",
returnMsg = "{xI}{c}.{m} ⇒ {rV} ({d}ms)",
exceptionMsg = "{tI}{c}.{m} !! {ex}: {eM} at {ec}.{em} ({f}:{L})")
public String greet(String name) { return "Hello, " + name; }- Spring AOP or AspectJ weaving intercepts
@Loggedmethods. LoggedEnginecomposes tokens and plugins.- Plugins: SLF4J, MDC, OTel, color/decorator utilities.
- No heavy runtime reflection.
Logged is licensed under the Apache License 2.0. Free for commercial and open-source use, modification and redistribution.
Versions up to and including 1.6.1 were published under LGPL-3.0 and remain so; the Apache 2.0 license applies from 1.7.0 onwards.