Skip to content

Added: A site with a VarDir of its own can keep its logs, its INI cache and its expiry timestamps apart from the other sites of the installation - #136

Merged
se7enxweb merged 6 commits into
se7enxweb:mainfrom
fwoldt:feature/project-log-and-cache-paths
Oct 7, 2026
Merged

se7enxweb merged 6 commits into
se7enxweb:mainfrom
fwoldt:feature/project-log-and-cache-paths

Conversation

@fwoldt

@fwoldt fwoldt commented Oct 7, 2026

Copy link
Copy Markdown

What changed

Installations that host several sites, each with a VarDir of its own, can now keep logs, caches and expiry
timestamps apart per site, or move them for all sites at once. Everything is set in site.ini [FileSettings], and
every default keeps today's behaviour.

Setting Effect
UseGlobalLogDir=disabled The debug logs (error.log, warning.log, …), the logs eZLog::write() writes to its default directory and the CSRF refusal log go to the log directory of the site (eZSys::logDirectory()) instead of var/log.
LogDir May be an absolute path, as CacheDir already may. storage.log and the debug bar's log follow it.
LogVarDir, CacheVarDir Put the logs or the caches of every site into a tree of their own with one line: the first directory of VarDir is replaced (var/example → var_log/example, var_cache/example). One memory file system can then hold the caches of all sites.
ExpiryDir Keeps expiry.php outside the cache directory. With the cache on a memory file system, the expiry timestamps survive a restart. Otherwise image aliases created before a clear would count as current again.
INICacheDir=site Caches the INI files of a site in its own cache directory, so clearing the INI cache of one site leaves the others alone.

Velocity and the web servers. Velocity serves the public caches below CacheVarDir (packed scripts and style
sheets, text to image) and nothing else there. expVelocity::staticPaths() adds them for all three engines, and only
for a plain relative directory name. .htaccess_root, .htaccess_root_static, the Apache example and the nginx
guide carry the matching rule, commented out, ready to enable.

Siteaccess changes. eZSiteAccess::change() derives the log directory, the INI cache directory and the expiry
file again on every change. This holds for web requests, REST, the tree menu and scripts (ezcache.php -s <siteaccess>, cronjobs). Nothing is kept in static properties:

  • Velocity: a worker removes these globals between requests, so the next request starts with the defaults.
  • Scripts: a process that changes siteaccess takes the paths of each site from its own site.ini.
  • Multi-site wrappers: an INI cache directory a wrapper set before startup comes back for a site without the
    setting.

The guide doc/features/6.0/multi-site-log-and-cache-paths.md has sample setups (one site with its cache in memory;
many sites with one log tree and one cache tree), what each cache command clears, and the behaviour under Velocity.

New API:

  • eZSys::logDirectory() and eZSys::relocatedVarDirectory()
  • eZDebug::setLogDirectory() and logDirectory()
  • eZExpiryHandler::filePath()
  • eZSiteAccess::updateINICacheDirectory()
  • eZUpdateDebugLogDirectory()
  • expVelocity::staticPaths()

Why

Until now, multi-site hosting had to share more than the code:

  • Logs: every site wrote its debug logs into the same var/log.
  • INI cache: clearing the INI cache of one site removed it for all of them.
  • Cache in memory: the only way was an absolute CacheDir, which site.ini calls unsupported. The files served
    from the cache would leave the served paths, and expiry.php would be lost at every restart.

How it was tested

New tests, all of which fail without the change:

  • eZSiteLogAndExpiryPathsTest (14 tests, no database):
    • the log directory inside VarDir and absolute;
    • LogVarDir and CacheVarDir, relative and absolute;
    • the debug logs, eZLog and storage.log in the log directory;
    • UseGlobalLogDir;
    • ExpiryDir empty, relative, absolute and with a moved cache;
    • timestamps that survive an emptied cache directory.
  • eZSiteAccessSitePathsTest (5 tests, writes temporary siteaccesses, no database):
    • eZSiteAccess::change() to a site with the settings and then to one without, in the same process;
    • the moved trees;
    • a directory the installation set, kept and restored;
    • a new request without the globals a Velocity worker removes.
  • expVelocityEnginesTest: the public caches below CacheVarDir are served and nothing else there. An absolute path,
    .. or other characters are not served.

Existing suites: lib, kernel-classes and security give the same results as main.

Static checks: phpcs reports no new violations; phpstan reports nothing new in the changed files.

On an installation, with one siteaccess with the settings and one without, under nginx with PHP-FPM:

  • Errors went to the log directory of the site with the settings, and to var/log for the other.
  • The INI cache of the site with the settings was written to its own cache directory.
  • ezcache.php -s <siteaccess> wrote the expiry timestamps to ExpiryDir.

Every cache command, cleared and purged (global_ini, ini, tag content, all caches):

  • Each command removed only the cache it names.
  • expiry.php in ExpiryDir was kept by every command and got the new timestamps.
  • The .cleanup-trash directories were empty afterwards.

Multi-site layout: the global override set UseGlobalLogDir=disabled, LogVarDir=var_log,
CacheVarDir=var_cache, INICacheDir=site and ExpiryDir=expiry.

  • Under nginx with PHP-FPM and under Velocity, pages linked their packed style sheets and scripts below
    var_cache/<site>/cache/public/ and got them (200).
  • Other files there were refused (404).
  • Errors went to var_log/<site>/log.
  • Clearing and purging worked on var_cache, while expiry.php stayed in var/<site>/expiry/.

Velocity 0.0.4.45 (engine qbix, 4 persistent workers):

  • 40 requests alternated between two siteaccesses, each worker serving both. All 20 errors of the one were in its log
    directory, all 20 of the other in var/log.
  • 30 further requests to the site without the settings left the other site's INI cache untouched.

Still open

  • Messages written before the siteaccess is known (while a request is matched) still go to var/log.
  • A running Velocity holds settings in memory as before: after clearing an INI cache it needs a restart, as Setup >
    Caches says.
  • Extensions that build a log path from VarDir and LogDir themselves do not follow LogVarDir. They should use
    eZSys::logDirectory().
  • With a cluster file handler, the rewrite rules of index_cluster.php name var/ only. A moved cache would have to
    be added there.

felix added 6 commits October 7, 2026 09:57
…he and its expiry timestamps apart from the other sites of the installation

For multi-site hosting, site.ini [FileSettings] has four settings, all keeping the behaviour of before by default.
UseGlobalLogDir=disabled writes the debug logs, the logs eZLog::write() writes to its default directory and the CSRF
refusal log into the log directory of the site (eZSys::logDirectory()); LogDir may be an absolute path. ExpiryDir
keeps expiry.php outside the cache directory, so a cache on a memory file system mounted at var/<site>/cache does not
lose the expiry timestamps at a restart. INICacheDir=site caches the INI files of the site in its cache directory, so
clearing the INI cache of one site leaves the others alone.

eZSiteAccess::change() derives the log directory, the INI cache directory and the expiry file again on every change,
for web requests, Velocity workers and scripts, and keeps nothing in static properties: a process that serves several
sites one after another takes the paths of each from its own site.ini, and a directory a multi-site wrapper set comes
back for a site without the setting.

Logs on another file system use an absolute LogDir, a cache on a memory file system a mount at its own path, which
keeps the cache files the web server serves at their addresses. Nothing rewrites paths as text.
… INI cache and expiry paths, their tests, settings, guide and changelog
…site of a multi-site installation into a tree of their own with one setting

site.ini [FileSettings] LogVarDir=var_log and CacheVarDir=var_cache replace the first directory of VarDir in the
log and cache directory (eZSys::relocatedVarDirectory()): a site with VarDir=var/example logs to var_log/example/log
and caches in var_cache/example/cache, so one memory file system can hold the caches of all sites. Set once in the
global override, they cover every site; ExpiryDir keeps the expiry timestamps inside VarDir.

Velocity serves the public caches below CacheVarDir (packed scripts and style sheets, text to image) and nothing else
there: expVelocity::staticPaths() adds them for all three engines, and only for a plain relative directory name.
.htaccess_root, .htaccess_root_static and the nginx and Apache examples carry the rule to enable for other servers.

Checked with the settings in the global override of an installation, under nginx with PHP-FPM and under Velocity
0.0.4.45: pages link and get their packed files from var_cache, internal cache files are refused, errors go to
var_log, clearing and purging the caches works on var_cache while expiry.php stays in VarDir.
…heVarDir, the served cache paths of Velocity and the web server rules, their tests, settings, guide and changelog
…scribes how an existing multi-site setup moves to them
se7enxweb added a commit that referenced this pull request Oct 7, 2026
…paths

A site with a VarDir of its own can keep its logs, its INI cache and its
expiry timestamps apart from the other sites of the installation, and
LogVarDir and CacheVarDir move the logs or caches of every site into a tree
of their own. Reviewed in three rounds: the per-site site.ini cache, the
log readers, the audit directory, the deletion guard, Velocity's reading of
every siteaccess and its warm-up were refined, and tests were added.
@se7enxweb
se7enxweb merged commit 38819ba into se7enxweb:main Oct 7, 2026
5 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants