This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch docs
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/docs by this push:
     new fc55468b04 TODO-368: JUL/Spring control plane for REST debug logging
fc55468b04 is described below

commit fc55468b044aa7177f5b09407421a074081c9a1d
Author: James Bognar <[email protected]>
AuthorDate: Sun Aug 16 06:52:31 2026 -0400

    TODO-368: JUL/Spring control plane for REST debug logging
    
    - Emit REST debug records at stable INFO level; tier (INFO/DEBUG/TRACE) 
controls message detail only.
    - Add proxy-safe logger naming (LoggerNaming.userClassName) and wire 
RestContext default logger derivation.
    - Add Spring Boot auto-config (JuneauRestLoggingAutoConfiguration) with 
reset-resistant Logback->JUL LevelChangePropagator, provided logback-classic, 
optional OSGi import + manifest assertion, and no-Logback fallback.
    - Integration coverage for resource/op-level level propagation; docs + 
migration + release-note updates.
---
 pages/release-notes/10.0.0.md                      |  7 ++++-
 .../topics/10.32.RestServerLoggingAndDebugging.md  | 33 ++++++++++++++++++++--
 pages/topics/12.00.JuneauRestServerSpringboot.md   | 29 +++++++++++++++++++
 pages/topics/27.V10MigrationGuide.md               |  7 ++++-
 4 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/pages/release-notes/10.0.0.md b/pages/release-notes/10.0.0.md
index bfd1c5dd13..d2f559bcfc 100644
--- a/pages/release-notes/10.0.0.md
+++ b/pages/release-notes/10.0.0.md
@@ -476,9 +476,12 @@ for the full removed-symbol mapping.
 
 - **One signal.** A resource's own `java.util.logging.Logger` level is the 
sole control for request/response debug
   capture — no annotations, no per-request headers, no separate config keys. 
Verbosity is cumulative: `INFO` =
-  basic, `FINE` = + headers, `FINEST` = + bodies, one `LogRecord` per request 
at the highest enabled tier.
+  basic, `FINE` = + headers, `FINEST` = + bodies, one `LogRecord` per request 
(stable emitted level: `INFO`).
 - **Per-operation granularity** falls out of ordinary JUL parent-inheritance 
via a hierarchical child logger
   (`resourceClass.getName() + "." + methodName`) — elevate one method to 
`FINEST` without touching the rest.
+- **Spring Boot propagation path.** For real Logback backends, 
`logging.level.*` now propagates into JUL by default
+  (`juneau.rest.logging.propagate-levels=true`), with an additive default 
posture
+  (`juneau.rest.logging.propagate-levels.reset-jul=false`) and silent no-op 
fallback for non-Logback backends.
 - **New `RestDebugFormatter` SPI** (`org.apache.juneau.rest.server.logging`) — 
a per-tier formatter interface
   (`formatBasic`/`formatHeaders`/`formatBody`) with a shipped 
`BasicRestDebugFormatter` default. It's the only
   public extension point; the two-phase capture pipeline underneath it is 
internal. Resolution precedence:
@@ -493,6 +496,8 @@ for the full removed-symbol mapping.
 - **Marshall-layer `debug`** (recursion detection + richer serialization 
exceptions) is unaffected in behavior —
   `RestRequest.isDebug()` still exists, now derived and read-only, `true` when 
the resolved logger is
   `FINE`-or-finer.
+- **Operator caveat.** Stable-`INFO` emission means DEBUG/TRACE-selected 
headers and bodies flow through INFO sinks;
+  keep broad DEBUG/TRACE raises scoped until payload-hardening controls are in 
place.
 
 See the new [Logging / Debugging](/docs/topics/RestServerLoggingAndDebugging) 
topic page for the full model.
 
diff --git a/pages/topics/10.32.RestServerLoggingAndDebugging.md 
b/pages/topics/10.32.RestServerLoggingAndDebugging.md
index a57f014ec2..9f4201cd0a 100644
--- a/pages/topics/10.32.RestServerLoggingAndDebugging.md
+++ b/pages/topics/10.32.RestServerLoggingAndDebugging.md
@@ -14,7 +14,7 @@ that class's endpoints, at three cumulative tiers.
   The resolved JUL logger's level is the sole control.
 - **Cumulative tiers.** `INFO` = basic request/response logging, `FINE` = adds 
headers, `FINEST` = adds bodies.
   Each tier includes everything the tier below it logs.
-- **One log record per request**, emitted at the resolved tier, through the 
resolved logger.
+- **One log record per request**, always emitted at JUL `INFO`. The resolved 
tier controls content only.
 - **Secure by default.** Sensitive headers are redacted and bodies are capped, 
both overridable — see
   [Secure by default](#secure-by-default-redaction--body-cap) below.
 
@@ -34,6 +34,10 @@ this is a plain <a 
href="https://docs.oracle.com/en/java/javase/17/docs/api/java
 hierarchy, ordinary JUL parent-inheritance rules apply — an operation logger 
with no level of its own inherits the
 resource logger's level.
 
+Default resource logger naming normalizes common proxy-shaped classes (Spring 
CGLIB, ByteBuddy, JDK proxy-style,
+Hibernate/Mockito proxy infixes) back to the user class name, while preserving 
ordinary nested class names unchanged.
+This avoids logger-name churn when resources are wrapped by runtime proxies.
+
 ```java
 // logging.properties
 com.example.MyResource.level = FINE
@@ -102,6 +106,9 @@ makes its *operations* log full detail; it does not 
retroactively add header/bod
 | `FINE` | Basic **+** request/response headers. |
 | `FINEST` | Basic + headers **+** request/response bodies. |
 
+`FINER` resolves through the `FINE` tier (headers), while `CONFIG` resolves 
through `INFO` (basic line only), matching
+JUL `isLoggable(...)` semantics used by the pipeline.
+
 The tier is re-derived at request completion via `isLoggable(...)` against the 
resolved logger, and is stable for
 the life of the request. Content is cumulative — `FINEST` always includes 
everything `FINE` and `INFO` log, in one
 `LogRecord`.
@@ -118,7 +125,7 @@ customization surface is the 
[`RestDebugFormatter`](#the-restdebugformatter-spi)
   happens at all, so requests below `FINEST` pay no buffering overhead.
 - **Phase B (request completion):** the tier is re-derived, the resolved 
`RestDebugFormatter` is invoked
   cumulatively (`formatBasic` always, `+ formatHeaders` at `FINE`-or-finer, `+ 
formatBody` at `FINEST`), header
-  redaction is applied, and exactly one `LogRecord` is emitted at the resolved 
level through the resolved logger.
+  redaction is applied, and exactly one `LogRecord` is emitted at `INFO` 
through the resolved logger.
 - **Bounded capture.** The caching wrapper buffers at most the configured body 
cap (default 8 KB), not the entire
   stream, so memory use is bounded even for large uploads/downloads.
 - **Edge case:** if the logger's level is changed *during* a request (between 
Phase A and Phase B), the two phases
@@ -220,10 +227,30 @@ try (var c = 
RichLogger.getLogger(MyResource.class).captureEvents(Level.FINEST))
 ```
 
 `captureEvents(Level.FINEST)` is the right threshold for 
`.debug()`/`logLevel(FINEST)` mock flows, since debug
-records are emitted at `FINEST`. Pair this with the mock request's 
`logLevel(Level)` helper to set the resolved
+records are emitted at `INFO`, and the capture threshold is `>=`-based. 
`captureEvents(Level.INFO)` is the precise
+threshold; `captureEvents(Level.FINEST)` still captures these records for 
existing tests. Pair this with the mock
+request's `logLevel(Level)` helper to set the resolved
 logger level for one call (and restore it afterward) — the mock equivalent of 
editing `logging.properties` without
 introducing a separate boolean debug flag.
 
+## Spring/back-end notes
+
+- Spring Boot + Logback can propagate `logging.level.*` into JUL through 
`LevelChangePropagator` when enabled.
+- The propagator's inherit-then-parent-change synchronization hole still 
applies: a JUL child logger set to inherit
+  can remain stale after a later parent-level change.
+- For nested resource class names that contain `$`, `logging.level.<fqcn>` 
property keys may need escaping in Spring
+  property sources because `$...` can be interpreted as a placeholder.
+- Backend fallback matrix:
+  - Logback: auto-propagation support.
+  - Log4j2 + `log4j-jul`: JUL facade path works.
+  - Log4j2 without `log4j-jul`: no JUL back-propagation.
+  - Plain JUL / other SLF4J backends: configure JUL directly.
+
+:::danger
+Stable-INFO emission means DEBUG/TRACE-selected headers and bodies now travel 
through INFO sinks. Before dedicated
+payload-hardening controls are enabled, avoid broad DEBUG/TRACE raises on 
production resource loggers.
+:::
+
 ## Migrating from pre-10.0
 
 If you're coming from a pre-10.0 REST debug/logging setup — 
`@Rest(debug=...)`, `@Debug`, `DebugEnablement`,
diff --git a/pages/topics/12.00.JuneauRestServerSpringboot.md 
b/pages/topics/12.00.JuneauRestServerSpringboot.md
index 9def257c49..e58b4f6d46 100644
--- a/pages/topics/12.00.JuneauRestServerSpringboot.md
+++ b/pages/topics/12.00.JuneauRestServerSpringboot.md
@@ -66,6 +66,35 @@ the same property space Spring uses — `application.yaml` / 
`application.proper
 command-line arguments, and any custom Spring `PropertySource`. Spring's 
active profiles are also surfaced
 to Juneau's `juneau.profiles.active` config-profile key. See the cross-links 
below for details.
 
+## Logback level propagation to JUL
+
+When Logback is the active backend, `juneau-rest-server-springboot` 
auto-installs a JUL `LevelChangePropagator`
+listener by default (`juneau.rest.logging.propagate-levels=true`, 
`matchIfMissing=true`) so `logging.level.*`
+changes are reflected into JUL-backed REST debug detail controls.
+
+- Installation is guarded at runtime:
+  - if Logback classes are absent, no install is attempted;
+  - if `ILoggerFactory` is not a Logback `LoggerContext`, it silently no-ops.
+- Disable propagation with `juneau.rest.logging.propagate-levels=false`.
+- The installer is additive and idempotent (it reuses any existing 
`LevelChangePropagator` subtype, and installs
+  at most one reset-resistant listener).
+
+### `reset-jul` posture
+
+`juneau.rest.logging.propagate-levels.reset-jul` defaults to `false` 
(recommended).
+
+- `false` (default): pre-existing JUL logger levels/handlers are preserved.
+- `true`: process-global reset/reapply behavior from Logback's propagator is 
enabled.
+
+When `reset-jul=true`, be explicit about the side effects:
+
+- non-root explicit JUL logger levels are cleared;
+- explicit Logback levels are then propagated back into JUL;
+- JUL-only `logging.properties` entries not mirrored by explicit Logback 
levels do not survive.
+
+For operator-controlled durability across explicit Logback resets, you can 
also install a Logback XML
+`<contextListener>` directly.
+
 ## See also
 
 - [Spring Boot Overview](/docs/topics/SpringBootOverview) — base classes and a 
worked sample application.
diff --git a/pages/topics/27.V10MigrationGuide.md 
b/pages/topics/27.V10MigrationGuide.md
index 6511824f63..ea276b53cc 100644
--- a/pages/topics/27.V10MigrationGuide.md
+++ b/pages/topics/27.V10MigrationGuide.md
@@ -116,7 +116,7 @@ Single-type imports follow the same rename, e.g.:
 | Class-level `@RestInit public void init(RestContext.Builder b) { ... }` hook 
— the framework added the in-flight `RestContext.Builder` to the resource's 
bean store so any `@RestInit` method that declared a `RestContext.Builder` 
parameter received it and could imperatively configure the resource-level 
context (`builder.path(...)`, `builder.children(...)`, `builder.encoders(...)`, 
etc.). | **Removed.** The class-level Builder-injection protocol is gone — 
`RestContext.Builder` is no longe [...]
 | Custom annotation appliers — user code that subclassed the internal 
`AnnotationApplier<Rest, RestContext.Builder>` (or `AnnotationApplier<RestOp, 
RestOpContext.Builder>`) to extend the annotation-processing pass (the 
`apply(AnnotationInfo<A>, B builder)` hook invoked once per annotation during 
context construction). | **Removed.** The builder-based apply-pass is gone; 
`RestAnnotation.Apply` (`RestContextApply`) is now a package-private nested 
class inside `RestContext` and is not exten [...]
 | Custom `RestAnnotation.create(...)` / `RestOpAnnotation.create(...)` 
builder-of-builders patterns — programmatic construction of `@Rest` / `@RestOp` 
annotation proxies used to feed synthetic annotations into the builder 
apply-pass (common in test fixtures and extension libraries). | The annotation 
proxy builders still exist for test use (`RestAnnotation.create()` / 
`RestOpAnnotation.create()` are still available via annotation-test helpers), 
but they no longer feed into a builder apply [...]
-| All prior REST debug/logging mechanisms, in order of vintage: `@Rest(debug)` 
/ `@RestOp(debug)` plain-string attributes; the nested `@Debug` annotation 
(`value()`/`on()`/`format()`/`level()`/`config()`) and its 
`debugDefault`/`debugEnablement`/`debugOn` siblings; 
`DebugEnablement`/`BasicDebugEnablement`/`DebugConfig`/`DebugRule`; and the 
`CallLogger`/`CallLoggerRule`/`BasicCallLogger` logging SPI (including the 
`juneau.restLogger.*` config keys). | **Removed — replaced by a single JUL  
[...]
+| All prior REST debug/logging mechanisms, in order of vintage: `@Rest(debug)` 
/ `@RestOp(debug)` plain-string attributes; the nested `@Debug` annotation 
(`value()`/`on()`/`format()`/`level()`/`config()`) and its 
`debugDefault`/`debugEnablement`/`debugOn` siblings; 
`DebugEnablement`/`BasicDebugEnablement`/`DebugConfig`/`DebugRule`; and the 
`CallLogger`/`CallLoggerRule`/`BasicCallLogger` logging SPI (including the 
`juneau.restLogger.*` config keys). | **Removed — replaced by a single JUL  
[...]
 
 ## REST Debug/Logging Redesign (JUL-Level-Driven `RestDebugFormatter`)
 
@@ -140,6 +140,11 @@ rest-server-only type. It has been **deleted with no 
replacement in 10.0**.
   core marshalling artifact most projects already depend on, not an opt-in 
rest-server module.
 :::
 
+For Spring Boot users: Logback propagation to JUL is default-on for real 
Logback backends
+(`juneau.rest.logging.propagate-levels=true`), additive by default 
(`...reset-jul=false`), and silently no-ops for
+other backends. See 
[juneau-rest-server-springboot](/docs/topics/JuneauRestServerSpringboot) for 
fallback behavior
+and the process-global side effects of opting into `reset-jul=true`.
+
 | Removed | Replacement |
 |---|---|
 | `@Rest(debug=...)` / `@RestOp(debug=...)` and the nested `@Debug` annotation 
(`value()`, `on()`, `format()`, `level()`, `config()`) | No annotation 
replacement. Set your resource's JUL logger level (`INFO`/`FINE`/`FINEST`) 
instead. |

Reply via email to