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.
Summary
logframes reportcontext: {}even when the app passes a non-empty context array toLog::info()/ etc., as soon as any value in that array isn't string-coercible (e.g. a nested array, an object).Repro
Captured frame:
{ "context": {}, "file": "...", "level": "info", "line": 217, "message": "transmission created" }Expected:
contextto containchannelandtest, at least in some best-effort form.Root cause
emit_loginsrc/observers/events.rsreads context via:HashMap<K, V>::from_zval(inext-php-rs) converts the whole array viaTryFrom<&ZendHashTable>, which uses?on each entry'sV::from_zval(val). The first entry that isn't string-coercible turns the whole conversion intoErr, so.ok()yieldsNoneand 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 implementingFromZvalthat maps scalars natively and falls back to the same bounded text renderingrender.rsalready uses fordumpframes (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.