Skip to content

Commit 944fa2d

Browse files
committed
Add static log prefix resolver
1 parent dd056fe commit 944fa2d

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ As a real example of using this framework, see [TabShell](https://github.com/tec
2121
* [Component Lifecycle](#component-lifecycle)
2222
* [Component Tree](#component-tree)
2323
* [Imperative Component Management](#component-imperative)
24+
* [Component Logging](#component-logging)
2425
* [Component Code Example](#component-code)
2526
* [When to Create a Component?](#when-to-create-component)
2627
* [When not to Create a Component?](#when-not-to-create-component)
@@ -322,6 +323,24 @@ tabs, dialogs, or search panels).
322323
This approach ensures that PatternFX components behave predictably, remain testable, and can support complex,
323324
long-living, dynamic UI applications.
324325

326+
### Component Logging <a name="component-logging"></a>
327+
328+
PatternFX supports component-scoped logging, allowing log messages to be produced in the context of a specific
329+
component instance rather than only at the class or subsystem level. This approach is especially useful in complex and
330+
dynamic applications where multiple instances of the same component type may exist simultaneously (for example, tabs,
331+
dialogs, editors, or background components). Component-scoped logging makes it possible to precisely identify the
332+
exact source of a log message and greatly simplifies debugging and diagnostics.
333+
334+
Each component exposes a log prefix that uniquely identifies its instance. This prefix can be obtained via the
335+
`Component#getLogPrefix()` method and is also available to the `ViewModel` through `ComponentMediator#getLogPrefix()`.
336+
337+
In the default implementation (`AbstractComponent`), the log prefix is determined during construction by calling the
338+
protected method `resolveLogPrefix()`. By default, this method delegates to a static
339+
`Function<AbstractComponent<?>, String> logPrefixResolver` (which can be customized), which defines a consistent
340+
application-wide policy for computing log prefixes. This design allows all components to share a uniform logging format
341+
by default, while still enabling subclasses to override `resolveLogPrefix()` and provide a custom log prefix when needed.
342+
The resolved log prefix is stored in the component instance and remains stable for the component's entire lifecycle.
343+
325344
### Component Code Example<a name="component-code"></a>
326345

327346
This example demonstrates the creation of a Foo component that dynamically adds a child Bar component.

patternfx-core/src/main/java/com/techsenger/patternfx/core/AbstractComponent.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package com.techsenger.patternfx.core;
1818

19+
import java.util.Objects;
1920
import java.util.UUID;
21+
import java.util.function.Function;
2022
import javafx.beans.property.ObjectProperty;
2123
import javafx.beans.property.ReadOnlyObjectProperty;
2224
import javafx.beans.property.ReadOnlyObjectWrapper;
@@ -32,14 +34,15 @@ public abstract class AbstractComponent<T extends AbstractComponentView<?, ?>> i
3234

3335
private static final Logger logger = LoggerFactory.getLogger(AbstractComponent.class);
3436

35-
private static String logDelimiter = " :";
37+
private static Function<AbstractComponent<?>, String> logPrefixResolver = (c) -> "[" + c.getFullName() + "]";
3638

37-
public static String getLogDelimiter() {
38-
return logDelimiter;
39+
public static Function<AbstractComponent<?>, String> getLogPrefixResolver() {
40+
return logPrefixResolver;
3941
}
4042

41-
public static void setLogDelimiter(String logDelimiter) {
42-
AbstractComponent.logDelimiter = logDelimiter;
43+
public static void setLogPrefixResolver(Function<AbstractComponent<?>, String> logPrefixResolver) {
44+
Objects.requireNonNull(logPrefixResolver, "logPrefixResolver can't be null");
45+
AbstractComponent.logPrefixResolver = logPrefixResolver;
4346
}
4447

4548
protected class Mediator implements ComponentMediator {
@@ -141,7 +144,7 @@ public AbstractComponent(T view) {
141144
long least32bits = uuid.getLeastSignificantBits() & 0xFFFFFFFFL;
142145
String shortUuid = String.format("%08X", least32bits);
143146
this.fullName = getName().getText() + "@" + shortUuid;
144-
this.logPrefix = resolveLogPrefix(fullName);
147+
this.logPrefix = resolveLogPrefix();
145148
}
146149

147150
@Override
@@ -253,8 +256,8 @@ public final void deinitialize() {
253256
}
254257
}
255258

256-
protected String resolveLogPrefix(String fullName) {
257-
return fullName + logDelimiter;
259+
protected String resolveLogPrefix() {
260+
return getLogPrefixResolver().apply(this);
258261
}
259262

260263
/**

0 commit comments

Comments
 (0)