Skip to content

fix: Fix issues related to automatic logging set up in Haystack#11635

Draft
sjrl wants to merge 2 commits into
mainfrom
fix-logger
Draft

fix: Fix issues related to automatic logging set up in Haystack#11635
sjrl wants to merge 2 commits into
mainfrom
fix-logger

Conversation

@sjrl

@sjrl sjrl commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Related Issues

Proposed Changes:

  • haystack.logging.configure_logging now attaches its formatting handler to Haystack's own logger namespaces
    (haystack, haystack_integrations and haystack_experimental) instead of the root logger. This makes
    Haystack a better-behaved library when it runs next to other services in the same process: the log records of the
    host application and other libraries are no longer reformatted or duplicated by Haystack. To restore the previous
    behavior of formatting every log record in the process, call configure_logging(logger_name="").
  • haystack.logging.configure_logging no longer freezes the log level at import time. Previously the level was
    captured once when the function ran (at import haystack), so a log level set later by the application was
    ignored for structlog-native loggers. The effective level is now read on every log call.
  • Fixed the logger in haystack.utils.requests_utils being named after the module's file path instead of
    haystack.utils.requests_utils, which kept its records outside the haystack logger namespace.
  • Importing Haystack no longer overwrites a structlog configuration that the host application already set up.
    The import-time call to configure_logging now skips configuration when structlog is already configured.
  • haystack.logging.getLogger is now idempotent. Previously, calling it more than once for the same logger name
    wrapped the already-wrapped logger methods again, which caused the log message to be run through str.format
    once per call. As a result a field value containing {...} could be re-interpolated and pull in the value of
    another field. Each logger is now patched only once.
  • The patched findCaller used to determine the source of a log entry no longer prints to stdout and no longer
    masks errors with a misleading NameError, matching structlog's own findCaller implementation.
    features:
  • haystack.logging.configure_logging gained three parameters: logger_name to choose which logger(s) the
    formatting handler is attached to, propagate to control whether Haystack's loggers propagate their records to
    ancestor loggers, and force to control whether an existing structlog configuration is replaced. Set
    propagate=False to let Haystack fully own the output of its own logs and avoid duplicate log lines when the
    host application also configures the root logger.

How did you test it?

Notes for the reviewer

Checklist

  • I have read the contributors guidelines and the code of conduct.
  • I have updated the related issue with new insights and changes.
  • I have added unit tests and updated the docstrings.
  • I've used one of the conventional commit types for my PR title: fix:, feat:, build:, chore:, ci:, docs:, style:, refactor:, perf:, test: and added ! in case the PR includes breaking changes.
  • I have documented my code.
  • I have added a release note file, following the contributors guidelines.
  • I have run pre-commit hooks and fixed any issue.

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
haystack-docs Ignored Ignored Jun 15, 2026 9:21am

Request Review

@sjrl sjrl requested a review from mpangrazzi June 15, 2026 09:21
@github-actions github-actions Bot added topic:tests type:documentation Improvements on the docs labels Jun 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack
  __init__.py
  logging.py
  haystack/core/pipeline
  async_pipeline.py
  haystack/utils
  requests_utils.py
Project Total  

This report was generated by python-coverage-comment-action

@sjrl sjrl self-assigned this Jun 15, 2026

@mpangrazzi mpangrazzi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I've left two minor comments.

Comment thread haystack/logging.py
for h in target_logger.handlers
if not (isinstance(h, logging.StreamHandler) and h.name == "HaystackLoggingHandler")
]
target_logger.handlers = [handler, *old_handlers]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may duplicate Haystack logs when users opt back into root formatting with configure_logging(logger_name="").

import haystack already installs HaystackLoggingHandler on the haystack namespaces then adds another handler to root but leaves the namespace handlers in place. Since propagation remains enabled, haystack.* records may be emitted twice.

Not 100% sure that this happens, would try to verify with e.g.:

import logging
import haystack

haystack.logging.configure_logging(use_json=True, logger_name="")
logging.getLogger("haystack.demo").warning("dup check")

And maybe extend this test to cover also the logger_name="" case.

Comment thread haystack/logging.py
@@ -352,11 +390,16 @@ def configure_logging(use_json: bool | None = None) -> None:
shared_processors.append(correlate_logs_with_traces)

structlog.configure(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This structlog.configure(...) call is (still?) process-global.

If Haystack is imported before the host app configures structlog, any non-Haystack structlog logger used while Haystack’s config is active will still run through Haystack’s processor chain (regardless of logger name).

Maybe we could move structlog.configure(...) into configure_logging(...) calls.

@sjrl sjrl requested a review from tstadel June 16, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:tests type:documentation Improvements on the docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Haystack should not configure root logger handlers

2 participants