Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Log4Php Laravel Package

apache/log4php

Apache log4php is a flexible logging framework for PHP modeled on log4j. It provides configurable loggers, appenders, layouts, filters, and log levels, with XML, INI, or PHP configuration for routing messages to files, databases, and other destinations.

View on GitHub
Deep Wiki
Context7

Getting Started

Log4php is a port of Log4j: loggers, levels, appenders, and layouts configured from a file rather than from code. In a Laravel app, Monolog already covers this ground, so treat log4php as a legacy-integration or migration tool, not a default choice.

Minimal setup:

composer require apache/log4php

Create a config file (XML is the canonical format) at config/log4php.xml:

<log4php:configuration xmlns:log4php="http://logging.apache.org/log4php/">
  <appender name="rolling" class="LoggerAppenderRollingFile">
    <param name="file" value="/var/www/storage/logs/app.log" />
    <param name="maxFileSize" value="10MB" />
    <param name="maxBackupIndex" value="5" />
    <layout class="LoggerLayoutPattern">
      <param name="conversionPattern" value="%d{Y-m-d H:i:s} %-5p %c %m%n" />
    </layout>
  </appender>
  <rootLogger level="INFO">
    <appender_ref ref="rolling" />
  </rootLogger>
  <logger name="payments" additivity="false">
    <level value="DEBUG" />
    <appender_ref ref="rolling" />
  </logger>
</log4php:configuration>

Bootstrap it once in a service provider (or AppServiceProvider::boot):

use Logger;

public function boot(): void
{
    Logger::configure(base_path('config/log4php.xml'));
}

First use case: an existing module or vendor package already calls Logger::getLogger('...'), or you need log4j-style XML operational config (rolling files, per-package levels) that ops already knows how to edit. For brand-new application logging, use Laravel's Log facade and stop here.

First things to look at in the repo: Logger::configure() entry point, LoggerAppenderFile/RollingFile/DailyFile, LoggerLayoutPattern conversion specifiers, and the LoggerLevel constants. The docs are on the Apache logging site, not in the Laravel ecosystem.

Implementation Patterns

Bootstrap once, per process. Wrap configuration in a singleton/provider and guard it:

$this->app->singleton('log4php', function () {
    Logger::configure(base_path(config('logging.log4php.config')));
    return Logger::getRootLogger();
});

Do not call Logger::configure() on every request or per log call; it re-parses the file each time. Long-running workers (queue, Octane, Sail) parse once at worker boot.

Environment-specific config. Pick the XML file from app()->environment() (log4php.local.xml, log4php.production.xml) and point the file appender at storage_path('logs/...'). Pass paths via config, not hardcoded XML, if you need per-deployment values — generate or template the XML, or use the PHP-array config format which allows env()-style lookup.

Config formats. XML, INI, properties, and a PHP file that returns an array are supported (Logger::configure() accepts the path). The PHP format is the easiest to keep inside Laravel's config system; keep it side-effect free and return the array.

Logger hierarchy. Use dotted logger names (payments.gateway, payments.refund) and set levels at the package level. additivity="false" is how you stop child loggers from also writing to the root appender. Root level should be INFO or WARN in production, DEBUG locally.

Appenders map to Laravel concerns:

  • LoggerAppenderDailyFile / RollingFile — storage/logs, rotation by date or size.
  • LoggerAppenderConsole with php://stdout — Docker/Sail/docker logs.
  • LoggerAppenderSyslog — containers with a log collector.
  • LoggerAppenderPDO / LoggerAppenderMail — rarely worth it; buffered appenders need explicit flushing.
  • LoggerAppenderNull — silencing noisy loggers or tests.

Bridge into Laravel's logging stack instead of letting two logging systems diverge. Two options:

  1. Custom Monolog handler that forwards records to a log4php logger, registered via a custom channel in config/logging.php and Log::extend().
  2. A thin service/facade around Logger::getLogger() injected where needed, so application code calls one API (Log::info()); only the bridge talks log4php.

If legacy code expects PSR-3, write a small PSR-3 adapter that delegates to Logger::getLogger() rather than teaching callers two APIs.

Context data. Use LoggerMDC::put('request_id', $id) and clear it at the end of the request/job; LoggerNDC::push()/pop() for nesting. These are static, so reset them in terminate() or job finally blocks to avoid context bleeding across queue jobs.

Custom extension points. Subclass LoggerAppender (override append()/close()), LoggerLayout (override format()), LoggerFilter (override decide()), or LoggerRenderer for object-to-string mapping. Register custom classes by fully qualified class name in the appender's class attribute — log4php instantiates them reflectively, so constructors must be no-arg.

Testing. Call Logger::resetConfiguration() in tearDown, and point tests at a LoggerAppenderNull or a temp file. Assert on file contents rather than mocking the static Logger API.

Gotchas and Tips

  • Archived and unmaintained. No security or PHP-version fixes. Expect PHP 8.x deprecation notices (implicit nullable parameters, dynamic properties) and no official compatibility statement. Budget for a fork or a pin, and test every PHP upgrade against it. For new code, this is a hard sell against Monolog.
  • Global class names. Classes live in the global namespace (Logger, LoggerAppenderFile, …) with a legacy autoloader. Composer autoloading generally works, but any manual Logger::configure() before vendor/autoload.php loads will fatal. Name collisions with other global-namespace packages are possible.
  • Relative config paths resolve against the current working directory, which is public/ for web requests in a typical Laravel/FPM setup — not the app root. Always use base_path()/storage_path().
  • Static configuration is process-global. In Octane and queue workers, config is read once and reused; config changes require a worker restart. There is no per-request reconfiguration. This is the most common source of "why is my level change not applying?"
  • Rotation concurrency. Multiple PHP-FPM workers or Octane workers writing/rotating the same file can race; size-based rotation is not coordinated across processes. Prefer one file per worker, an external rotator (logrotate), or the daily appender with container-local disks.
  • Level and additivity confusion. A record is filtered twice: by logger level and by appender threshold. If messages disappear, check both, plus additivity on parent loggers. Also check that Logger::getLogger('payments.gateway') is matching the configured payments logger name.
  • Exceptions are not handled like Monolog. There is no Laravel-style report()/render() pipeline or automatic stack-trace formatting. Log $e->getMessage() plus $e->getTraceAsString() explicitly, or verify the pattern layout's throwable support in your version before relying on it.
  • Pattern syntax is log4j, not Monolog. %d{...}, %p, %c, %m, %n — do not paste Monolog format strings. Malformed conversion patterns fail quietly, producing unexpected output.
  • XML config is parsed with SimpleXML. Never accept user-supplied config files (XXE risk). Keep config files in the repo, owned and reviewed.
  • Logger::configure() throws LoggerException for bad XML, missing appenders, or unwritable paths. A bad config at boot will 500 the whole app — wrap it and fail soft with a Monolog fallback rather than dying on logging configuration.
  • Buffered appenders need flushing. Mail/PDO appenders may not emit until Logger::shutdown(); rely on Laravel's terminating callback or call shutdown() explicitly. File appenders should be close()d at process end.
  • No native Laravel channel. You cannot add 'driver' => 'log4php' to config/logging.php without writing a bridge. This means two logging stacks, two sets of config, two retention policies — a real operational cost.
  • Debugging tips. Set the root level to TRACE, attach LoggerAppenderConsole to php://stdout, and run php artisan tinker to confirm configuration and logger names resolve. Check file permissions (storage/logs must be writable by the FPM user and queue worker user alike).
  • Migration path. Keep log4php scoped to legacy modules, emit through a Laravel Log channel for everything new, and plan to delete log4php once the last legacy call sites are converted. Do not introduce it into new Laravel packages.

Bottom line: low stars, zero dependents, archived. Its only defensible day-to-day role in a Laravel codebase is honoring existing log4j-style configuration during a migration window. Everything it does for a typical app — rolling files, JSON/line layouts, level filtering, context — Monolog does with maintained code and native Laravel integration.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums