GB0291

Graph-Break Type

Short name describing what triggered the graph break

logging.Logger method not supported for non-export cases

Context

Values or code snippet captured at the break point

method: {self.value}.{name}, args: {args}, kwargs: {kwargs}

Explanation

Explanation of why the graph break was triggered

logging.Logger methods are not supported for non-export cases.

Hints

Hints on how to resolve the graph break

Additional Information

This graph break happens when you call a logging.Logger method (e.g. logger.info(...), logger.debug(...)) inside a compiled region. Logging has side effects that Dynamo cannot safely fold into the graph, so it breaks rather than risk dropping or reordering log output.

Example code that causes the graph break is:

import logging
import torch

logger = logging.getLogger(__name__)


@torch.compile(fullgraph=True)
def fn(x):
    logger.info("processing tensor of shape %s", x.shape)
    return x + 1


fn(torch.randn(3))

If you do not need the log line to fire from inside the compiled region, the simplest fix is to move it outside the compiled region:

import logging
import torch

logger = logging.getLogger(__name__)


@torch.compile(fullgraph=True)
def fn(x):
    return x + 1


x = torch.randn(3)
logger.info("processing tensor of shape %s", x.shape)
fn(x)

If you want to keep the logging call where it is, add the method to torch._dynamo.config.ignore_logging_functions. Note that this makes the call a no-op inside the compiled region: the graph break goes away, but the log message is not emitted at all.

import logging
import torch

logger = logging.getLogger(__name__)

torch._dynamo.config.ignore_logging_functions.add(logging.Logger.info)


@torch.compile(fullgraph=True)
def fn(x):
    logger.info("processing tensor of shape %s", x.shape)  # silently skipped
    return x + 1


fn(torch.randn(3))

A note on reorderable_logging_functions

You may have seen torch._dynamo.config.reorderable_logging_functions used to handle print and similar calls (it lets Dynamo reorder the call to run after the compiled graph, so the output is preserved). It does not apply to this graph break: bound logging.Logger methods (logger.info, logger.debug, …) go through a different code path that only consults ignore_logging_functions. Adding logging.Logger.info (bound or unbound) to reorderable_logging_functions will not prevent the break.

reorderable_logging_functions only works for free functions such as print, warnings.warn, and the module-level logging helpers (logging.info, logging.warning, …). So if you need the log output preserved (rather than skipped as with ignore_logging_functions), one option is to call the module-level function and register it:

import logging
import torch

torch._dynamo.config.reorderable_logging_functions.add(logging.info)


@torch.compile(fullgraph=True)
def fn(x):
    logging.info("processing tensor %s", x)  # reordered, still emitted
    return x + 1


fn(torch.randn(3))

Two caveats. First, the arguments to a reordered logging call must be tensors, constants, or string formatters; passing something else (for example x.shape, a torch.Size object) raises a different graph break, “attempted to reorder a debugging function that can’t actually be reordered.” Second, logging.info logs via the root logger, which is not always equivalent to logging through a specific named logger; moving the call out of the compiled region (above) is the most faithful fix.

Click here to add Additional Info

Back to Registry