Add a PSR-3 logger, and support any PSR-3 logger#265
Add a PSR-3 logger, and support any PSR-3 logger#265pbowyer wants to merge 18 commits intomodxcms:3.xfrom
Conversation
`initConfig()` sorts out the data, so we don't have to look at `$options` when setting up the logger
|
Thanks for this work, Peter! I will check this out as soon as possible and get some feedback to you. |
opengeek
left a comment
There was a problem hiding this comment.
I'm still considering the necessity of the new methods on the xPDO class. Are these potential overkill? I am wondering if we could simply activate it if a PSR-3 logger was provided in the container… 🤔
|
I agree, how about something like this: 3.x...pbowyer:xpdo:3.x-psr-logger-take2 Or were you thinking more pared back? |
Yeah, that is looking more like what I had in mind. |
resolveLogLocation() in src/xPDO/xPDO.php was added but never used. Keeping it around increases maintenance surface and risk: its logic overwrote any backtrace-derived file with $_SERVER['SCRIPT_NAME'], which would produce misleading log locations if it were ever called. Remove the dead helper to avoid confusion and prevent accidental future use of incorrect location resolution.
When callers omit $file/$line, xPDO::_log() resolves the log location using debug_backtrace(). The default debug_backtrace() captures the full stack (including args), which is unnecessary overhead when we only need the immediate caller's file/line. Use debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3) to keep the same frame indexing used by the existing logic while avoiding deep/arg-heavy traces. This preserves the resulting file/line values in log output while reducing CPU/memory cost.
|
Thanks @opengeek, I've cleaned it up further and merged it into this branch |
Extend the change in c6ab4d9 to xPDOLogger
|
I've also done another "What if..." branch: 3.x...pbowyer:xpdo:3.x-psr-logger-take3 This lets the I've included an optional BC break in a separate commit which removes |
|
Lovely to see this moving! |
|
Nice work @pbowyer ! |
|
FYI @pbowyer — I am experimenting with Copilot reviews on your PR. I'm mostly curious to see the results. Do not take this as feedback to act on immediately. |
There was a problem hiding this comment.
Pull request overview
This pull request adds PSR-3 logging support to xPDO while maintaining 100% backward compatibility. It introduces a lightweight PSR-3 logger implementation (xPDOLogger) that preserves the legacy xPDO logging format, and enables any PSR-3-compliant logger to be registered via the service container.
Changes:
- Added
psr/logdependency and createdxPDOLoggerclass implementing PSR-3 interface with legacy format preservation - Modified
xPDOclass to support logger injection via service container while maintaining legacy logging behavior - Added comprehensive test suites covering historic behavior, fatal logging, and new PSR-3 functionality
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| composer.json | Added psr/log dependency (^1.1||^2.0||^3.0) and monolog dev dependency for testing |
| src/xPDO/xPDO.php | Added logger property and initialization logic, modified _log method to delegate to PSR-3 loggers when available |
| src/xPDO/Logging/xPDOLogger.php | New PSR-3 logger implementation preserving legacy xPDO log format and behavior |
| test/xPDO/Test/Logging/xPDOLoggingHistoricTest.php | Comprehensive tests ensuring legacy behavior is preserved |
| test/xPDO/Test/Logging/xPDOLoggingFatalTest.php | Tests for FATAL level logging with exit behavior |
| test/xPDO/Test/Logging/xPDOLoggerTest.php | Tests for new xPDOLogger functionality and PSR-3 integration |
| test/*.phpunit.xml | Added new test files to test suites |
| * @var array | ||
| */ | ||
| protected $targetOptions = array(); | ||
|
|
There was a problem hiding this comment.
The constructor is missing a docblock. Public methods including constructors should have documentation describing their parameters, especially since this accepts an options array with specific expected keys like 'target' and 'target_options'.
| /** | |
| * xPDOLogger constructor. | |
| * | |
| * @param xPDO $xpdo The xPDO instance used for configuration and debugging. | |
| * @param array $options Optional logger configuration: | |
| * - 'target' (string|array|null): Log destination or destinations. | |
| * - 'target_options' (array): Options specific to the configured target(s). | |
| */ |
src/xPDO/xPDO.php
Outdated
| $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); | ||
| if ($backtrace && isset($backtrace[1])) { | ||
| $file = $backtrace[1]['file']; | ||
| $line = $backtrace[1]['line']; |
There was a problem hiding this comment.
The backtrace depth is incorrect for resolving the caller's file and line. With depth 2, backtrace1 will point to the xPDO::log() method itself, not the actual caller of log().
The call stack is:
- [2]: actual caller (what we want)
This should use depth 3 and access backtrace[2] to get the correct calling location, matching the legacy behavior that was removed from lines 2132+ in the original code.
| $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); | |
| if ($backtrace && isset($backtrace[1])) { | |
| $file = $backtrace[1]['file']; | |
| $line = $backtrace[1]['line']; | |
| $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); | |
| if ($backtrace && isset($backtrace[2])) { | |
| $file = $backtrace[2]['file']; | |
| $line = $backtrace[2]['line']; |
There was a problem hiding this comment.
@copilot code review[agent] Now this one's interesting because the tests pass, and I wrote the tests against the parent branch. So did I get the tests wrong - or have they been silently modified?
| $this->targetOptions = $options['target_options']; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
The public method handleXpdo is missing a docblock. Public methods should have documentation describing their purpose, parameters, and return values, consistent with other public methods in the codebase.
| /** | |
| * Handles logging using the legacy xPDO format. | |
| * | |
| * For fatal log levels, all output buffers are flushed and the script | |
| * exits immediately after writing the formatted log message. For other | |
| * levels, the message is delegated to {@see log()} with a context | |
| * payload that preserves legacy xPDO fields. | |
| * | |
| * @param int|string $level Numeric or string log level (xPDO or PSR-3 style). | |
| * @param string $msg Log message to record. | |
| * @param string $target Optional log target identifier. | |
| * @param string $def Optional log message definition or label. | |
| * @param string $file Optional file name associated with the log entry. | |
| * @param string|int $line Optional line number associated with the log entry. | |
| * | |
| * @return void | |
| */ |
|
Well, that was underwhelming in terms of feedback. 🤔 |
No problem! Unlike the Gemini code review bot, it looks like with Copilot you can't have a conversation about the changes? |
I thought you could by just mentioning it… hmm |
@opengeek can you try as (I assume) the bot's owner? My mention broke into text... |
I guess I am wrong!
|
|
cOpiLOt sUcKs Another open source project I contribute to uses https://developers.google.com/gemini-code-assist/docs/review-github-code which has been rather helpful. Free up to 33 PR a day I believe. And OpenAI has their own too I believe. |
I'm going to reserve judgment for now. I had it review my PR yesterday and it was super insightful. I think you just wrote really good code and it is potentially confused on the backtrace level? 😅 |
|
Mine has already been reviewed by AI multiple times before submitting (and I've got AI reviewing the backtrace level locally to confirm) so that could be the case! Here's an example Gemini code assist review: BadgerHobbs/BinDays-API#182 (review) |
Nice! This is the kind of AI-assisted contribution I love to see. 🙌🏼 |
|
Copilot was right about I've also updated the alternative 'take3' branch: 3.x...pbowyer:xpdo:3.x-psr-logger-take3 (comparison with this PR: pbowyer/xpdo@3.x-psr-logger...pbowyer:xpdo:3.x-psr-logger-take3) |
Context and history
This PR builds on previous efforts to finally resolve those constraints while ensuring 100% backward compatibility.
Goals
Implementation
I have integrated psr/log with a simple default implementation. The logic follows a "opt-in" flow:
I’ve included exhaustive tests in xPDOLoggingHistoricTest.php to ensure no regressions from the current behaviour.
I started by looking at @Mark-H's branch but I wanted to preserve full backwards compatibility, so used it as inspiration rather than building directly on it. In my code MODX logging works exactly as it currently does, until a custom PSR logger is provided. Once a custom PSR logger is provided, it's assumed that you want PSR-3 output and you opt out of the traditional MODX logging.
Request for feedback
xPDO::$logger. Is this acceptable for ease of use, or should we strictly require the service container for access?xPDOthan I wished to, and there is some duplication to support the current xPDO logging behaviours. Is this level of duplication acceptable to keep the "legacy" side untouched?xPDOLoggerhas a dependency onxPDO. It works, but it feels unclean. Would you prefer a different approach?Remaining Todos
xPDOLoggingHistoricTest.phpandxPDOLoggerTest.phpneed rationalising. I am satisfied thatxPDOLoggingHistoricTest.phpis exhaustive