Developer Guide
This section covers the data model, configuration reference, log capture pipeline, and extension points available to developers integrating Activity Log into an application.
Data Model
Activity Log persists six core entities. An activity log record holds a single captured log event. An extractor defines the rules that determine which log events are saved. A remover defines the rules that determine when old records are deleted. A log viewer defines a saved view configuration used to display logs. A logger filter and a timestamp filter are reusable filter components shared by both extractors and removers.
---
config:
layout: elk
---
erDiagram
al_activitylog {
integer id PK
timestamp timestamp
varchar logger
varchar detail
varchar level
text stacktrace
varchar session_id
}
al_extractor {
integer id PK
varchar name
boolean active
varchar levels
boolean save_stacktrace
boolean save_session_id
}
al_remover {
integer id PK
varchar name
varchar expiration_unit
integer expiration_value
boolean active
varchar levels
}
al_log_viewer {
integer id PK
varchar title
varchar levels_filter
varchar logger_filter
varchar detail_filter
varchar route
timestamp start_date_time_filter
timestamp end_date_time_filter
boolean show_timestamp_column
boolean show_logger_column
boolean show_level_column
boolean show_detail_column
boolean show_stacktrace_column
boolean show_session_id_column
boolean show_timestamp_filter
boolean show_detail_filter
boolean session_filter_enabled
boolean live_enabled
}
al_logger_filter {
integer id PK
varchar type
varchar regex_pattern
}
al_timestamp_filter {
integer id PK
varchar filter_type
date since_date
date until_date
time from_time
time to_time
varchar days_of_week
}
al_extractor ||--o{ al_extractor_logger_filters : "logger filters"
al_extractor ||--o{ al_extractor_detail_filters : "detail filters"
al_extractor ||--o{ al_extractor_timestamp_filters : "timestamp filters"
al_remover ||--o{ al_remover_logger_filters : "logger filters"
al_remover ||--o{ al_remover_detail_filters : "detail filters"
al_remover ||--o{ al_remover_timestamp_filters : "timestamp filters"
al_extractor_logger_filters }o--|| al_logger_filter : ""
al_extractor_detail_filters }o--|| al_logger_filter : ""
al_remover_logger_filters }o--|| al_logger_filter : ""
al_remover_detail_filters }o--|| al_logger_filter : ""
al_extractor_timestamp_filters }o--|| al_timestamp_filter : ""
al_remover_timestamp_filters }o--|| al_timestamp_filter : ""
Database Schema
Activity Log manages twelve tables. The schema below represents the DDL generated by Hibernate for a standard relational database.
CREATE TABLE al_activitylog (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
timestamp TIMESTAMP(6),
logger VARCHAR(255),
detail VARCHAR(255),
level VARCHAR(255),
stacktrace TEXT,
session_id VARCHAR(255),
CONSTRAINT pk_al_activitylog PRIMARY KEY (id)
);
CREATE TABLE al_logger_filter (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
type VARCHAR(255),
regex_pattern VARCHAR(255),
CONSTRAINT pk_al_logger_filter PRIMARY KEY (id)
);
CREATE TABLE al_timestamp_filter (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
filter_type VARCHAR(255),
since_date DATE,
until_date DATE,
from_time TIME,
to_time TIME,
days_of_week VARCHAR(255),
CONSTRAINT pk_al_timestamp_filter PRIMARY KEY (id)
);
CREATE TABLE al_extractor (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name VARCHAR(255) NOT NULL,
active BOOLEAN,
levels VARCHAR(255),
save_stacktrace BOOLEAN,
save_session_id BOOLEAN,
CONSTRAINT pk_al_extractor PRIMARY KEY (id),
CONSTRAINT uq_al_extractor_name UNIQUE (name)
);
CREATE TABLE al_remover (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name VARCHAR(255) NOT NULL,
expiration_unit VARCHAR(255),
expiration_value INTEGER,
active BOOLEAN,
levels VARCHAR(255),
CONSTRAINT pk_al_remover PRIMARY KEY (id),
CONSTRAINT uq_al_remover_name UNIQUE (name)
);
CREATE TABLE al_log_viewer (
id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
title VARCHAR(255),
levels_filter VARCHAR(255),
logger_filter VARCHAR(255),
detail_filter VARCHAR(255),
route VARCHAR(255),
start_date_time_filter TIMESTAMP(6),
end_date_time_filter TIMESTAMP(6),
show_timestamp_column BOOLEAN,
show_logger_column BOOLEAN,
show_level_column BOOLEAN,
show_detail_column BOOLEAN,
show_stacktrace_column BOOLEAN,
show_session_id_column BOOLEAN,
show_timestamp_filter BOOLEAN,
show_detail_filter BOOLEAN,
session_filter_enabled BOOLEAN NOT NULL DEFAULT FALSE,
live_enabled BOOLEAN NOT NULL DEFAULT FALSE,
CONSTRAINT pk_al_log_viewer PRIMARY KEY (id)
);
CREATE TABLE al_extractor_logger_filters (
extractor_entity_id INTEGER NOT NULL,
logger_filters_id INTEGER NOT NULL,
CONSTRAINT fk_al_extractor_logger_filters_extractor FOREIGN KEY (extractor_entity_id) REFERENCES al_extractor (id),
CONSTRAINT fk_al_extractor_logger_filters_logger_filter FOREIGN KEY (logger_filters_id) REFERENCES al_logger_filter (id)
);
CREATE TABLE al_extractor_detail_filters (
extractor_entity_id INTEGER NOT NULL,
detail_filters_id INTEGER NOT NULL,
CONSTRAINT fk_al_extractor_detail_filters_extractor FOREIGN KEY (extractor_entity_id) REFERENCES al_extractor (id),
CONSTRAINT fk_al_extractor_detail_filters_logger_filter FOREIGN KEY (detail_filters_id) REFERENCES al_logger_filter (id)
);
CREATE TABLE al_extractor_timestamp_filters (
extractor_entity_id INTEGER NOT NULL,
timestamp_filters_id INTEGER NOT NULL,
CONSTRAINT fk_al_extractor_timestamp_filters_extractor FOREIGN KEY (extractor_entity_id) REFERENCES al_extractor (id),
CONSTRAINT fk_al_extractor_timestamp_filters_timestamp_filter FOREIGN KEY (timestamp_filters_id) REFERENCES al_timestamp_filter (id)
);
CREATE TABLE al_remover_logger_filters (
remover_entity_id INTEGER NOT NULL,
logger_filters_id INTEGER NOT NULL,
CONSTRAINT fk_al_remover_logger_filters_remover FOREIGN KEY (remover_entity_id) REFERENCES al_remover (id),
CONSTRAINT fk_al_remover_logger_filters_logger_filter FOREIGN KEY (logger_filters_id) REFERENCES al_logger_filter (id)
);
CREATE TABLE al_remover_detail_filters (
remover_entity_id INTEGER NOT NULL,
detail_filters_id INTEGER NOT NULL,
CONSTRAINT fk_al_remover_detail_filters_remover FOREIGN KEY (remover_entity_id) REFERENCES al_remover (id),
CONSTRAINT fk_al_remover_detail_filters_logger_filter FOREIGN KEY (detail_filters_id) REFERENCES al_logger_filter (id)
);
CREATE TABLE al_remover_timestamp_filters (
remover_entity_id INTEGER NOT NULL,
timestamp_filters_id INTEGER NOT NULL,
CONSTRAINT fk_al_remover_timestamp_filters_remover FOREIGN KEY (remover_entity_id) REFERENCES al_remover (id),
CONSTRAINT fk_al_remover_timestamp_filters_timestamp_filter FOREIGN KEY (timestamp_filters_id) REFERENCES al_timestamp_filter (id)
);
al_activitylog, al_logger_filter, and al_timestamp_filter use GENERATED BY DEFAULT AS IDENTITY rather than sequence-based generation, reflecting the use of GenerationType.IDENTITY in those entities. The level column stores the string representation of the AuditLevel enum. The levels column in al_extractor and al_remover stores a comma-separated list of AuditLevel values. The expiration_unit column stores the string representation of a ChronoUnit value. The days_of_week column in al_timestamp_filter stores a comma-separated list of DayOfWeek values. The stacktrace column in al_activitylog is mapped as a large text column (unbounded length) rather than a fixed VARCHAR, so full stack traces are stored without truncation and without relying on database large-object handling.
Instant-based timestamps (al_activitylog.timestamp and the al_log_viewer date-time filter bounds) are persisted as absolute points in time (UTC) and rendered in the browser's time zone by the views. Storing instants rather than local date-time strings keeps ordering and range filtering correct regardless of the time zone of the server or of the user viewing the data.
Both al_logger_filter and al_timestamp_filter are referenced by extractor and remover join tables: each entity uses a dedicated set of join tables to avoid cross-contamination of filter associations. The al_logger_filter type covers both logger-name matching and detail-content matching, distinguished by the type column storing the LoggerFilterType enum value.
Module Overview
Activity Log is structured as six Maven modules following the AppJars layered architecture:
| Module | Artifact ID | Description |
|---|---|---|
| Model | appjars-activity-log-model |
DTOs, enums, auto-configuration |
| Business API | appjars-activity-log-business |
ActivityLogService, ExtractorService, RemoverService, LogViewerService interfaces |
| Business Impl | appjars-activity-log-business-impl |
Service implementations, ActivityLogAppender, ActivityLogAppendersConnector, ExpiredLogsPruner |
| Data API | appjars-activity-log-data |
ActivityLogDao, ExtractorDao, RemoverDao, LogViewerDao interfaces |
| Data Impl | appjars-activity-log-data-impl |
JPA entities and DAO implementations |
| Flow UI | appjars-activity-log-flow-free-it |
Vaadin views and route configuration |
A monolithic application includes the three implementation modules (-business-impl, -data-impl, -flow-free-it). The API modules (-business, -data) are pulled in transitively.
Spring Auto-Configuration
Activity Log registers itself through Spring Boot's auto-configuration mechanism. The entry point is ActivityLogAutoConfiguration, declared in:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
This class scans the com.appjars.activitylog package for all Spring components and JPA entities. On startup, ActivityLogAppendersConnector initialises a BlockingQueue with the configured capacity and starts a background consumer thread that drains the queue and persists log records via ActivityLogService. The Log4j2 custom appender (ActivityLogAppender) is registered through the standard Log4j2 plugin mechanism and begins forwarding events to the connector as soon as logging is active.
Log Capture Pipeline
Activity Log captures log events through a three-stage pipeline that sits outside the standard Spring request lifecycle:
flowchart TD
A[Application Code] -->|log statement| B[Log4j2]
B -->|plugin appender| C[ActivityLogAppender]
C -->|offer| D[BlockingQueue\ncapacity 1000]
D -->|consumer thread| E[ActivityLogAppendersConnector]
E -->|extractor matching| F{Active extractor\nmatches?}
F -->|yes| G[ActivityLogService.save]
F -->|no| H[discard]
G --> I[(al_activitylog)]
ActivityLogAppender is a Log4j2 plugin appender declared in log4j2.xml. It receives every log event that passes through the Log4j2 pipeline and offers it to the connector's queue. Events offered to a full queue are dropped rather than blocking the calling thread.
ActivityLogAppendersConnector maintains a BlockingQueue<LogEvent> and a single background consumer thread. The consumer takes events from the queue, evaluates each against all active extractors, and calls ActivityLogService.save() for every event that matches. If no active extractor matches the event, the record is not persisted.
Extractor matching checks whether the log event's level, logger name, message content, and timestamp fall within the rules defined by each active extractor's filter sets. An event must pass all filter sets on a given extractor to be saved by that extractor.
The queue capacity defaults to 1000 events. Under sustained high-throughput logging, events are dropped when the queue is full. This design prevents logging from blocking application threads, at the cost of potential loss of individual records during traffic spikes.
Startup Buffering
Log events emitted while the application is starting — before the Spring context is ready and the connector is available — would otherwise be lost. To avoid this, ActivityLogAppender holds early events in a bounded pre-context buffer and drains them into the connector once Activity Log becomes active. The buffer is configured with two optional attributes on the <ActivityLogAppender> element in log4j2.xml:
| Attribute | Default | Description |
|---|---|---|
bufferCapacity |
10000 |
Maximum number of startup events held before the oldest entries are evicted |
bufferLevel |
INFO |
Minimum severity level buffered during startup |
When the buffer fills, the oldest entries are dropped. If any events were evicted this way, a single summary record is persisted as an ERROR entry on activation, so the loss is visible in the log itself.
If the ActivityLogAppender is not declared in the logging configuration, the pre-context buffer is never created and startup events are not captured. Capture still works from activation on: Activity Log verifies the logging setup when the Spring context refreshes and repairs the configuration if needed — registering a fallback appender on the root logger, attaching a declared-but-unreferenced appender, or replacing an appender copy loaded by a different classloader. A setup no repair can save (wrong LogManager provider or wrong SLF4J binding) fails the startup instead. See Logging Requirements for the verification and repair rules and the properties that control them.
Logging Requirements
This section describes what the application's classpath must provide for capture to work, how those requirements are verified at startup, and how to diagnose a setup where logs are not being captured.
Supported logging backends
As of 2.0.0, Log4j2 is the only supported logging backend, and the requirements below are enforced at startup. Support for capturing through other backends (such as Logback, or directly at the SLF4J level) is under consideration for a future release.
The Two Requirements
For Activity Log to capture anything, two conditions must both hold at runtime:
-
log4j-core must be the active
LogManagerprovider. The appender is a Log4j2 plugin: if another provider wins (typicallylog4j-to-slf4j, which redirects the Log4j2 API to SLF4J), the Log4j2 configuration file is never read and the appender never receives a single event. -
log4j-slf4j2-impl must own the SLF4J binding. Most application logging — Spring, Hibernate, Vaadin, and most libraries — is emitted through the SLF4J API, not the Log4j2 API. If another binding owns SLF4J (typically
logback-classic), those events go to Logback and never reach Log4j2, even when requirement 1 holds. The appender then looks perfectly healthy while capturing almost nothing.
Both problems have the same root cause: spring-boot-starter-logging (Spring Boot's default) brings log4j-to-slf4j and logback-classic to the classpath.
Setting Up the Classpath
Add the Log4j2 starter and exclude the default logging starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Every starter needs its own exclusion
spring-boot-starter-logging is a transitive dependency of every Spring Boot starter. The exclusion must be repeated on each starter the application declares — spring-boot-starter-web, spring-boot-starter-actuator, and so on. A single missed starter silently reintroduces the conflicting jars.
Do not place the exclusion on the spring-boot-dependencies BOM in <dependencyManagement>: Maven ignores <exclusions> on a dependency imported with <scope>import</scope>, so that exclusion has no effect at all while appearing to provide blanket coverage.
To verify the result, resolve the dependency tree and confirm that neither log4j-to-slf4j nor logback-classic appears:
mvn dependency:tree -Dincludes="*:log4j-to-slf4j,*:logback-classic"
To keep the classpath from regressing when new starters are added later, the ban can be enforced at build time:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.6.2</version>
<executions>
<execution>
<id>ban-spring-boot-starter-logging</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<excludes>
<exclude>org.springframework.boot:spring-boot-starter-logging</exclude>
</excludes>
</bannedDependencies>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Startup Verification (Fail Fast)
Since 2.0.0, both requirements are verified when Activity Log activates (on the Spring context refresh). If either one fails, the application fails to start with a message naming the problem and the exact exclusion to add. A silently empty activity log is treated as worse than a loud boot error.
If you need the application to start anyway — accepting that activity logging will capture nothing or almost nothing — the failure can be downgraded to a warning:
com.appjars.activitylog.appender.strict=false
Why Activity Log does not force Log4j2 itself
A library could try to win the provider conflict programmatically (for example by shipping log4j2.component.properties or setting log4j.provider). This was evaluated and rejected: it restores logging emitted through the Log4j2 API, but the SLF4J binding — which carries nearly all real application logging — would still belong to Logback, so the logs would keep disappearing while the warning went silent. Fixing the classpath is the only correct solution, so that is what the startup error asks for.
Appender Registration and Self-Repair
The recommended setup declares the appender in log4j2.xml, as shown in Getting Started. Declaring it enables startup buffering: events emitted before the Spring context is ready are held in a bounded buffer and persisted once Activity Log activates.
On activation, Activity Log inspects the Log4j2 configuration and repairs common problems:
- Appender not present (not declared, or the plugin was not discovered — see IDE builds): a fallback appender is registered on the root logger, with a warning. Capture works from that point on, but startup events were not buffered.
- Appender declared but not referenced by any
<AppenderRef>: the declared appender is attached to the root logger, with a warning suggesting the missing reference. - Appender loaded by a different classloader (IDE hot-restart, classloader isolation): the unreachable copy is replaced by a reachable instance, preserving its name, filter, and logger attachments — including each
<AppenderRef>'slevelandfilter.
The first two repairs change what the configuration captures (they attach an unfiltered appender to the root logger). An application that prefers to keep its logging configuration untouched can decline them:
com.appjars.activitylog.appender.autoRegister=false
With auto-registration declined and no appender configured, activity logging stays inert and only the warning is emitted.
IDE Builds and Plugin Discovery
Log4j2 discovers plugins through a Log4j2Plugins.dat descriptor generated by an annotation processor during compilation. Maven builds run it automatically, but Eclipse JDT-based compilers (including the Eclipse IDE and VS Code Java tooling) have annotation processing disabled by default — which historically produced the confusing symptom of an application that captures logs when launched with mvn spring-boot:run but not from the IDE.
Two safeguards cover this case:
- The
packages="com.appjars.activitylog.business.service"attribute on<Configuration>(part of the recommendedlog4j2.xml) lets Log4j2 find the appender without the descriptor. - Even if discovery fails entirely, the fallback registration described above kicks in on activation.
Troubleshooting
| Startup message | Cause | Fix |
|---|---|---|
Log4j2 core is not the active logging implementation (LogManager resolved to ...) |
log4j-to-slf4j is on the classpath and outranks log4j-core as provider |
Exclude spring-boot-starter-logging from the starter that introduced it |
The SLF4J binding is ..., so logs emitted through the SLF4J API ... cannot be captured |
logback-classic (or another binding) owns the SLF4J binding instead of log4j-slf4j2-impl |
Exclude spring-boot-starter-logging from the starter that introduced it |
ActivityLogAppender was not found in the Log4j2 configuration |
The appender is not declared in log4j2.xml, or the plugin was not discovered (IDE build without annotation processing) |
Declare the appender and keep the packages attribute on <Configuration>; capture still works through the fallback, but without startup buffering |
ActivityLogAppender is declared in the Log4j2 configuration but no logger references it |
<ActivityLogAppender> exists under <Appenders> but no <AppenderRef> points to it |
Add <AppenderRef ref="ActivityLogAppender"/> to the intended <Root>/<Logger> |
The configured ActivityLogAppender was loaded by a different classloader |
IDE hot-restart or classloader isolation created an unreachable appender copy | Automatic — the copy is replaced; note the replaced copy's startup buffer is not recovered |
N activity log(s) were discarded during startup (persisted as an ERROR record) |
The startup buffer filled before the Spring context was ready | Increase bufferCapacity or raise bufferLevel on <ActivityLogAppender> |
Expired Log Pruning
ExpiredLogsPruner is a Spring-managed @Component that runs on a configurable schedule and deletes log records that have exceeded the expiration window defined by active removers. It processes up to a configurable maximum number of records per round to bound the size of each delete operation.
The pruner is enabled by default and can be disabled by setting com.appjars.activitylog.logspruner.removalEnabled to false. When disabled, old records accumulate indefinitely unless deleted manually or through ActivityLogService.deleteExpiredLogs().
Configuration Properties
Log Capture
| Property | Default | Description |
|---|---|---|
com.appjars.activitylog.appendersconnector.queueCapacity |
1000 |
Maximum number of log events held in the capture queue before events are dropped |
com.appjars.activitylog.appender.strict |
true |
Fail the application startup when the logging setup cannot be captured — see Logging Requirements |
com.appjars.activitylog.appender.autoRegister |
true |
Allow Activity Log to register or re-attach its appender on activation — see Logging Requirements |
Log Pruning
| Property | Default | Description |
|---|---|---|
com.appjars.activitylog.logspruner.removalEnabled |
true |
Whether the expired logs pruner runs automatically |
com.appjars.activitylog.logspruner.prunningFrecuency |
5000 |
Interval in milliseconds between pruning rounds |
com.appjars.activitylog.logspruner.maxLogsPerRound |
500 |
Maximum number of records deleted in a single pruning round |
Display Formatting
| Property | Default | Description |
|---|---|---|
com.appjars.activitylog.dateformat |
dd-MM-yy |
Date format pattern used in log viewer columns |
com.appjars.activitylog.timeformat |
HH:mm |
Time format pattern used in log viewer columns |
com.appjars.activitylog.datetimeformat |
dd-MM-yyyy HH:mm:ss |
Combined date-time format pattern used in log viewer columns |
View URLs
| Property | Default | Description |
|---|---|---|
com.appjars.activitylog.url.activitylogview |
al/activitylog |
URL path of the activity log view |
com.appjars.activitylog.url.extractorsview |
al/extractors |
URL path of the extractor list view |
com.appjars.activitylog.url.extractorsview-create |
al/extractors/create |
URL path of the extractor creation view |
com.appjars.activitylog.url.extractorsview-edit |
al/extractors/edit |
URL path of the extractor edit view |
com.appjars.activitylog.url.removersview |
al/removers |
URL path of the remover list view |
com.appjars.activitylog.url.removersview-create |
al/removers/create |
URL path of the remover creation view |
com.appjars.activitylog.url.removersview-edit |
al/removers/edit |
URL path of the remover edit view |
com.appjars.activitylog.url.logviewer |
al/logviewer |
URL path of the log viewer list view |
com.appjars.activitylog.url.logviewer-create |
al/logviewer/create |
URL path of the log viewer creation view |
com.appjars.activitylog.url.logviewer-edit |
al/logviewer/edit |
URL path of the log viewer edit view |
Service API
ActivityLogService
ActivityLogService is the primary interface for accessing and managing log records. It extends CrudService and exposes the following methods specific to the module:
// Persist a single log record
void log(ActivityLogDto activityLog);
// Retrieve a paginated, filtered, and sorted stream of log records
Stream<ActivityLogDto> getLogs(int offset, int limit, ActivityLogFilter filter, List<ActivityLogSort> sortOrder);
// Count log records matching a filter
Integer countLogs(int offset, int limit, ActivityLogFilter filter);
// Delete all records that have exceeded any active remover's expiration window
void deleteExpiredLogs();
// Count records created today
Long countTodayLogs();
deleteExpiredLogs() is the method called by ExpiredLogsPruner on each scheduled round. It can also be called directly from application code when a manual pruning pass is required.
ExtractorService
ExtractorService manages extractor definitions. Key methods beyond standard CRUD:
// Toggle the active state of an extractor
void switchActiveExtractor(ExtractorDto extractor);
// Find an extractor by its unique name
Optional<ExtractorDto> findByName(String name);
Only active extractors participate in event matching. An application with no active extractor saves no log records regardless of how many events flow through the Log4j2 pipeline.
RemoverService
RemoverService manages remover definitions. Key methods beyond standard CRUD:
// Toggle the active state of a remover
void switchActiveRemover(RemoverDto remover);
// Find a remover by its unique name
Optional<RemoverDto> findByName(String name);
Only active removers are evaluated by ExpiredLogsPruner. A remover's expiration window is defined by combining expiration_value (a number) with expiration_unit (a ChronoUnit such as DAYS or HOURS).
LogViewerService
LogViewerService manages saved log viewer configurations. Key methods beyond standard CRUD:
// Find a log viewer by its route path
Optional<LogViewerDto> findByRoute(String route);
// Find a log viewer by its display title
Optional<LogViewerDto> findByTitle(String title);
Each log viewer record stores both the filter state and the column visibility configuration for a specific view route, allowing multiple independently configured log displays to coexist in the same application.
Customisation
Assigning a Router Layout
By default, Activity Log registers its views without a parent layout. To wrap them in the application's main layout, inject the RouteConfigurer bean using its qualifier and call setViewsRouterLayout in a @PostConstruct method:
@Autowired
@Qualifier("ActivityLogRouteConfigurer")
private RouteConfigurer routeConfigurer;
@PostConstruct
public void configure() {
routeConfigurer.setViewsRouterLayout(MainLayout.class);
}
The @Qualifier is required because multiple AppJars may contribute a bean named RouteConfigurer.
Customising View URLs
The default URL paths can be overridden in application.properties:
com.appjars.activitylog.url.activitylogview=myapp/activity
com.appjars.activitylog.url.extractorsview=myapp/activity/extractors
com.appjars.activitylog.url.removersview=myapp/activity/removers
com.appjars.activitylog.url.logviewer=myapp/activity/viewers
The full list of configurable properties and their defaults is in Configuring View Route Paths.
Tuning the Capture Queue
For applications that generate very high log volumes, the queue capacity and pruning frequency can be adjusted to balance memory use against record loss:
com.appjars.activitylog.appendersconnector.queueCapacity=5000
com.appjars.activitylog.logspruner.prunningFrecuency=60000
com.appjars.activitylog.logspruner.maxLogsPerRound=2000
Increasing the queue capacity reduces the probability of event loss under burst load. Increasing the pruning frequency (in milliseconds) reduces the rate at which the background pruner runs, which lowers database write pressure during periods of heavy activity.