Skip to content

Log context is empty when any context value isn't string-coercible #3

Description

@wadimsewo

Summary

log frames report context: {} even when the app passes a non-empty context array to Log::info() / etc., as soon as any value in that array isn't string-coercible (e.g. a nested array, an object).

Repro

Log::info('transmission created', [
    'channel' => $channel, // an array
    'test' => 1,
]);

Captured frame:

{
  "context": {},
  "file": "...",
  "level": "info",
  "line": 217,
  "message": "transmission created"
}

Expected: context to contain channel and test, at least in some best-effort form.

Root cause

emit_log in src/observers/events.rs reads context via:

obj.get_property::<HashMap<String, String>>("context")

HashMap<K, V>::from_zval (in ext-php-rs) converts the whole array via TryFrom<&ZendHashTable>, which uses ? on each entry's V::from_zval(val). The first entry that isn't string-coercible turns the whole conversion into Err, so .ok() yields None and the fallback is an empty map — not just that one key.

Since Laravel log context frequently carries mixed types (arrays, exceptions, models, etc.), this silently drops the entire context on real-world log calls.

Suggested fix

Make the per-entry conversion infallible instead of using a plain HashMap<String, String>, e.g. a small wrapper type implementing FromZval that maps scalars natively and falls back to the same bounded text rendering render.rs already uses for dump frames (arrays/objects → render(z).1, truncated). That keeps the existing owned-map extraction pattern (no new unsafe borrowing) while no longer aborting on the first non-string entry.

I have a draft fix along these lines locally if useful for reference.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions