logfire icon indicating copy to clipboard operation
logfire copied to clipboard

Propagate tags to child spans

Open LumaC0 opened this issue 1 year ago • 8 comments

Description

A logfire.span argument that allows child spans and records to inherit tags. All child spans (a relationship that looks to be defined by index in OPEN_SPANS) would inherit tags from surrounding spans that have propagate_tags=True. Spans that set the argument to False (the default) do not pass tags to child spans.

Proposal


logfire.config()

with logfire.span("first span", _tags=["one"], _propagate_tags=True): # has tag ["one"]
    logfire.info("first") # has tag ["one"]

    with logfire.span("second span", _tags=["two"]): # has tags ["one", "two"]
        logfire.info("second", _tags=["t1"]) # has tag ["one", "t1"]

        with logfire.span("third span", _tags=["three"], _propagate_tags=True) # has tags ["one", "three"]
            logfire.info("third") # has tags ["one", "three"]

LumaC0 avatar Oct 10 '24 17:10 LumaC0

Try logfire.with_tags

alexmojaki avatar Oct 10 '24 17:10 alexmojaki

@alexmojaki I don't think that will work across files. logfire.with_tags creates a new instance of logfire. if I create that new instance in file1.py and, within that file, create a span that encapsulates ClassInFile2().create() which exists in file2.py, I can't import the logfire instance from file1.py because of circular import issues.

Sorry if this is unclear or I am missing something

LumaC0 avatar Oct 10 '24 17:10 LumaC0

Can't you define the instance in another file that both file1 and file2 import?

alexmojaki avatar Oct 10 '24 17:10 alexmojaki

I could hack this together in each of my projects.

(I would instantiate a Logfire instance (not using with_tags) in file3 and just keep updating its internal _tags attribute)

this is fine but it's not really a long term solution.

LumaC0 avatar Oct 10 '24 18:10 LumaC0

OK, I guess you're using tags in a way that's more dynamic than what with_tags was intended for.

I would recommend creating a context variable and passing the value to _tags rather than modifying a global shared logfire instance. But I understand that this is still inconvenient. We should create an API that automates this, without requiring opening a span, and that also propagates things like attributes and levels.

alexmojaki avatar Oct 14 '24 10:10 alexmojaki

I usually define a convenience function in a logger config file and then use it as needed across the code base:

def get_tagged_logfire(tags: list[str] | None = None) -> logfire.Logfire :
    if tags is None:
        tags = []
    if CONFIG.LOGFIRE_API_KEY:
        logfire.configure(
            token=CONFIG.LOGFIRE_API_KEY,
        )
    logger.configure(handlers=[logfire.loguru_handler()])
    
    tlg = logfire.with_tags(*tags)
    tlg.instrument_pydantic_ai()
    return tlg

However, instruments don't consume these tags; only direct logfire statements will inherit these.

parashardhapola avatar Jul 28 '25 11:07 parashardhapola

Baggage allows propagating attributes like this, but not tags yet.

alexmojaki avatar Jul 28 '25 11:07 alexmojaki

Proposal: logfire.configure(baggaged_tags=['tag1', 'tag2'])

This means that if there are tag1 and tag2 keys in the baggage, then they can appear as tags in all the child spans.

This might be interesting: https://github.com/open-telemetry/opentelemetry-java/issues/11

parashardhapola avatar Jul 28 '25 12:07 parashardhapola