Skip to content

Fix #99: Add customizable context format and value conversion#140

Open
WarLikeLaux wants to merge 8 commits into
yiisoft:masterfrom
WarLikeLaux:customizable-formatter
Open

Fix #99: Add customizable context format and value conversion#140
WarLikeLaux wants to merge 8 commits into
yiisoft:masterfrom
WarLikeLaux:customizable-formatter

Conversation

@WarLikeLaux
Copy link
Copy Markdown
Contributor

@WarLikeLaux WarLikeLaux commented Mar 24, 2026

Q A
Is bugfix?
New feature? ✔️
Docs added? ✔️
Tests added? ✔️
Breaks BC?
Fixed issues #99

What does this PR do?

Add two constructor parameters to Target (and its subclasses StreamTarget, PsrTarget) for customizing context output:

  • $contextFormat (string|callable|null) - a template string for reordering context sections, or a callable for full control over context rendering
  • $stringConverter (?callable) - custom value-to-string conversion (defaults to VarDumper-based conversion)

Use cases

$stringConverter replaces the default VarDumper-based conversion, for example to JSON-encode all context values:

$target = new StreamTarget(
    stringConverter: static fn(mixed $value): string => json_encode($value, JSON_THROW_ON_ERROR),
);

A $contextFormat template string reorders sections via {trace}, {message}, {common} placeholders. Empty sections are omitted automatically:

$target = new StreamTarget(contextFormat: "{common}{message}{trace}\n");

A $contextFormat callable gives full control over context rendering, including custom headers:

$target = new StreamTarget(
    contextFormat: static function (string $trace, string $messageContext, string $commonContext): string {
        $result = '';
        if ($commonContext !== '') {
            $result .= "\n\nCommon:\n" . $commonContext;
        }
        if ($messageContext !== '') {
            $result .= "\n\nMessage:\n" . $messageContext;
        }
        if ($trace !== '') {
            $result .= "\n\nTrace:\n" . $trace;
        }
        return $result;
    },
);

$contextFormat accepts either a template string or a callable. Default output is unchanged when neither parameter is passed.

Summary by CodeRabbit

  • New Features

    • Added flexible context formatting options: template-based formatting with placeholders and callable-based custom formatting
    • Added configurable value-to-string conversion for context data
  • Documentation

    • Added "Customizing log format" section documenting log formatting configuration options including timestamps, prefixes, and context rendering

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (2e385fb) to head (5ca3646).

Additional details and impacted files
@@             Coverage Diff             @@
##              master      #140   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity       165       174    +9     
===========================================
  Files             11        12    +1     
  Lines            454       486   +32     
===========================================
+ Hits             454       486   +32     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new configuration hooks to customize how log context is rendered and how context values are converted to strings, enabling user-defined context ordering and formatting while keeping the default output unchanged.

Changes:

  • Add setConvertToString(), setContextTemplate(), and setContextFormat() APIs on Target/Formatter and implement precedence rules in formatting.
  • Update formatter context assembly to support template-based section ordering and fully custom rendering via callable.
  • Add/extend tests and documentation covering the new customization options.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Message/Formatter.php Implements custom context formatting/template logic and pluggable value-to-string conversion.
src/Target.php Exposes new formatter customization methods at the target level.
tests/Message/FormatterTest.php Adds coverage for new formatter customization behaviors and precedence/error cases.
tests/TargetTest.php Adds target-level tests for new customization methods.
tests/TestAsset/DummyTarget.php Ensures test target mirrors new formatter customization settings for exported formatting.
README.md Documents new formatting customization options and examples.
CHANGELOG.md Records the new feature in the upcoming release notes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CHANGELOG.md Outdated
Comment thread tests/TargetTest.php
Comment thread README.md Outdated
Comment thread src/Message/Formatter.php Outdated
Comment thread src/Message/Formatter.php Outdated
Comment thread src/Message/Formatter.php Outdated
Comment thread src/Message/Formatter.php Outdated
Comment thread src/Target.php Outdated
Comment thread src/Target.php Outdated
Comment thread src/Target.php Outdated
@WarLikeLaux WarLikeLaux requested a review from samdark March 26, 2026 16:13
@vjik
Copy link
Copy Markdown
Member

vjik commented Mar 28, 2026

@WarLikeLaux resolve conflicts, please

Comment thread src/Target.php
Comment thread src/Message/Formatter.php
Comment thread src/Message/Formatter.php Outdated
Comment thread src/Message/Formatter.php Outdated
Comment thread src/Message/Formatter.php Outdated
@WarLikeLaux WarLikeLaux requested a review from vjik May 31, 2026 09:24
@WarLikeLaux
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR extends the logging system with three new customization methods. setConvertToString() provides pluggable value conversion for context data; setContextTemplate() and setContextFormat() enable flexible context composition via template strings or callables. The changes include a new VarDumperValueConverter utility, significant refactoring of the Formatter class, three new fluent setters in Target, comprehensive test coverage, and documentation updates.

Changes

Context formatting and value conversion customization

Layer / File(s) Summary
Value converter implementation
src/Message/VarDumperValueConverter.php, tests/Message/VarDumperValueConverterTest.php
New VarDumperValueConverter invokable class stringifies context values via __toString() or VarDumper, with tests covering scalars, stringable objects, and objects requiring VarDumper fallback.
Formatter context formatting refactor
src/Message/Formatter.php
Formatter now maintains a $stringConverter callable and flexible $contextFormat setting supporting template strings ({trace}, {message}, {common} placeholders) or callables. The refactored getContext() builds separate message and common context strings, applies the format, and validates string returns; convertToString() delegates to the configurable converter.
Target public configuration API
src/Target.php, tests/TestAsset/DummyTarget.php
Added setContextFormat(), setContextTemplate(), and setConvertToString() fluent setters to Target, each delegating to Formatter equivalents, with corresponding overrides in DummyTarget for export-formatter consistency.
Formatter behavior tests
tests/Message/FormatterTest.php
Added 14 tests covering converter behavior with common context, template placeholders and empty-section omission, callable formatting with empty trace/common strings, template vs callable precedence, converter override of stringable objects, and exception handling for non-string returns.
Target integration tests
tests/TargetTest.php
Added three tests validating Target methods: setConvertToString rendering JSON context values, setContextTemplate composing message and common context via template, and setContextFormat using conditional callable composition.
Documentation and changelog
CHANGELOG.md, README.md
Updated changelog to announce the three new methods; added "Customizing log format" README section documenting all format customization options including format, prefix, timestamp, value conversion, and context template/format with placeholder descriptions and precedence rules.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 With whiskers twitching, I hop through the logs,
Converting values, templates that jog,
Format and common, now flexibly blessed,
Context customized—a logger's request!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The PR title accurately describes the main feature: adding customizable context format and value conversion mechanisms to the logging system.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/TargetTest.php (1)

261-320: ⚡ Quick win

Cover the non-exported path for these new setters.

All three tests go through collectOneAndExport(), so they only exercise DummyTarget::$exportFormatter. If a future change stopped delegating to parent::setContextFormat(), parent::setContextTemplate(), or parent::setConvertToString(), these tests would still pass while buffered, non-exported formatting regressed. Please add a collect(..., false) assertion here or a dedicated test for the non-exported path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/TargetTest.php` around lines 261 - 320, Tests only exercise the
exported path via collectOneAndExport() and DummyTarget::$exportFormatter; add
coverage for the non-exported (buffered) path by invoking collect(..., false) or
a dedicated test that calls collect with export=false and then asserting the
buffered formatting result (e.g. call formatMessages() or the buffer accessor)
to match the same expected strings; update the tests testSetConvertToString,
testSetContextTemplate, and testSetContextFormat (or add a new test) to call
collect($level, $message, $context, false) or collect(..., false) after
configuring setConvertToString, setContextTemplate, and setContextFormat so you
verify parent::setConvertToString / parent::setContextTemplate /
parent::setContextFormat behavior for the non-exported path as well.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Message/Formatter.php`:
- Around line 298-299: The current return expression in Formatter.php appends a
trailing "\n" unconditionally, causing a stray newline when $messageSection and
$commonContextString (and trace) are empty; update the return so the trailing
newline is only added when there is at least one non-empty context piece (i.e.
when $messageSection !== '' || $commonContextString !== '' || trace exists).
Concretely, adjust the return that uses $messageSection and $commonContextString
to concatenate the separator/newline only when one of those variables (or the
trace output) is non-empty so the method returns an empty string when there is
no context. Ensure you reference and use the existing $messageSection and
$commonContextString variables (and the trace check used earlier in this method)
when constructing the final string.

---

Nitpick comments:
In `@tests/TargetTest.php`:
- Around line 261-320: Tests only exercise the exported path via
collectOneAndExport() and DummyTarget::$exportFormatter; add coverage for the
non-exported (buffered) path by invoking collect(..., false) or a dedicated test
that calls collect with export=false and then asserting the buffered formatting
result (e.g. call formatMessages() or the buffer accessor) to match the same
expected strings; update the tests testSetConvertToString,
testSetContextTemplate, and testSetContextFormat (or add a new test) to call
collect($level, $message, $context, false) or collect(..., false) after
configuring setConvertToString, setContextTemplate, and setContextFormat so you
verify parent::setConvertToString / parent::setContextTemplate /
parent::setContextFormat behavior for the non-exported path as well.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1bf644a5-c169-46ad-a11c-5e03017d83f4

📥 Commits

Reviewing files that changed from the base of the PR and between e6aa6b8 and 3195398.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • README.md
  • src/Message/Formatter.php
  • src/Message/VarDumperValueConverter.php
  • src/Target.php
  • tests/Message/FormatterTest.php
  • tests/Message/VarDumperValueConverterTest.php
  • tests/TargetTest.php
  • tests/TestAsset/DummyTarget.php

Comment thread src/Message/Formatter.php
@WarLikeLaux WarLikeLaux changed the title Add customizable context format and value conversion Fix #99: Add customizable context format and value conversion May 31, 2026
@vjik
Copy link
Copy Markdown
Member

vjik commented May 31, 2026

Waiting #146

@samdark
Copy link
Copy Markdown
Member

samdark commented Jun 7, 2026

@WarLikeLaux would you please rebase it?

@WarLikeLaux
Copy link
Copy Markdown
Contributor Author

@samdark done 🫡

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.

4 participants