Imported from Jahia/tomcat-log-provider (
AGENTS.md). Install upstream withnpx skills add Jahia/tomcat-log-provider. Copyright stays with the author.
tomcat-log-provider
Jahia OSGi module that mounts Tomcat log files as a JCR virtual filesystem via an ExternalContentStoreProvider (VFS2 over the local filesystem). Provides a live log viewer for jahia.log. Admin UI at /jahia/administration/tomcatLogProvider and /jahia/administration/tomcatLogViewer.
Key Facts
- artifactId:
tomcat-log-provider(module key:tomcatLogProvider) - Java package:
org.jahia.community.external.tomcat.log(GraphQL extensions in.graphqlsub-package) - jahia-depends:
default,external-provider,graphql-dxm-provider(defined inpom.xmlproperties) - OSGi config PID:
org.jahia.modules.tomcatlogprovider(set via@Component property = SERVICE_PID + "=...") - OSGi DS annotations scan:
_dsannotations = org.jahia.community.external.tomcat.log.*(in pom.xml maven-bundle-plugin) logPath— resolved from${catalina.base}/logsat runtime (read-only)mountPath— configurable; default:/sites/systemsite/files/tomcat-logs
Architecture
| Class | Role |
|---|---|
TomcatLogMountPointService |
Merged ManagedService + mount lifecycle; updated(), remount(), @Deactivate |
TomcatLogDataSource |
ExternalDataSource; maps VFS2 FileObject → ExternalData for log files/folders |
TomcatLogBinaryImpl |
JCR Binary impl over VFS2 FileContent for streaming log file bytes |
TomcatLogProviderGraphQLExtensionsProvider |
Registers GraphQL extensions |
TomcatLogProviderQueryExtension |
GraphQL settings query + log tail query |
TomcatLogProviderMutationExtension |
GraphQL save mutation |
TomcatLogMountPointService creates new ExternalContentStoreProvider(), sets dynamicallyMounted = false.
VFS2 root: StandardFileSystemManager.resolveFile("file:" + logPath).
GraphQL API
All operations are nested under a single hierarchical tomcatLog namespace on the
root Query/Mutation types (one field on each, returning TomcatLogProviderQuery /
TomcatLogProviderMutation) — not flat root fields.
| Operation | Path | Notes |
|---|---|---|
| Query | tomcatLog { settings { mountPath, logPath } } |
logPath is read-only |
| Query | tomcatLog { tail(lines?) } → [String] |
Returns last N lines of jahia.log (default 200, capped 5000); used for live tail polling |
| Mutation | tomcatLog { saveSettings(mountPath!) } → Boolean |
Writes config + triggers remount |
All operations require the tomcatLogProviderAdmin permission (shipped via the
tomcat-log-provider-administrator role in src/main/import/roles.xml), enforced with
@GraphQLRequiresPermission("tomcatLogProviderAdmin").
Admin UI
Two-level admin route structure:
- Parent group:
tomcatLogatadministration-server:99(isSelectable: false) - Config panel:
tomcatLogProvideratadministration-server-tomcatLog:1→/jahia/administration/tomcatLogProvider - Log viewer:
tomcatLogVieweratadministration-server-tomcatLog:2→/jahia/administration/tomcatLogViewer
CSS prefix: tlp_.
Input id: #tlp-mount-path.
Features
- Save button + Ctrl+Enter shortcut (fires when field non-empty)
- Browse in jContent button: converts
/sites/{siteKey}/files{rest}→/jahia/jcontent/{siteKey}/en/media/files{rest}; disabled when mount path doesn't match/sites/*/files/* - URL derived from component state (not Apollo cache) — avoids stale URL after mutation
- Live tail viewer: polls the
tomcatLog { tail }query, auto-scrolls to bottom; pauses when user scrolls up
Build
mvn clean install
yarn build
yarn lint
Tests (Cypress Docker)
cd tests
cp .env.example .env
yarn install
./ci.build.sh && ./ci.startup.sh
- Tests:
tests/cypress/e2e/01-tomcatLogProvider.cy.ts - Tests cover: GraphQL API (settings fields, roundtrip), log file JCR node, admin UI (configuration + log viewer), Browse in jContent, Ctrl+Enter
cy.window().then(win => cy.stub(win, 'open').as('windowOpen'))used to test Browse in jContent without opening new tab
Gotchas
${catalina.base}/logsmust be accessible from within the Jahia JVM; path is resolved at@Activatetime — if Tomcat logs are in a non-standard location, the mount will appear empty- Provisioning manifests use bare filenames (
include: 'provisioning.yml') — Jahia engine prependsassets/automatically; do not add the prefix - CSS Modules in Cypress: match with
[class*="tlp_..."] - The parent route (
tomcatLog) hasisSelectable: false— it's a group node only; both child routes must be clicked individually in the admin sidebar