Skip to content

[Laravel] Add opt-in context flattening for faceted log search#560

Open
nickmarden wants to merge 2 commits into
open-telemetry:mainfrom
nickmarden:feature/laravel-log-context-flatten
Open

[Laravel] Add opt-in context flattening for faceted log search#560
nickmarden wants to merge 2 commits into
open-telemetry:mainfrom
nickmarden:feature/laravel-log-context-flatten

Conversation

@nickmarden
Copy link
Copy Markdown
Contributor

Description

This PR restores the context-flattening feature from #491 (which was reverted in #559 due to a conflict with #511), now correctly layered on top of the structured-array default that #511 introduced.

Background

PR #491 identified a real observability problem: the Laravel LogWatcher was JSON-encoding the entire log context into a single context string attribute, making it impossible to filter by specific values in backends like SigNoz, Jaeger, or Grafana. For example, given context {"http": {"method": "GET", "path": "/users"}, "user_id": "123"}, there was no way to query http.method = "GET" as a facet.

PR #491 solved this with an opt-in OTEL_PHP_LARAVEL_LOG_ATTRIBUTES_FLATTEN flag that spreads context fields as individual OTLP attributes using dot notation for nested keys:

http.method = GET
http.path   = /users
user_id     = 123

What went wrong with #491

When #491 was merged, it conflicted with #511, which had already changed the default context handling from a JSON-encoded string to a structured array (->setAttribute('context', $context)). The #491 code regressed that improvement by reverting the non-flatten path back to json_encode().

PR #559 reverted #491 entirely to restore the #511 behaviour, but that also lost the flattening feature.

What this PR does

This PR re-introduces the flattening feature cleanly on top of #511:

  • Default behaviour (unchanged from feat: Update log builder for Laravel Instrumentation #511): context is stored as a structured array attribute, e.g. ->setAttribute('context', ['http' => ['method' => 'GET'], 'user_id' => '123']).
  • Opt-in flatten mode (OTEL_PHP_LARAVEL_LOG_ATTRIBUTES_FLATTEN=true): context fields are spread as individual top-level OTLP attributes using Illuminate\Support\Arr::dot(), enabling faceted search in observability backends.

The non-flatten default path is identical to what #511 shipped. The flatten path is additive and off by default.

Changes

  • src/Watchers/LogWatcher.php: adds OTEL_PHP_LARAVEL_LOG_ATTRIBUTES_FLATTEN constant, reads it via ConfigurationResolver in the constructor, and branches on it in recordLog(). A normalizeValue() helper ensures OTLP-compatible scalar types (casting Stringable objects to string, JSON-encoding anything else).
  • tests/Unit/Watchers/LogWatcherTest.php: 8 unit tests covering default structured-array mode, flatten mode, nested dot-notation expansion, exception extraction, Stringable normalisation, and null filtering.

Backward compatibility

Restores the OTEL_PHP_LARAVEL_LOG_ATTRIBUTES_FLATTEN feature from open-telemetry#491,
now correctly layered on top of open-telemetry#511's structured-array default.

- Default (no env var): context stored as structured array attribute,
  preserving the behaviour introduced in open-telemetry#511.
- Opt-in (OTEL_PHP_LARAVEL_LOG_ATTRIBUTES_FLATTEN=true): context fields
  spread as individual top-level OTLP attributes using dot notation for
  nested keys (e.g. http.method, http.path), enabling faceted search in
  backends such as SigNoz, Jaeger, and Grafana.

Adds unit tests covering both modes, exception extraction, Stringable
normalisation, null filtering, and nested dot-notation expansion.
@nickmarden nickmarden requested a review from a team as a code owner April 30, 2026 09:38
@welcome
Copy link
Copy Markdown

welcome Bot commented Apr 30, 2026

Thanks for opening your first pull request! If you haven't yet signed our Contributor License Agreement (CLA), then please do so that we can accept your contribution. A link should appear shortly in this PR if you have not already signed one.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.09%. Comparing base (0309f76) to head (d90fb68).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##               main     #560      +/-   ##
============================================
+ Coverage     80.45%   81.09%   +0.63%     
+ Complexity     1669     1521     -148     
============================================
  Files           116       93      -23     
  Lines          6262     5431     -831     
============================================
- Hits           5038     4404     -634     
+ Misses         1224     1027     -197     
Flag Coverage Δ
Context/Swoole 0.00% <ø> (ø)
Exporter/Instana 49.80% <ø> (ø)
Instrumentation/AwsSdk 82.14% <ø> (ø)
Instrumentation/CakePHP 20.42% <ø> (ø)
Instrumentation/CodeIgniter 79.31% <ø> (ø)
Instrumentation/Curl 86.88% <ø> (ø)
Instrumentation/Doctrine 92.82% <ø> (ø)
Instrumentation/ExtAmqp 88.80% <ø> (ø)
Instrumentation/Guzzle 76.25% <ø> (ø)
Instrumentation/HttpAsyncClient 78.94% <ø> (ø)
Instrumentation/HttpConfig 28.76% <ø> (ø)
Instrumentation/IO 0.00% <ø> (ø)
Instrumentation/Laravel ?
Instrumentation/MongoDB 76.84% <ø> (ø)
Instrumentation/MySqli 93.39% <ø> (ø)
Instrumentation/OpenAIPHP 86.71% <ø> (ø)
Instrumentation/PostgreSql 91.36% <ø> (ø)
Instrumentation/Psr14 77.41% <ø> (ø)
Instrumentation/Psr15 89.74% <ø> (ø)
Instrumentation/Psr16 97.43% <ø> (ø)
Instrumentation/Psr18 79.41% <ø> (ø)
Instrumentation/Psr6 97.56% <ø> (ø)
Instrumentation/Session 94.28% <ø> (ø)
Instrumentation/Slim 84.21% <ø> (ø)
Propagation/CloudTrace 90.69% <ø> (ø)
Propagation/Instana 98.07% <ø> (ø)
Propagation/ServerTiming 94.73% <ø> (ø)
Propagation/TraceResponse 94.73% <ø> (ø)
ResourceDetectors/Azure 91.66% <ø> (ø)
ResourceDetectors/DigitalOcean 100.00% <ø> (ø)
Sampler/Xray 78.38% <ø> (ø)
Shims/OpenTracing 92.99% <ø> (ø)
SqlCommenter 95.58% <ø> (ø)
Utils/Test 87.79% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.
see 23 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0309f76...d90fb68. Read the comment docs.

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

@ChrisLightfootWild ChrisLightfootWild self-requested a review April 30, 2026 16:40
Copy link
Copy Markdown
Contributor

@ChrisLightfootWild ChrisLightfootWild left a comment

Choose a reason for hiding this comment

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

Thanks for re-creating this with a comprehensive write-up 💪

There's a failure in the pipeline, if you could take a look:
1) tests/Unit/Watchers/LogWatcherTest.php (class_definition)

Remove the space between `class` and `()` in the anonymous class instantiation,
which the class_definition fixer rule requires.
@nickmarden
Copy link
Copy Markdown
Contributor Author

@ChrisLightfootWild I think I fixed the issue that you highlighted in your previous comment, but CI is generally red for reasons unrelated to this PR AFAICT.

Do you want me to take a stab at getting CI green (which would be a lot of scope creep), or is this PR OK as-is?

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