Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/statelyai/xstate/llms.txt

Use this file to discover all available pages before exploring further.

Logs a value using the actor’s logger.
import { log } from 'xstate';

Signature

function log<
  TContext extends MachineContext,
  TExpressionEvent extends EventObject,
  TParams extends ParameterizedObject['params'] | undefined,
  TEvent extends EventObject
>(
  value?: ResolvableLogValue<TContext, TExpressionEvent, TParams, TEvent>,
  label?: string
): LogAction<TContext, TExpressionEvent, TParams, TEvent>

Parameters

value
string | LogExpr
The value to log. Can be:
  • String: static message to log
  • Function: expression that receives ActionArgs and returns a value to log
Defaults to a function that returns { context, event }.
label
string
Optional label to prefix the logged value.

Returns

LogAction
LogAction
An action function that logs the value when executed.

Examples

Default logging

import { createMachine, log } from 'xstate';

const machine = createMachine({
  on: {
    EVENT: {
      actions: log()
    }
  }
});

// Logs: { context: {...}, event: {...} }

Log static message

const machine = createMachine({
  on: {
    START: {
      actions: log('Machine started')
    }
  }
});

// Logs: 'Machine started'

Log with label

const machine = createMachine({
  on: {
    UPDATE: {
      actions: log('Processing update', 'UPDATE_ACTION')
    }
  }
});

// Logs: 'UPDATE_ACTION', 'Processing update'

Log dynamic value

const machine = createMachine({
  types: {} as {
    context: { count: number };
  },
  context: { count: 0 },
  on: {
    INCREMENT: {
      actions: [
        assign({
          count: ({ context }) => context.count + 1
        }),
        log(({ context }) => `Count is now: ${context.count + 1}`)
      ]
    }
  }
});

Log event data

const machine = createMachine({
  on: {
    SUBMIT: {
      actions: log(
        ({ event }) => ({
          type: event.type,
          data: event.data,
          timestamp: Date.now()
        }),
        'Form Submission'
      )
    }
  }
});

// Logs: 'Form Submission', { type: 'SUBMIT', data: {...}, timestamp: 1234567890 }

Debug state transitions

const machine = createMachine({
  initial: 'idle',
  states: {
    idle: {
      entry: log('Entered idle state', 'STATE'),
      on: {
        START: 'active'
      }
    },
    active: {
      entry: log(
        ({ context, event }) => ({
          state: 'active',
          context,
          triggerEvent: event
        }),
        'STATE'
      )
    }
  }
});

Conditional logging

import { enqueueActions } from 'xstate';

const machine = createMachine({
  types: {} as {
    context: { debug: boolean; count: number };
  },
  context: { debug: true, count: 0 },
  on: {
    INCREMENT: {
      actions: enqueueActions(({ enqueue, context }) => {
        enqueue.assign({
          count: context.count + 1
        });
        
        if (context.debug) {
          enqueue(log(
            `Incremented to ${context.count + 1}`,
            'DEBUG'
          ));
        }
      })
    }
  }
});

Custom logger

import { createActor } from 'xstate';

const machine = createMachine({
  on: {
    EVENT: {
      actions: log('Custom log message')
    }
  }
});

const actor = createActor(machine, {
  logger: (msg) => {
    // Custom logging implementation
    console.log('[CUSTOM]', msg);
  }
}).start();

Notes

By default, the log action uses console.log. You can provide a custom logger when creating the actor using the logger option.
Use log actions during development to debug state transitions, context changes, and event handling. Remove or disable them in production if needed.
The log action is not imperative and should only be used in machine configurations, not in custom action implementations.

Build docs developers (and LLMs) love