diff --git a/.claude/skills/architecture-sync/SKILL.md b/.claude/skills/architecture-sync/SKILL.md index 2c1da91008..cdd340b813 100644 --- a/.claude/skills/architecture-sync/SKILL.md +++ b/.claude/skills/architecture-sync/SKILL.md @@ -1,6 +1,6 @@ --- name: architecture-sync -description: Read this WHEN A CHANGE ALTERS THE SHAPE OF THE LIBRARY — adding, removing, renaming or moving a Java package under logback-android/src/main/java; moving a responsibility between packages; adding an android.* import to a new package or any core→classic import; adding a published output (artifact, flavor, the XSD, consumer R8 rules) or a runtime dependency; or changing how configuration is discovered or a log call is dispatched. Also read it before opening the PR for such a change, and when asked to check whether docs/architecture is still accurate. +description: Read this WHEN A CHANGE ALTERS THE SHAPE OF THE LIBRARY — adding, removing, renaming or moving a Java or Kotlin package under logback-android/src/main/java or src/main/kotlin; moving a responsibility between packages; adding an android.* import to a new package or any core→classic import; adding a published output (artifact, flavor, the XSD, consumer R8 rules) or a runtime dependency; or changing how configuration is discovered or a log call is dispatched. Also read it before opening the PR for such a change, and when asked to check whether docs/architecture is still accurate. --- # Keeping the architecture docs true @@ -44,7 +44,7 @@ is a design question, not a documentation question — ask before writing it dow ``` Add, remove or rename the entry to match. The backticked directory path (relative to -`logback-android/src/main/java`) is what the gate matches on, so it has to be exact. Mark +`logback-android/src/main/java` or `logback-android/src/main/kotlin`) is what the gate matches on, so it has to be exact. Mark Android-only packages as such. Then read the entries **either side of the change**, not just the one you added. A diff --git a/docs/architecture/components.md b/docs/architecture/components.md index ca8a819397..aa64969db9 100644 --- a/docs/architecture/components.md +++ b/docs/architecture/components.md @@ -1,6 +1,7 @@ # Component catalogue -One entry per Java package under `logback-android/src/main/java`. The heading's backticked +One entry per package under `logback-android/src/main/java` (the upstream logback port) or +`logback-android/src/main/kotlin` (the Android layer, #388). The heading's backticked path is what `scripts/check-architecture-docs.sh` matches on, so it must be exact. Each entry says what the package is responsible for, and anything that must stay true of it. @@ -29,7 +30,7 @@ safety of `Logger` and `LoggerContext` is load-bearing: they are called from eve ### `ch/qos/logback/classic/android` — `ch.qos.logback.classic.android` -Android-only appenders: `LogcatAppender`, `SQLiteAppender` (+ `SQLiteLogCleaner`), and +Kotlin. Android-only appenders: `LogcatAppender`, `SQLiteAppender` (+ `SQLiteLogCleaner`), and `BasicLogcatConfigurator`, which an app calls to log to logcat without a `logback.xml`. One of the few packages allowed to import `android.*`. @@ -133,7 +134,7 @@ the locking model of every appender built on them. ### `ch/qos/logback/core/android` — `ch.qos.logback.core.android` -Android-only: `AndroidContextUtil` (resolves `DATA_DIR`, `EXT_DIR`, package name, etc. for +Kotlin. Android-only: `AndroidContextUtil` (resolves `DATA_DIR`, `EXT_DIR`, package name, etc. for configuration properties) and `SystemPropertiesProxy`. Lookups are lazy so configuration does not read disk on the main thread (see #383). diff --git a/logback-android/src/main/java/ch/qos/logback/classic/AsyncAppender.java b/logback-android/src/main/java/ch/qos/logback/classic/AsyncAppender.java index 9c888c9a3b..e4de2a1f4a 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/AsyncAppender.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/AsyncAppender.java @@ -37,11 +37,13 @@ public class AsyncAppender extends AsyncAppenderBase { * @param event * @return true if the event is of level TRACE, DEBUG or INFO false otherwise. */ + @Override protected boolean isDiscardable(ILoggingEvent event) { Level level = event.getLevel(); return level.toInt() <= Level.INFO_INT; } + @Override protected void preprocess(ILoggingEvent eventObject) { eventObject.prepareForDeferredProcessing(); if(includeCallerData) diff --git a/logback-android/src/main/java/ch/qos/logback/classic/BasicConfigurator.java b/logback-android/src/main/java/ch/qos/logback/classic/BasicConfigurator.java index 12890d08e8..6327c1dee8 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/BasicConfigurator.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/BasicConfigurator.java @@ -36,6 +36,7 @@ public class BasicConfigurator extends ContextAwareBase implements Configurator public BasicConfigurator() { } + @Override public void configure(LoggerContext lc) { addInfo("Setting up default configuration."); ConsoleAppender ca = new ConsoleAppender(); diff --git a/logback-android/src/main/java/ch/qos/logback/classic/Level.java b/logback-android/src/main/java/ch/qos/logback/classic/Level.java index 48d3801088..0ac53dc82f 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/Level.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/Level.java @@ -96,6 +96,7 @@ private Level(int levelInt, String levelStr) { * Returns the string representation of this Level. * @return the string value of this level */ + @Override public String toString() { return levelStr; } diff --git a/logback-android/src/main/java/ch/qos/logback/classic/Logger.java b/logback-android/src/main/java/ch/qos/logback/classic/Logger.java index 95cd38dea4..37c2e22239 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/Logger.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/Logger.java @@ -54,7 +54,7 @@ public final class Logger implements org.slf4j.Logger, LocationAwareLogger, private String name; // The assigned levelInt of this logger. Can be null. - transient private Level level; + transient private volatile Level level; // The effective levelInt is the assigned levelInt and if null, a levelInt is // inherited form a parent. @@ -122,6 +122,7 @@ public Level getLevel() { return level; } + @Override public String getName() { return name; } @@ -207,12 +208,14 @@ private synchronized void handleParentLevelChange(int newParentLevelInt) { *

* This is useful when re-reading configuration information. */ + @Override public void detachAndStopAllAppenders() { if (aai != null) { aai.detachAndStopAllAppenders(); } } + @Override public boolean detachAppender(String name) { if (aai == null) { return false; @@ -222,6 +225,7 @@ public boolean detachAppender(String name) { // this method MUST be synchronized. See comments on 'aai' field for further // details. + @Override public synchronized void addAppender(Appender newAppender) { if (aai == null) { aai = new AppenderAttachableImpl(); @@ -229,6 +233,7 @@ public synchronized void addAppender(Appender newAppender) { aai.addAppender(newAppender); } + @Override public boolean isAttached(Appender appender) { if (aai == null) { return false; @@ -237,6 +242,7 @@ public boolean isAttached(Appender appender) { } @SuppressWarnings("unchecked") + @Override public Iterator> iteratorForAppenders() { if (aai == null) { return Collections.EMPTY_LIST.iterator(); @@ -244,6 +250,7 @@ public Iterator> iteratorForAppenders() { return aai.iteratorForAppenders(); } + @Override public Appender getAppender(String name) { if (aai == null) { return null; @@ -282,6 +289,7 @@ private int appendLoopOnAppenders(ILoggingEvent event) { /** * Remove the appender passed as parameter form the list of appenders. */ + @Override public boolean detachAppender(Appender appender) { if (aai == null) { return false; @@ -439,22 +447,27 @@ private void buildLoggingEventAndAppend(final String localFQCN, callAppenders(le); } + @Override public void trace(String msg) { filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, null); } + @Override public void trace(String format, Object arg) { filterAndLog_1(FQCN, null, Level.TRACE, format, arg, null); } + @Override public void trace(String format, Object arg1, Object arg2) { filterAndLog_2(FQCN, null, Level.TRACE, format, arg1, arg2, null); } + @Override public void trace(String format, Object... argArray) { filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, format, argArray, null); } + @Override public void trace(String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, t); } @@ -509,6 +522,7 @@ public void trace(List markers, String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, markers, Level.TRACE, msg, null, t); } + @Override public boolean isDebugEnabled() { return isDebugEnabled(Collections.emptyList()); } @@ -526,22 +540,27 @@ public boolean isDebugEnabled(List markers) { } } + @Override public void debug(String msg) { filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, null); } + @Override public void debug(String format, Object arg) { filterAndLog_1(FQCN, null, Level.DEBUG, format, arg, null); } + @Override public void debug(String format, Object arg1, Object arg2) { filterAndLog_2(FQCN, null, Level.DEBUG, format, arg1, arg2, null); } + @Override public void debug(String format, Object... argArray) { filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, format, argArray, null); } + @Override public void debug(String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, t); } @@ -596,22 +615,27 @@ public void debug(List markers, String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, markers, Level.DEBUG, msg, null, t); } + @Override public void error(String msg) { filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, null); } + @Override public void error(String format, Object arg) { filterAndLog_1(FQCN, null, Level.ERROR, format, arg, null); } + @Override public void error(String format, Object arg1, Object arg2) { filterAndLog_2(FQCN, null, Level.ERROR, format, arg1, arg2, null); } + @Override public void error(String format, Object... argArray) { filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, format, argArray, null); } + @Override public void error(String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, t); } @@ -666,6 +690,7 @@ public void error(List markers, String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, markers, Level.ERROR, msg, null, t); } + @Override public boolean isInfoEnabled() { return isInfoEnabled(Collections.emptyList()); } @@ -683,22 +708,27 @@ public boolean isInfoEnabled(List markers) { } } + @Override public void info(String msg) { filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null); } + @Override public void info(String format, Object arg) { filterAndLog_1(FQCN, null, Level.INFO, format, arg, null); } + @Override public void info(String format, Object arg1, Object arg2) { filterAndLog_2(FQCN, null, Level.INFO, format, arg1, arg2, null); } + @Override public void info(String format, Object... argArray) { filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, format, argArray, null); } + @Override public void info(String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, t); } @@ -753,6 +783,7 @@ public void info(List markers, String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, markers, Level.INFO, msg, null, t); } + @Override public boolean isTraceEnabled() { return isTraceEnabled(Collections.emptyList()); } @@ -770,6 +801,7 @@ public boolean isTraceEnabled(List markers) { } } + @Override public boolean isErrorEnabled() { return isErrorEnabled(Collections.emptyList()); } @@ -787,6 +819,7 @@ public boolean isErrorEnabled(List markers) { } } + @Override public boolean isWarnEnabled() { return isWarnEnabled(Collections.emptyList()); } @@ -822,10 +855,12 @@ public boolean isEnabledFor(Level level) { return isEnabledFor(null, level); } + @Override public void warn(String msg) { filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, null); } + @Override public void warn(String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, t); } @@ -860,14 +895,17 @@ public void warn(Marker marker, String msg, Throwable t) { warn(Collections.singletonList(marker), msg, t); } + @Override public void warn(String format, Object arg) { filterAndLog_1(FQCN, null, Level.WARN, format, arg, null); } + @Override public void warn(String format, Object arg1, Object arg2) { filterAndLog_2(FQCN, null, Level.WARN, format, arg1, arg2, null); } + @Override public void warn(String format, Object... argArray) { filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, format, argArray, null); } @@ -900,6 +938,7 @@ public void setAdditive(boolean additive) { this.additive = additive; } + @Override public String toString() { return "Logger[" + name + "]"; } diff --git a/logback-android/src/main/java/ch/qos/logback/classic/LoggerContext.java b/logback-android/src/main/java/ch/qos/logback/classic/LoggerContext.java index 7876f48905..152891f007 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/LoggerContext.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/LoggerContext.java @@ -116,6 +116,7 @@ public final Logger getLogger(final Class clazz) { return getLogger(clazz.getName()); } + @Override public Logger getLogger(final String name) { if (name == null) { @@ -350,11 +351,13 @@ private void fireOnStop() { // === end listeners ============================================== + @Override public void start() { super.start(); fireOnStart(); } + @Override public void stop() { reset(); fireOnStop(); diff --git a/logback-android/src/main/java/ch/qos/logback/classic/PatternLayout.java b/logback-android/src/main/java/ch/qos/logback/classic/PatternLayout.java index b89a074508..2add84c011 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/PatternLayout.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/PatternLayout.java @@ -139,10 +139,12 @@ public PatternLayout() { this.postCompileProcessor = new EnsureExceptionHandling(); } + @Override public Map getDefaultConverterMap() { return defaultConverterMap; } + @Override public String doLayout(ILoggingEvent event) { if (!isStarted()) { return CoreConstants.EMPTY_STRING; diff --git a/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnErrorEvaluator.java b/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnErrorEvaluator.java index 9d7a6e262f..90e84b5869 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnErrorEvaluator.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnErrorEvaluator.java @@ -33,6 +33,7 @@ public class OnErrorEvaluator extends EventEvaluatorBase { * Return true if event passed as parameter has level ERROR or higher, returns * false otherwise. */ + @Override public boolean evaluate(ILoggingEvent event) throws NullPointerException, EvaluationException { return event.getLevel().levelInt >= Level.ERROR_INT; diff --git a/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnMarkerEvaluator.java b/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnMarkerEvaluator.java index 9c47f67f0b..e82fdd28c3 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnMarkerEvaluator.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/boolex/OnMarkerEvaluator.java @@ -42,6 +42,7 @@ public void addMarker(String markerStr) { * Return true if event passed as parameter contains one of the specified * user-markers. */ + @Override public boolean evaluate(ILoggingEvent event) throws NullPointerException, EvaluationException { diff --git a/logback-android/src/main/java/ch/qos/logback/classic/db/names/DefaultDBNameResolver.java b/logback-android/src/main/java/ch/qos/logback/classic/db/names/DefaultDBNameResolver.java index edbeec2ac1..08ebe73fec 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/db/names/DefaultDBNameResolver.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/db/names/DefaultDBNameResolver.java @@ -27,10 +27,12 @@ */ public class DefaultDBNameResolver implements DBNameResolver { + @Override public > String getTableName(N tableName) { return tableName.toString().toLowerCase(Locale.US); } + @Override public > String getColumnName(N columnName) { return columnName.toString().toLowerCase(Locale.US); } diff --git a/logback-android/src/main/java/ch/qos/logback/classic/db/names/SimpleDBNameResolver.java b/logback-android/src/main/java/ch/qos/logback/classic/db/names/SimpleDBNameResolver.java index 0d6db8ad6b..0eb3550c9e 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/db/names/SimpleDBNameResolver.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/db/names/SimpleDBNameResolver.java @@ -33,10 +33,12 @@ public class SimpleDBNameResolver implements DBNameResolver { private String columnNameSuffix = ""; + @Override public > String getTableName(N tableName) { return tableNamePrefix + tableName.name().toLowerCase(Locale.US) + tableNameSuffix; } + @Override public > String getColumnName(N columnName) { return columnNamePrefix + columnName.name().toLowerCase(Locale.US) + columnNameSuffix; } diff --git a/logback-android/src/main/java/ch/qos/logback/classic/filter/LevelFilter.java b/logback-android/src/main/java/ch/qos/logback/classic/filter/LevelFilter.java index 55d10ec434..0f00e32a66 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/filter/LevelFilter.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/filter/LevelFilter.java @@ -51,6 +51,7 @@ public void setLevel(Level level) { this.level = level; } + @Override public void start() { if (this.level != null) { super.start(); diff --git a/logback-android/src/main/java/ch/qos/logback/classic/filter/ThresholdFilter.java b/logback-android/src/main/java/ch/qos/logback/classic/filter/ThresholdFilter.java index 9ad67e2cc3..0a79ae739c 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/filter/ThresholdFilter.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/filter/ThresholdFilter.java @@ -55,6 +55,7 @@ public void setLevel(String level) { this.level = Level.toLevel(level); } + @Override public void start() { if (this.level != null) { super.start(); diff --git a/logback-android/src/main/java/ch/qos/logback/classic/html/DefaultCssBuilder.java b/logback-android/src/main/java/ch/qos/logback/classic/html/DefaultCssBuilder.java index 0eccd1ca01..542f292bfa 100644 --- a/logback-android/src/main/java/ch/qos/logback/classic/html/DefaultCssBuilder.java +++ b/logback-android/src/main/java/ch/qos/logback/classic/html/DefaultCssBuilder.java @@ -29,6 +29,7 @@ */ public class DefaultCssBuilder implements CssBuilder { + @Override public void addCss(StringBuilder sbuf) { sbuf.append("