Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions agent-notes/improve-atomic-initialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Goal

Keep a failed logging initialization from installing partial handlers or replacing the exception hook.

# State

Construct and format handlers before attaching them or changing process logging state. Close constructed handlers when a later setup step fails. This PR is independently based on integrated master and contains no other open PR's commits.

# Decisions and why

The framework catches setup failures and continues. Leaving an error handler installed when opening the debug file fails previously made its basicConfig fallback a no-op. A failure now preserves pre-existing root handlers, root level and exception hook. Fatal handling is enabled only after handler construction succeeds. File opens may still create or truncate files; this change does not roll back their contents.

# Surprises

create_handler is an internal module helper, not exported by the package. Its callers now receive an unattached handler; setup_logging attaches only the completed set. No consumer call site changes are required.

# Next step

Read the existing package checks. The separate app_framework failure-reporting PR makes its fallback status accurate. No merge or release.
76 changes: 46 additions & 30 deletions logger_setup/logger_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ def create_handler(
handler = handler_class()
else:
handler = handler_class(filename, mode=handler_mode, encoding="utf-8")
handler.setLevel(level)
handler.setFormatter(formatter)
logger.addHandler(handler)
try:
handler.setLevel(level)
handler.setFormatter(formatter)
except BaseException:
handler.close()
raise
return handler


Expand All @@ -52,35 +55,48 @@ def setup_logging(
remote_address=None,
remote_level=logging.ERROR,
):
formatter = logging.Formatter(message_format)
handlers = []
try:
if error_log:
error_handler = create_handler(error_log, logging.WARNING, formatter=formatter)
handlers.append(error_handler)
if debug_log:
handlers.append(create_handler(debug_log, logging.DEBUG, formatter=formatter))
if console_level:
handlers.append(create_handler(
level=console_level,
handler_class=logging.StreamHandler,
formatter=formatter,
))
if remote_address:
remote_format = (
"1 %(asctime)s - "
+ application_name
+ " - - version: %s" % application_version
+ " thread: %(thread)d function: %(module)s.%(funcName)s:\n%(message)s"
)
remote_date_format = "%Y-%m-%dT%H:%M:%SZ"
remote_formatter = logging.Formatter(remote_format, datefmt=remote_date_format)
remote_handler = create_handler(
filename=None,
level=remote_level,
handler_class=lambda: logging.handlers.SysLogHandler(address=remote_address),
formatter=remote_formatter,
)
handlers.append(remote_handler)
if error_log and log_crashes:
crashlogger.enable_crashlogger(error_handler)
except BaseException:
for handler in handlers:
handler.close()
raise

for handler in handlers:
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
if log_unhandled_exceptions:
sys.excepthook = custom_excepthook
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(message_format)
if error_log:
error_handler = create_handler(error_log, logging.WARNING, formatter=formatter)
if debug_log:
create_handler(debug_log, logging.DEBUG, formatter=formatter)
if console_level:
console_handler = create_handler(
level=console_level,
handler_class=logging.StreamHandler,
formatter=formatter,
)
if error_log and log_crashes:
crashlogger.enable_crashlogger(error_handler)
if remote_address:
remote_format = (
"1 %(asctime)s - "
+ application_name
+ " - - version: %s" % application_version
+ " thread: %(thread)d function: %(module)s.%(funcName)s:\n%(message)s"
)
remote_date_format = "%Y-%m-%dT%H:%M:%SZ"
remote_handler = logging.handlers.SysLogHandler(address=remote_address)
remote_handler.setLevel(remote_level)
remote_formatter = logging.Formatter(remote_format, datefmt=remote_date_format)
remote_handler.setFormatter(remote_formatter)
logger.addHandler(remote_handler)
logger.info("Logging initialized. PID: %d", os.getpid())
return logger

Expand Down
Loading