xstate icon indicating copy to clipboard operation
xstate copied to clipboard

Bug: Logger not propagated to child machines from root

Open xylophonehero opened this issue 2 years ago • 2 comments

XState version

XState version 5

Description

In v4, when passing a custom logger to the machine options, the child machines also used to use the same logger.

In v5, they just use the default logger console.log

Expected result

Expected the log function in a child machine to use the custom logger defined in the root machine from the interpreter options

Actual result

The child machines log using the default log function

Reproduction

https://codesandbox.io/p/sandbox/logging-not-propagated-tn93jf

Additional context

No response

xylophonehero avatar Dec 26 '23 21:12 xylophonehero

We should "inherit" it:

Alternatively, we could try to "inherit" it through the system.

Andarist avatar Dec 27 '23 00:12 Andarist

Inheriting through the system would be super nice. Right now we have extended the logger to pass the systemId as the category. We intercept this directly on the root and forward it to our third party log service

import { AnyActorRef, enqueueActions, log as xstateLog } from 'xstate5'

export const log: typeof xstateLog = (logExp) =>
  enqueueActions(({ enqueue, self }) => {
    const systemId = (self as AnyActorRef & { _systemId: string })._systemId
    return enqueue(
      xstateLog((args) => {
        // We can't pass params to the log function as they don't work with enqueue actions
        if (typeof logExp === 'function') return logExp(args, {} as any)
        return logExp
      }, systemId),
    )
  })

This function sadly doesn't accept parameters but we always use logging inline in the machine anyway so not a problem

xylophonehero avatar Dec 30 '23 20:12 xylophonehero

spawn() and spawnChild() seem like they should allow a logger option, yes? Maybe other options available on createActor()?

I'm just trying to use debug in place of the default logger. It works for the machine I created with createActor(), but not for any spawned machine.

My terrible hack for this:

import Debug from 'debug';

// ...stuff...

assign({
  actorRef: (({spawn}) => {
    const actorRef = spawn('someActor', {
      id: 'someId',
      // logger: Debug('someActor') <-- plz 😄 
    });
    // @ts-expect-error
    actorRef.logger = actorRef._actorScope.logger = Debug('someActor');
    return actorRef;
  })
})

Above, I'd rather use invoke. But invoke doesn't allow a logger option either, and I can't figure out how to get at the ActorRef to mutilate it. 😄

w/r/t xstate internals: would it make sense for _actorScope.logger to be a getter?

boneskull avatar Mar 29 '24 21:03 boneskull